Merge pull request #2404 from 0xProject/feature/instant/fortmatic-integration
Formatic integration into instant
This commit is contained in:
commit
282a351859
@ -2,6 +2,8 @@ INSTANT_ROLLBAR_PUBLISH_TOKEN=
|
|||||||
INSTANT_ROLLBAR_CLIENT_TOKEN=
|
INSTANT_ROLLBAR_CLIENT_TOKEN=
|
||||||
INSTANT_HEAP_ANALYTICS_ID_PRODUCTION=
|
INSTANT_HEAP_ANALYTICS_ID_PRODUCTION=
|
||||||
INSTANT_HEAP_ANALYTICS_ID_DEVELOPMENT=
|
INSTANT_HEAP_ANALYTICS_ID_DEVELOPMENT=
|
||||||
|
INSTANT_FORTMATIC_API_KEY_PRODUCTION=
|
||||||
|
INSTANT_FORTMATIC_API_KEY_DEVELOPMENT=
|
||||||
INSTANT_INFURA_PROJECT_ID_PRODUCTION=
|
INSTANT_INFURA_PROJECT_ID_PRODUCTION=
|
||||||
INSTANT_INFURA_PROJECT_ID_DEVELOPMENT=
|
INSTANT_INFURA_PROJECT_ID_DEVELOPMENT=
|
||||||
# if you want to report to heap or rollbar when building in development mode, you can use the following:
|
# if you want to report to heap or rollbar when building in development mode, you can use the following:
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
"babel-runtime": "^6.26.0",
|
"babel-runtime": "^6.26.0",
|
||||||
"bowser": "^1.9.4",
|
"bowser": "^1.9.4",
|
||||||
"copy-to-clipboard": "^3.0.8",
|
"copy-to-clipboard": "^3.0.8",
|
||||||
|
"fortmatic": "^1.0.1",
|
||||||
"lodash": "^4.17.11",
|
"lodash": "^4.17.11",
|
||||||
"polished": "^1.9.2",
|
"polished": "^1.9.2",
|
||||||
"react": "^16.5.2",
|
"react": "^16.5.2",
|
||||||
|
@ -199,7 +199,7 @@
|
|||||||
};
|
};
|
||||||
const render = renderOptionsOverrides => {
|
const render = renderOptionsOverrides => {
|
||||||
const renderOptionsDefaults = {
|
const renderOptionsDefaults = {
|
||||||
orderSource: 'https://api.0x.org/sra/',
|
orderSource: 'https://api.0x.org/sra',
|
||||||
onClose: () => {
|
onClose: () => {
|
||||||
console.log('0x Instant Closed');
|
console.log('0x Instant Closed');
|
||||||
},
|
},
|
||||||
|
3
packages/instant/src/assets/icons/chevronRight.svg
generated
Normal file
3
packages/instant/src/assets/icons/chevronRight.svg
generated
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="7" height="13" viewBox="0 0 7 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M1 1.5L6 6.5L1 11.5" stroke="#AAAAAA" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 216 B |
3
packages/instant/src/assets/icons/phone.svg
generated
Normal file
3
packages/instant/src/assets/icons/phone.svg
generated
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M5.55139 1.67194C5.93755 2.05783 6.32503 2.44262 6.70943 2.83027C7.38729 3.51398 7.38861 4.31146 6.71338 4.9899C6.22904 5.4766 5.74755 5.96616 5.25376 6.44298C5.12328 6.56883 5.11296 6.67249 5.17908 6.83107C5.50329 7.60966 5.97204 8.29908 6.49943 8.94743C7.5595 10.2505 8.75839 11.4071 10.1881 12.3045C10.4943 12.4967 10.833 12.6366 11.152 12.8096C11.3161 12.8986 11.4285 12.8703 11.5599 12.7345C12.0429 12.2353 12.5376 11.7471 13.0312 11.2579C13.6776 10.6175 14.489 10.6162 15.1383 11.2593C15.9317 12.0451 16.7216 12.8347 17.5082 13.6271C18.1681 14.2917 18.1628 15.1039 17.4992 15.7733C17.0509 16.2258 16.5771 16.6552 16.1531 17.1291C15.5361 17.819 14.762 18.0423 13.8766 17.9936C12.5896 17.9229 11.4024 17.4959 10.2591 16.9402C7.71765 15.7052 5.54502 13.9937 3.72758 11.8305C2.38372 10.2312 1.27313 8.4906 0.542776 6.52468C0.189567 5.5739 -0.0630384 4.60006 0.0138415 3.56999C0.0612874 2.93438 0.300055 2.39365 0.768583 1.9478C1.2716 1.46878 1.75089 0.964948 2.24643 0.477807C2.8953 -0.16022 3.70693 -0.158902 4.35734 0.479565C4.75887 0.873582 5.15359 1.27419 5.55139 1.67194Z" fill="#3CB34F"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
@ -13,7 +13,7 @@ import * as _ from 'lodash';
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { oc } from 'ts-optchain';
|
import { oc } from 'ts-optchain';
|
||||||
|
|
||||||
import { WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX } from '../constants';
|
import { DEFAULT_AFFILIATE_INFO, WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX } from '../constants';
|
||||||
import { ColorOption } from '../style/theme';
|
import { ColorOption } from '../style/theme';
|
||||||
import { AffiliateInfo, Asset, ZeroExInstantError } from '../types';
|
import { AffiliateInfo, Asset, ZeroExInstantError } from '../types';
|
||||||
import { analytics } from '../util/analytics';
|
import { analytics } from '../util/analytics';
|
||||||
@ -77,7 +77,7 @@ export class BuyButton extends React.PureComponent<BuyButtonProps> {
|
|||||||
const {
|
const {
|
||||||
swapQuote,
|
swapQuote,
|
||||||
swapQuoteConsumer,
|
swapQuoteConsumer,
|
||||||
affiliateInfo,
|
affiliateInfo = DEFAULT_AFFILIATE_INFO,
|
||||||
accountAddress,
|
accountAddress,
|
||||||
accountEthBalanceInWei,
|
accountEthBalanceInWei,
|
||||||
web3Wrapper,
|
web3Wrapper,
|
||||||
@ -132,6 +132,14 @@ export class BuyButton extends React.PureComponent<BuyButtonProps> {
|
|||||||
this.props.onSignatureDenied(swapQuote);
|
this.props.onSignatureDenied(swapQuote);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Fortmatic specific error handling
|
||||||
|
if (e.message && e.message.includes('Fortmatic:')) {
|
||||||
|
if (e.message.includes('User denied transaction.')) {
|
||||||
|
analytics.trackBuySignatureDenied(swapQuote);
|
||||||
|
this.props.onSignatureDenied(swapQuote);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
const startTimeUnix = new Date().getTime();
|
const startTimeUnix = new Date().getTime();
|
||||||
|
@ -2,10 +2,11 @@ import * as React from 'react';
|
|||||||
|
|
||||||
export interface CoinbaseWalletLogoProps {
|
export interface CoinbaseWalletLogoProps {
|
||||||
width?: number;
|
width?: number;
|
||||||
|
height?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CoinbaseWalletLogo: React.StatelessComponent<CoinbaseWalletLogoProps> = ({ width }) => (
|
export const CoinbaseWalletLogo: React.StatelessComponent<CoinbaseWalletLogoProps> = ({ width, height }) => (
|
||||||
<svg width={width} viewBox="0 0 51 51" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg width={width} height={height} viewBox="0 0 51 51" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<circle cx="25.5" cy="25.5" r="25.5" fill="#3263E9" />
|
<circle cx="25.5" cy="25.5" r="25.5" fill="#3263E9" />
|
||||||
<path
|
<path
|
||||||
fillRule="evenodd"
|
fillRule="evenodd"
|
||||||
@ -20,4 +21,5 @@ CoinbaseWalletLogo.displayName = 'CoinbaseWalletLogo';
|
|||||||
|
|
||||||
CoinbaseWalletLogo.defaultProps = {
|
CoinbaseWalletLogo.defaultProps = {
|
||||||
width: 164,
|
width: 164,
|
||||||
|
height: 164,
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,7 @@ import { oc } from 'ts-optchain';
|
|||||||
|
|
||||||
import { BIG_NUMBER_ZERO, DEFAULT_UNKOWN_ASSET_NAME } from '../constants';
|
import { BIG_NUMBER_ZERO, DEFAULT_UNKOWN_ASSET_NAME } from '../constants';
|
||||||
import { ColorOption } from '../style/theme';
|
import { ColorOption } from '../style/theme';
|
||||||
import { BaseCurrency } from '../types';
|
import { Account, AccountState, BaseCurrency } from '../types';
|
||||||
import { format } from '../util/format';
|
import { format } from '../util/format';
|
||||||
|
|
||||||
import { AmountPlaceholder } from './amount_placeholder';
|
import { AmountPlaceholder } from './amount_placeholder';
|
||||||
@ -25,16 +25,22 @@ export interface OrderDetailsProps {
|
|||||||
baseCurrency: BaseCurrency;
|
baseCurrency: BaseCurrency;
|
||||||
onBaseCurrencySwitchEth: () => void;
|
onBaseCurrencySwitchEth: () => void;
|
||||||
onBaseCurrencySwitchUsd: () => void;
|
onBaseCurrencySwitchUsd: () => void;
|
||||||
|
account: Account;
|
||||||
}
|
}
|
||||||
export class OrderDetails extends React.PureComponent<OrderDetailsProps> {
|
export class OrderDetails extends React.PureComponent<OrderDetailsProps> {
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
const shouldShowUsdError = this.props.baseCurrency === BaseCurrency.USD && this._hadErrorFetchingUsdPrice();
|
const shouldShowUsdError = this.props.baseCurrency === BaseCurrency.USD && this._hadErrorFetchingUsdPrice();
|
||||||
return (
|
const { state } = this.props.account;
|
||||||
<Container width="100%" flexGrow={1} padding="20px 20px 0px 20px">
|
if (state !== AccountState.Ready) {
|
||||||
<Container marginBottom="10px">{this._renderHeader()}</Container>
|
return null;
|
||||||
{shouldShowUsdError ? this._renderErrorFetchingUsdPrice() : this._renderRows()}
|
} else {
|
||||||
</Container>
|
return (
|
||||||
);
|
<Container width="100%" flexGrow={1} padding="20px 20px 0px 20px">
|
||||||
|
<Container marginBottom="10px">{this._renderHeader()}</Container>
|
||||||
|
{shouldShowUsdError ? this._renderErrorFetchingUsdPrice() : this._renderRows()}
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _renderRows(): React.ReactNode {
|
private _renderRows(): React.ReactNode {
|
||||||
|
@ -1,19 +1,16 @@
|
|||||||
import * as _ from 'lodash';
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import PhoneIconSvg from '../assets/icons/phone.svg';
|
||||||
import { ColorOption } from '../style/theme';
|
import { ColorOption } from '../style/theme';
|
||||||
import { Account, AccountState, Network } from '../types';
|
import { Account, AccountState, Network, ProviderType } from '../types';
|
||||||
import { envUtil } from '../util/env';
|
import { envUtil } from '../util/env';
|
||||||
|
|
||||||
import { CoinbaseWalletLogo } from './coinbase_wallet_logo';
|
import { CoinbaseWalletLogo } from './coinbase_wallet_logo';
|
||||||
import { MetaMaskLogo } from './meta_mask_logo';
|
import { MetaMaskLogo } from './meta_mask_logo';
|
||||||
import { PaymentMethodDropdown } from './payment_method_dropdown';
|
import { PaymentMethodDropdown } from './payment_method_dropdown';
|
||||||
import { SectionHeader } from './section_header';
|
import { SectionHeader } from './section_header';
|
||||||
import { Circle } from './ui/circle';
|
|
||||||
import { Container } from './ui/container';
|
import { Container } from './ui/container';
|
||||||
import { Flex } from './ui/flex';
|
import { Flex } from './ui/flex';
|
||||||
import { Icon } from './ui/icon';
|
|
||||||
import { Text } from './ui/text';
|
|
||||||
import { WalletPrompt } from './wallet_prompt';
|
import { WalletPrompt } from './wallet_prompt';
|
||||||
|
|
||||||
export interface PaymentMethodProps {
|
export interface PaymentMethodProps {
|
||||||
@ -21,20 +18,20 @@ export interface PaymentMethodProps {
|
|||||||
network: Network;
|
network: Network;
|
||||||
walletDisplayName: string;
|
walletDisplayName: string;
|
||||||
onInstallWalletClick: () => void;
|
onInstallWalletClick: () => void;
|
||||||
onUnlockWalletClick: () => void;
|
onUnlockWalletClick: (providerType: ProviderType) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PaymentMethod extends React.PureComponent<PaymentMethodProps> {
|
export class PaymentMethod extends React.PureComponent<PaymentMethodProps> {
|
||||||
public render(): React.ReactNode {
|
public render(): React.ReactNode {
|
||||||
|
const marginBottom = this.props.account.state !== AccountState.Ready ? '77px' : null;
|
||||||
return (
|
return (
|
||||||
<Container width="100%" height="120px" padding="20px 20px 0px 20px">
|
<Container width="100%" height="100%" padding="20px 20px 0px 20px" marginBottom={marginBottom}>
|
||||||
<Container marginBottom="12px">
|
<Container marginBottom="12px">
|
||||||
<Flex justify="space-between">
|
<Flex justify="space-between">
|
||||||
<SectionHeader>{this._renderTitleText()}</SectionHeader>
|
<SectionHeader>{this._renderTitleText()}</SectionHeader>
|
||||||
{this._renderTitleLabel()}
|
|
||||||
</Flex>
|
</Flex>
|
||||||
</Container>
|
</Container>
|
||||||
{this._renderMainContent()}
|
<Container>{this._renderMainContent()}</Container>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -50,52 +47,88 @@ export class PaymentMethod extends React.PureComponent<PaymentMethodProps> {
|
|||||||
return 'payment method';
|
return 'payment method';
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
private readonly _renderTitleLabel = (): React.ReactNode => {
|
|
||||||
const { account } = this.props;
|
|
||||||
if (account.state === AccountState.Ready || account.state === AccountState.Locked) {
|
|
||||||
const circleColor: ColorOption = account.state === AccountState.Ready ? ColorOption.green : ColorOption.red;
|
|
||||||
return (
|
|
||||||
<Flex align="center">
|
|
||||||
<Circle diameter={8} color={circleColor} />
|
|
||||||
<Container marginLeft="5px">
|
|
||||||
<Text fontColor={ColorOption.darkGrey} fontSize="12px" lineHeight="30px">
|
|
||||||
{this.props.walletDisplayName}
|
|
||||||
</Text>
|
|
||||||
</Container>
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
private readonly _renderMainContent = (): React.ReactNode => {
|
private readonly _renderMainContent = (): React.ReactNode => {
|
||||||
const { account, network } = this.props;
|
const { account, network } = this.props;
|
||||||
const isMobile = envUtil.isMobileOperatingSystem();
|
const isMobile = envUtil.isMobileOperatingSystem();
|
||||||
const logo = isMobile ? <CoinbaseWalletLogo width={22} /> : <MetaMaskLogo width={19} height={18} />;
|
const metamaskLogo = <MetaMaskLogo width={23} height={22} />;
|
||||||
const primaryColor = isMobile ? ColorOption.darkBlue : ColorOption.darkOrange;
|
const logo = isMobile ? <CoinbaseWalletLogo width={22} height={22} /> : metamaskLogo;
|
||||||
const secondaryColor = isMobile ? ColorOption.lightBlue : ColorOption.lightOrange;
|
const primaryColor = ColorOption.grey;
|
||||||
|
const secondaryColor = ColorOption.whiteBackground;
|
||||||
const colors = { primaryColor, secondaryColor };
|
const colors = { primaryColor, secondaryColor };
|
||||||
|
const onUnlockGenericWallet = () => {
|
||||||
|
this.props.onUnlockWalletClick(ProviderType.MetaMask);
|
||||||
|
};
|
||||||
|
const onUnlockFormatic = () => this.props.onUnlockWalletClick(ProviderType.Fortmatic);
|
||||||
switch (account.state) {
|
switch (account.state) {
|
||||||
case AccountState.Loading:
|
case AccountState.Loading:
|
||||||
return null;
|
return null;
|
||||||
case AccountState.Locked:
|
case AccountState.Locked:
|
||||||
return (
|
return (
|
||||||
<WalletPrompt
|
<Flex direction="column">
|
||||||
onClick={this.props.onUnlockWalletClick}
|
<WalletPrompt
|
||||||
image={
|
onClick={onUnlockGenericWallet}
|
||||||
<Container position="relative" top="2px">
|
display="flex"
|
||||||
<Icon width={13} icon="lock" color={ColorOption.black} />
|
alignText={'flex-start'}
|
||||||
</Container>
|
marginLeft="16px"
|
||||||
}
|
fontWeight="normal"
|
||||||
{...colors}
|
padding="15px 18px"
|
||||||
>
|
image={
|
||||||
Click to Connect {this.props.walletDisplayName}
|
<Container position="relative" display="flex">
|
||||||
</WalletPrompt>
|
{logo}
|
||||||
|
</Container>
|
||||||
|
}
|
||||||
|
{...colors}
|
||||||
|
>
|
||||||
|
{isMobile ? 'Coinbase Wallet' : 'MetaMask'}
|
||||||
|
</WalletPrompt>
|
||||||
|
<WalletPrompt
|
||||||
|
onClick={onUnlockFormatic}
|
||||||
|
marginTop="14px"
|
||||||
|
marginLeft="19px"
|
||||||
|
fontWeight="normal"
|
||||||
|
padding="15px 18px"
|
||||||
|
image={
|
||||||
|
<Container position="relative" display="flex">
|
||||||
|
<PhoneIconSvg />
|
||||||
|
</Container>
|
||||||
|
}
|
||||||
|
display="flex"
|
||||||
|
{...colors}
|
||||||
|
>
|
||||||
|
Use phone number
|
||||||
|
</WalletPrompt>
|
||||||
|
</Flex>
|
||||||
);
|
);
|
||||||
case AccountState.None:
|
case AccountState.None:
|
||||||
return (
|
return (
|
||||||
<WalletPrompt onClick={this.props.onInstallWalletClick} image={logo} {...colors}>
|
<Flex direction="column" justify="space-between" height="100%">
|
||||||
{isMobile ? 'Install Coinbase Wallet' : 'Install MetaMask'}
|
<WalletPrompt
|
||||||
</WalletPrompt>
|
onClick={this.props.onInstallWalletClick}
|
||||||
|
image={logo}
|
||||||
|
{...colors}
|
||||||
|
fontWeight="normal"
|
||||||
|
marginLeft="19px"
|
||||||
|
padding="15px 18px"
|
||||||
|
>
|
||||||
|
{isMobile ? 'Install Coinbase Wallet' : 'Install MetaMask'}
|
||||||
|
</WalletPrompt>
|
||||||
|
<WalletPrompt
|
||||||
|
onClick={onUnlockFormatic}
|
||||||
|
marginTop="14px"
|
||||||
|
fontWeight="normal"
|
||||||
|
marginLeft="19px"
|
||||||
|
padding="15px 18px"
|
||||||
|
image={
|
||||||
|
<Container position="relative" display="flex">
|
||||||
|
<PhoneIconSvg />
|
||||||
|
</Container>
|
||||||
|
}
|
||||||
|
display="flex"
|
||||||
|
{...colors}
|
||||||
|
>
|
||||||
|
Use phone number
|
||||||
|
</WalletPrompt>
|
||||||
|
</Flex>
|
||||||
);
|
);
|
||||||
case AccountState.Ready:
|
case AccountState.Ready:
|
||||||
return (
|
return (
|
||||||
|
@ -75,6 +75,7 @@ export const Container = styled.div<ContainerProps>`
|
|||||||
${props => cssRuleIfExists(props, 'opacity')}
|
${props => cssRuleIfExists(props, 'opacity')}
|
||||||
${props => cssRuleIfExists(props, 'cursor')}
|
${props => cssRuleIfExists(props, 'cursor')}
|
||||||
${props => cssRuleIfExists(props, 'overflow')}
|
${props => cssRuleIfExists(props, 'overflow')}
|
||||||
|
${props => cssRuleIfExists(props, 'alignSelf')}
|
||||||
${props => (props.overflow === 'scroll' ? `-webkit-overflow-scrolling: touch` : '')};
|
${props => (props.overflow === 'scroll' ? `-webkit-overflow-scrolling: touch` : '')};
|
||||||
${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')};
|
${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')};
|
||||||
${props => props.display && stylesForMedia<string>('display', props.display)}
|
${props => props.display && stylesForMedia<string>('display', props.display)}
|
||||||
|
@ -19,6 +19,7 @@ interface IconInfoMapping {
|
|||||||
failed: IconInfo;
|
failed: IconInfo;
|
||||||
success: IconInfo;
|
success: IconInfo;
|
||||||
chevron: IconInfo;
|
chevron: IconInfo;
|
||||||
|
chevronRight: IconInfo;
|
||||||
search: IconInfo;
|
search: IconInfo;
|
||||||
lock: IconInfo;
|
lock: IconInfo;
|
||||||
}
|
}
|
||||||
@ -52,6 +53,14 @@ const ICONS: IconInfoMapping = {
|
|||||||
strokeLinecap: 'round',
|
strokeLinecap: 'round',
|
||||||
strokeLinejoin: 'round',
|
strokeLinejoin: 'round',
|
||||||
},
|
},
|
||||||
|
chevronRight: {
|
||||||
|
viewBox: '0 0 7 13',
|
||||||
|
path: 'M1 1.5L6 6.5L1 11.5',
|
||||||
|
strokeOpacity: 0.5,
|
||||||
|
strokeWidth: 1.5,
|
||||||
|
strokeLinecap: 'round',
|
||||||
|
strokeLinejoin: 'round',
|
||||||
|
},
|
||||||
search: {
|
search: {
|
||||||
viewBox: '0 0 14 14',
|
viewBox: '0 0 14 14',
|
||||||
fillRule: 'evenodd',
|
fillRule: 'evenodd',
|
||||||
@ -89,6 +98,7 @@ const PlainIcon: React.StatelessComponent<IconProps> = props => {
|
|||||||
viewBox={iconInfo.viewBox}
|
viewBox={iconInfo.viewBox}
|
||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
stroke={props.stroke}
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
d={iconInfo.path}
|
d={iconInfo.path}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
|
||||||
|
import ChevronRightSvg from '../assets/icons/chevronRight.svg';
|
||||||
import { ColorOption } from '../style/theme';
|
import { ColorOption } from '../style/theme';
|
||||||
|
|
||||||
import { Container } from './ui/container';
|
import { Container } from './ui/container';
|
||||||
@ -7,10 +8,16 @@ import { Flex } from './ui/flex';
|
|||||||
import { Text } from './ui/text';
|
import { Text } from './ui/text';
|
||||||
|
|
||||||
export interface WalletPromptProps {
|
export interface WalletPromptProps {
|
||||||
image: React.ReactNode;
|
image?: React.ReactNode;
|
||||||
onClick?: () => void;
|
onClick?: () => void;
|
||||||
primaryColor: ColorOption;
|
primaryColor: ColorOption;
|
||||||
secondaryColor: ColorOption;
|
secondaryColor: ColorOption;
|
||||||
|
marginTop?: string;
|
||||||
|
display?: string;
|
||||||
|
alignText?: string;
|
||||||
|
marginLeft?: string;
|
||||||
|
fontWeight?: string;
|
||||||
|
padding?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WalletPrompt: React.StatelessComponent<WalletPromptProps> = ({
|
export const WalletPrompt: React.StatelessComponent<WalletPromptProps> = ({
|
||||||
@ -19,24 +26,36 @@ export const WalletPrompt: React.StatelessComponent<WalletPromptProps> = ({
|
|||||||
children,
|
children,
|
||||||
secondaryColor,
|
secondaryColor,
|
||||||
primaryColor,
|
primaryColor,
|
||||||
|
marginTop,
|
||||||
|
display,
|
||||||
|
alignText,
|
||||||
|
marginLeft = '10px',
|
||||||
|
fontWeight = '500',
|
||||||
|
padding = '10px',
|
||||||
}) => (
|
}) => (
|
||||||
<Container
|
<Container
|
||||||
padding="10px"
|
padding={padding}
|
||||||
border={`1px solid ${primaryColor}`}
|
border={`1px solid`}
|
||||||
|
borderColor={ColorOption.feintGrey}
|
||||||
backgroundColor={secondaryColor}
|
backgroundColor={secondaryColor}
|
||||||
width="100%"
|
width="100%"
|
||||||
borderRadius="4px"
|
borderRadius="4px"
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
cursor={onClick ? 'pointer' : undefined}
|
cursor={onClick ? 'pointer' : undefined}
|
||||||
boxShadowOnHover={!!onClick}
|
boxShadowOnHover={!!onClick}
|
||||||
|
marginTop={marginTop}
|
||||||
|
display={display}
|
||||||
>
|
>
|
||||||
<Flex>
|
<Flex width="100%">
|
||||||
{image}
|
{image}
|
||||||
<Container marginLeft="10px">
|
<Container marginLeft={marginLeft} display={display} width="100%" alignSelf={alignText}>
|
||||||
<Text fontSize="16px" fontColor={primaryColor} fontWeight="500">
|
<Text fontSize="16px" fontColor={primaryColor} fontWeight={fontWeight}>
|
||||||
{children}
|
{children}
|
||||||
</Text>
|
</Text>
|
||||||
</Container>
|
</Container>
|
||||||
|
<Container position="relative" top="2px" display={display}>
|
||||||
|
<ChevronRightSvg />
|
||||||
|
</Container>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
|
|
||||||
import { AccountNotReady, AccountState, Network, ProviderType } from './types';
|
import { AccountNotReady, AccountState, AffiliateInfo, Network, ProviderType } from './types';
|
||||||
|
|
||||||
// TODO(dave4506) until we have /prices endpoint ready, we will use this whitelist for bridge order liquidity assets
|
// TODO(dave4506) until we have /prices endpoint ready, we will use this whitelist for bridge order liquidity assets
|
||||||
export const SUPPORTED_TOKEN_ASSET_DATA_WITH_BRIDGE_ORDERS = [
|
export const SUPPORTED_TOKEN_ASSET_DATA_WITH_BRIDGE_ORDERS = [
|
||||||
@ -91,5 +91,13 @@ export const PROVIDER_TYPE_TO_NAME: { [key in ProviderType]: string } = {
|
|||||||
[ProviderType.Parity]: 'Parity',
|
[ProviderType.Parity]: 'Parity',
|
||||||
[ProviderType.TrustWallet]: 'Trust Wallet',
|
[ProviderType.TrustWallet]: 'Trust Wallet',
|
||||||
[ProviderType.Opera]: 'Opera Wallet',
|
[ProviderType.Opera]: 'Opera Wallet',
|
||||||
|
[ProviderType.Fortmatic]: 'Fortmatic',
|
||||||
[ProviderType.Fallback]: 'Fallback',
|
[ProviderType.Fallback]: 'Fallback',
|
||||||
};
|
};
|
||||||
|
export const NULL_ADDRESS = '0x0000000000000000000000000000000000000000';
|
||||||
|
export const DEFAULT_AFFILIATE_INFO: AffiliateInfo = {
|
||||||
|
feeRecipient: NULL_ADDRESS,
|
||||||
|
feePercentage: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FORTMATIC_API_KEY = process.env.INSTANT_FORTMATIC_API_KEY;
|
||||||
|
@ -11,9 +11,18 @@ import {
|
|||||||
import { Action, actions } from '../redux/actions';
|
import { Action, actions } from '../redux/actions';
|
||||||
import { asyncData } from '../redux/async_data';
|
import { asyncData } from '../redux/async_data';
|
||||||
import { State } from '../redux/reducer';
|
import { State } from '../redux/reducer';
|
||||||
import { Network, Omit, OperatingSystem, ProviderState, StandardSlidingPanelContent, WalletSuggestion } from '../types';
|
import {
|
||||||
|
Network,
|
||||||
|
Omit,
|
||||||
|
OperatingSystem,
|
||||||
|
ProviderState,
|
||||||
|
ProviderType,
|
||||||
|
StandardSlidingPanelContent,
|
||||||
|
WalletSuggestion,
|
||||||
|
} from '../types';
|
||||||
import { analytics } from '../util/analytics';
|
import { analytics } from '../util/analytics';
|
||||||
import { envUtil } from '../util/env';
|
import { envUtil } from '../util/env';
|
||||||
|
import { providerStateFactory } from '../util/provider_state_factory';
|
||||||
|
|
||||||
export interface ConnectedAccountPaymentMethodProps {}
|
export interface ConnectedAccountPaymentMethodProps {}
|
||||||
|
|
||||||
@ -25,7 +34,7 @@ interface ConnectedState {
|
|||||||
|
|
||||||
interface ConnectedDispatch {
|
interface ConnectedDispatch {
|
||||||
openInstallWalletPanel: () => void;
|
openInstallWalletPanel: () => void;
|
||||||
unlockWalletAndDispatchToStore: (providerState: ProviderState) => void;
|
unlockWalletAndDispatchToStore: (providerState: ProviderState, providerType: ProviderType) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConnectedProps = Omit<PaymentMethodProps, keyof ConnectedAccountPaymentMethodProps>;
|
type ConnectedProps = Omit<PaymentMethodProps, keyof ConnectedAccountPaymentMethodProps>;
|
||||||
@ -43,10 +52,17 @@ const mapDispatchToProps = (
|
|||||||
ownProps: ConnectedAccountPaymentMethodProps,
|
ownProps: ConnectedAccountPaymentMethodProps,
|
||||||
): ConnectedDispatch => ({
|
): ConnectedDispatch => ({
|
||||||
openInstallWalletPanel: () => dispatch(actions.openStandardSlidingPanel(StandardSlidingPanelContent.InstallWallet)),
|
openInstallWalletPanel: () => dispatch(actions.openStandardSlidingPanel(StandardSlidingPanelContent.InstallWallet)),
|
||||||
unlockWalletAndDispatchToStore: (providerState: ProviderState) => {
|
unlockWalletAndDispatchToStore: (providerState: ProviderState, providerType: ProviderType) => {
|
||||||
|
const newProviderState: ProviderState = providerStateFactory.getProviderStateBasedOnProviderType(
|
||||||
|
providerState,
|
||||||
|
providerType,
|
||||||
|
);
|
||||||
|
// Updates provider state
|
||||||
|
dispatch(actions.setProviderState(newProviderState));
|
||||||
|
// Unlocks wallet
|
||||||
analytics.trackAccountUnlockRequested();
|
analytics.trackAccountUnlockRequested();
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
asyncData.fetchAccountInfoAndDispatchToStore(providerState, dispatch, true);
|
asyncData.fetchAccountInfoAndDispatchToStore(newProviderState, dispatch, true);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -59,7 +75,8 @@ const mergeProps = (
|
|||||||
network: connectedState.network,
|
network: connectedState.network,
|
||||||
account: connectedState.providerState.account,
|
account: connectedState.providerState.account,
|
||||||
walletDisplayName: connectedState.providerState.displayName,
|
walletDisplayName: connectedState.providerState.displayName,
|
||||||
onUnlockWalletClick: () => connectedDispatch.unlockWalletAndDispatchToStore(connectedState.providerState),
|
onUnlockWalletClick: (providerType: ProviderType) =>
|
||||||
|
connectedDispatch.unlockWalletAndDispatchToStore(connectedState.providerState, providerType),
|
||||||
onInstallWalletClick: () => {
|
onInstallWalletClick: () => {
|
||||||
const isMobile = envUtil.isMobileOperatingSystem();
|
const isMobile = envUtil.isMobileOperatingSystem();
|
||||||
const walletSuggestion: WalletSuggestion = isMobile
|
const walletSuggestion: WalletSuggestion = isMobile
|
||||||
|
@ -22,6 +22,7 @@ const mapStateToProps = (state: State, _ownProps: LatestBuyQuoteOrderDetailsProp
|
|||||||
isLoading: state.quoteRequestState === AsyncProcessState.Pending,
|
isLoading: state.quoteRequestState === AsyncProcessState.Pending,
|
||||||
assetName: assetUtils.bestNameForAsset(state.selectedAsset),
|
assetName: assetUtils.bestNameForAsset(state.selectedAsset),
|
||||||
baseCurrency: state.baseCurrency,
|
baseCurrency: state.baseCurrency,
|
||||||
|
account: state.providerState.account,
|
||||||
});
|
});
|
||||||
|
|
||||||
interface ConnectedDispatch extends Pick<OrderDetailsProps, DispatchProperties> {}
|
interface ConnectedDispatch extends Pick<OrderDetailsProps, DispatchProperties> {}
|
||||||
|
1
packages/instant/src/globals.d.ts
vendored
1
packages/instant/src/globals.d.ts
vendored
@ -10,3 +10,4 @@ declare module '*.json' {
|
|||||||
export default json;
|
export default json;
|
||||||
/* tslint:enable */
|
/* tslint:enable */
|
||||||
}
|
}
|
||||||
|
declare module 'fortmatic';
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
import { MarketBuySwapQuote } from '@0x/asset-swapper';
|
import { MarketBuySwapQuote } from '@0x/asset-swapper';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
|
|
||||||
import { ActionsUnion, AddressAndEthBalanceInWei, Asset, BaseCurrency, StandardSlidingPanelContent } from '../types';
|
import {
|
||||||
|
ActionsUnion,
|
||||||
|
AddressAndEthBalanceInWei,
|
||||||
|
Asset,
|
||||||
|
BaseCurrency,
|
||||||
|
ProviderState,
|
||||||
|
StandardSlidingPanelContent,
|
||||||
|
} from '../types';
|
||||||
|
|
||||||
export interface PlainAction<T extends string> {
|
export interface PlainAction<T extends string> {
|
||||||
type: T;
|
type: T;
|
||||||
@ -23,6 +30,7 @@ export enum ActionTypes {
|
|||||||
SetAccountStateLoading = 'SET_ACCOUNT_STATE_LOADING',
|
SetAccountStateLoading = 'SET_ACCOUNT_STATE_LOADING',
|
||||||
SetAccountStateLocked = 'SET_ACCOUNT_STATE_LOCKED',
|
SetAccountStateLocked = 'SET_ACCOUNT_STATE_LOCKED',
|
||||||
SetAccountStateReady = 'SET_ACCOUNT_STATE_READY',
|
SetAccountStateReady = 'SET_ACCOUNT_STATE_READY',
|
||||||
|
SetAccountStateNone = 'SET_ACCOUNT_STATE_NONE',
|
||||||
UpdateAccountEthBalance = 'UPDATE_ACCOUNT_ETH_BALANCE',
|
UpdateAccountEthBalance = 'UPDATE_ACCOUNT_ETH_BALANCE',
|
||||||
UpdateEthUsdPrice = 'UPDATE_ETH_USD_PRICE',
|
UpdateEthUsdPrice = 'UPDATE_ETH_USD_PRICE',
|
||||||
UpdateSelectedAssetUnitAmount = 'UPDATE_SELECTED_ASSET_UNIT_AMOUNT',
|
UpdateSelectedAssetUnitAmount = 'UPDATE_SELECTED_ASSET_UNIT_AMOUNT',
|
||||||
@ -43,11 +51,13 @@ export enum ActionTypes {
|
|||||||
OpenStandardSlidingPanel = 'OPEN_STANDARD_SLIDING_PANEL',
|
OpenStandardSlidingPanel = 'OPEN_STANDARD_SLIDING_PANEL',
|
||||||
CloseStandardSlidingPanel = 'CLOSE_STANDARD_SLIDING_PANEL',
|
CloseStandardSlidingPanel = 'CLOSE_STANDARD_SLIDING_PANEL',
|
||||||
UpdateBaseCurrency = 'UPDATE_BASE_CURRENCY',
|
UpdateBaseCurrency = 'UPDATE_BASE_CURRENCY',
|
||||||
|
SetProviderState = 'SET_PROVIDER_STATE',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const actions = {
|
export const actions = {
|
||||||
setAccountStateLoading: () => createAction(ActionTypes.SetAccountStateLoading),
|
setAccountStateLoading: () => createAction(ActionTypes.SetAccountStateLoading),
|
||||||
setAccountStateLocked: () => createAction(ActionTypes.SetAccountStateLocked),
|
setAccountStateLocked: () => createAction(ActionTypes.SetAccountStateLocked),
|
||||||
|
setAccountStateNone: () => createAction(ActionTypes.SetAccountStateNone),
|
||||||
setAccountStateReady: (address: string) => createAction(ActionTypes.SetAccountStateReady, address),
|
setAccountStateReady: (address: string) => createAction(ActionTypes.SetAccountStateReady, address),
|
||||||
updateAccountEthBalance: (addressAndBalance: AddressAndEthBalanceInWei) =>
|
updateAccountEthBalance: (addressAndBalance: AddressAndEthBalanceInWei) =>
|
||||||
createAction(ActionTypes.UpdateAccountEthBalance, addressAndBalance),
|
createAction(ActionTypes.UpdateAccountEthBalance, addressAndBalance),
|
||||||
@ -73,4 +83,5 @@ export const actions = {
|
|||||||
createAction(ActionTypes.OpenStandardSlidingPanel, content),
|
createAction(ActionTypes.OpenStandardSlidingPanel, content),
|
||||||
closeStandardSlidingPanel: () => createAction(ActionTypes.CloseStandardSlidingPanel),
|
closeStandardSlidingPanel: () => createAction(ActionTypes.CloseStandardSlidingPanel),
|
||||||
updateBaseCurrency: (baseCurrency: BaseCurrency) => createAction(ActionTypes.UpdateBaseCurrency, baseCurrency),
|
updateBaseCurrency: (baseCurrency: BaseCurrency) => createAction(ActionTypes.UpdateBaseCurrency, baseCurrency),
|
||||||
|
setProviderState: (providerState: ProviderState) => createAction(ActionTypes.SetProviderState, providerState),
|
||||||
};
|
};
|
||||||
|
@ -9,6 +9,7 @@ import { assetUtils } from '../util/asset';
|
|||||||
import { coinbaseApi } from '../util/coinbase_api';
|
import { coinbaseApi } from '../util/coinbase_api';
|
||||||
import { errorFlasher } from '../util/error_flasher';
|
import { errorFlasher } from '../util/error_flasher';
|
||||||
import { errorReporter } from '../util/error_reporter';
|
import { errorReporter } from '../util/error_reporter';
|
||||||
|
import { providerStateFactory } from '../util/provider_state_factory';
|
||||||
import { swapQuoteUpdater } from '../util/swap_quote_updater';
|
import { swapQuoteUpdater } from '../util/swap_quote_updater';
|
||||||
|
|
||||||
import { actions } from './actions';
|
import { actions } from './actions';
|
||||||
@ -59,24 +60,39 @@ export const asyncData = {
|
|||||||
providerState: ProviderState,
|
providerState: ProviderState,
|
||||||
dispatch: Dispatch,
|
dispatch: Dispatch,
|
||||||
shouldAttemptUnlock: boolean = false,
|
shouldAttemptUnlock: boolean = false,
|
||||||
shouldSetToLoading: boolean = false,
|
|
||||||
) => {
|
) => {
|
||||||
const web3Wrapper = providerState.web3Wrapper;
|
const web3Wrapper = providerState.web3Wrapper;
|
||||||
const provider = providerState.provider;
|
const provider = providerState.provider;
|
||||||
if (shouldSetToLoading && providerState.account.state !== AccountState.Loading) {
|
let availableAddresses: string[] = [];
|
||||||
|
if (shouldAttemptUnlock && providerState.account.state !== AccountState.Loading) {
|
||||||
dispatch(actions.setAccountStateLoading());
|
dispatch(actions.setAccountStateLoading());
|
||||||
}
|
}
|
||||||
let availableAddresses: string[];
|
|
||||||
try {
|
try {
|
||||||
// TODO(bmillman): Add support at the web3Wrapper level for calling `eth_requestAccounts` instead of calling enable here
|
// HACK: Fortmatic's getAvailableAddressesAsync behaves in ways that default wallet behavior can't handle
|
||||||
const isPrivacyModeEnabled = (provider as any).enable !== undefined;
|
if ((provider as any).isFortmatic) {
|
||||||
availableAddresses =
|
availableAddresses =
|
||||||
isPrivacyModeEnabled && shouldAttemptUnlock
|
(provider as any).isLoggedIn || shouldAttemptUnlock
|
||||||
? await (provider as any).enable()
|
? await web3Wrapper.getAvailableAddressesAsync()
|
||||||
: await web3Wrapper.getAvailableAddressesAsync();
|
: [];
|
||||||
|
} else {
|
||||||
|
// TODO(bmillman): Add support at the web3Wrapper level for calling `eth_requestAccounts` instead of calling enable here
|
||||||
|
const isPrivacyModeEnabled = (provider as any).enable !== undefined;
|
||||||
|
availableAddresses =
|
||||||
|
isPrivacyModeEnabled && shouldAttemptUnlock
|
||||||
|
? await (provider as any).enable()
|
||||||
|
: await web3Wrapper.getAvailableAddressesAsync();
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
analytics.trackAccountUnlockDenied();
|
analytics.trackAccountUnlockDenied();
|
||||||
dispatch(actions.setAccountStateLocked());
|
if (e.message.includes('Fortmatic: User denied account access.')) {
|
||||||
|
// If Fortmatic is not used, revert to injected provider
|
||||||
|
const initialProviderState = providerStateFactory.getInitialProviderStateWithCurrentProviderState(
|
||||||
|
providerState,
|
||||||
|
);
|
||||||
|
dispatch(actions.setProviderState(initialProviderState));
|
||||||
|
} else {
|
||||||
|
dispatch(actions.setAccountStateLocked());
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!_.isEmpty(availableAddresses)) {
|
if (!_.isEmpty(availableAddresses)) {
|
||||||
@ -84,7 +100,7 @@ export const asyncData = {
|
|||||||
dispatch(actions.setAccountStateReady(activeAddress));
|
dispatch(actions.setAccountStateReady(activeAddress));
|
||||||
// tslint:disable-next-line:no-floating-promises
|
// tslint:disable-next-line:no-floating-promises
|
||||||
asyncData.fetchAccountBalanceAndDispatchToStore(activeAddress, providerState.web3Wrapper, dispatch);
|
asyncData.fetchAccountBalanceAndDispatchToStore(activeAddress, providerState.web3Wrapper, dispatch);
|
||||||
} else {
|
} else if (providerState.account.state !== AccountState.Loading) {
|
||||||
dispatch(actions.setAccountStateLocked());
|
dispatch(actions.setAccountStateLocked());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -4,7 +4,7 @@ import { BigNumber } from '@0x/utils';
|
|||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { LOADING_ACCOUNT, LOCKED_ACCOUNT } from '../constants';
|
import { LOADING_ACCOUNT, LOCKED_ACCOUNT, NO_ACCOUNT } from '../constants';
|
||||||
import { assetMetaDataMap } from '../data/asset_meta_data_map';
|
import { assetMetaDataMap } from '../data/asset_meta_data_map';
|
||||||
import {
|
import {
|
||||||
Account,
|
Account,
|
||||||
@ -77,6 +77,8 @@ export const createReducer = (initialState: State) => {
|
|||||||
return reduceStateWithAccount(state, LOADING_ACCOUNT);
|
return reduceStateWithAccount(state, LOADING_ACCOUNT);
|
||||||
case ActionTypes.SetAccountStateLocked:
|
case ActionTypes.SetAccountStateLocked:
|
||||||
return reduceStateWithAccount(state, LOCKED_ACCOUNT);
|
return reduceStateWithAccount(state, LOCKED_ACCOUNT);
|
||||||
|
case ActionTypes.SetAccountStateNone:
|
||||||
|
return reduceStateWithAccount(state, NO_ACCOUNT);
|
||||||
case ActionTypes.SetAccountStateReady: {
|
case ActionTypes.SetAccountStateReady: {
|
||||||
const address = action.data;
|
const address = action.data;
|
||||||
let newAccount: AccountReady = {
|
let newAccount: AccountReady = {
|
||||||
@ -252,6 +254,11 @@ export const createReducer = (initialState: State) => {
|
|||||||
...state,
|
...state,
|
||||||
baseCurrency: action.data,
|
baseCurrency: action.data,
|
||||||
};
|
};
|
||||||
|
case ActionTypes.SetProviderState:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
providerState: action.data,
|
||||||
|
};
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
@ -291,7 +298,6 @@ const doesSwapQuoteMatchState = (swapQuote: MarketBuySwapQuote, state: State): b
|
|||||||
selectedAssetMetaData.decimals,
|
selectedAssetMetaData.decimals,
|
||||||
);
|
);
|
||||||
const doesAssetAmountMatch = selectedAssetAmountBaseUnits.eq(swapQuote.makerAssetFillAmount);
|
const doesAssetAmountMatch = selectedAssetAmountBaseUnits.eq(swapQuote.makerAssetFillAmount);
|
||||||
|
|
||||||
return doesAssetAmountMatch;
|
return doesAssetAmountMatch;
|
||||||
} else {
|
} else {
|
||||||
return true;
|
return true;
|
||||||
|
@ -27,6 +27,7 @@ export enum ColorOption {
|
|||||||
red = 'red',
|
red = 'red',
|
||||||
darkBlue = 'darkBlue',
|
darkBlue = 'darkBlue',
|
||||||
lightBlue = 'lightBlue',
|
lightBlue = 'lightBlue',
|
||||||
|
whiteBackground = 'whiteBackground',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const theme: Theme = {
|
export const theme: Theme = {
|
||||||
@ -44,6 +45,7 @@ export const theme: Theme = {
|
|||||||
red: '#D00000',
|
red: '#D00000',
|
||||||
darkBlue: '#135df6',
|
darkBlue: '#135df6',
|
||||||
lightBlue: '#F2F7FF',
|
lightBlue: '#F2F7FF',
|
||||||
|
whiteBackground: '#FFFFFF',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const transparentWhite = 'rgba(255,255,255,0.3)';
|
export const transparentWhite = 'rgba(255,255,255,0.3)';
|
||||||
|
@ -114,10 +114,12 @@ export interface ProviderState {
|
|||||||
swapQuoteConsumer: SwapQuoteConsumer;
|
swapQuoteConsumer: SwapQuoteConsumer;
|
||||||
web3Wrapper: Web3Wrapper;
|
web3Wrapper: Web3Wrapper;
|
||||||
account: Account;
|
account: Account;
|
||||||
|
orderSource: OrderSource;
|
||||||
|
isProviderInjected: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AccountState {
|
export enum AccountState {
|
||||||
None = 'NONE,',
|
None = 'NONE',
|
||||||
Loading = 'LOADING',
|
Loading = 'LOADING',
|
||||||
Ready = 'READY',
|
Ready = 'READY',
|
||||||
Locked = 'LOCKED',
|
Locked = 'LOCKED',
|
||||||
@ -185,6 +187,7 @@ export enum ProviderType {
|
|||||||
Cipher = 'CIPHER',
|
Cipher = 'CIPHER',
|
||||||
TrustWallet = 'TRUST_WALLET',
|
TrustWallet = 'TRUST_WALLET',
|
||||||
Opera = 'OPERA',
|
Opera = 'OPERA',
|
||||||
|
Fortmatic = 'Fortmatic',
|
||||||
Fallback = 'FALLBACK',
|
Fallback = 'FALLBACK',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +51,8 @@ export const envUtil = {
|
|||||||
return ProviderType.Parity;
|
return ProviderType.Parity;
|
||||||
} else if (anyProvider.isMetaMask) {
|
} else if (anyProvider.isMetaMask) {
|
||||||
return ProviderType.MetaMask;
|
return ProviderType.MetaMask;
|
||||||
|
} else if (anyProvider.isFortmatic) {
|
||||||
|
return ProviderType.Fortmatic;
|
||||||
} else if (_.get(window, 'SOFA') !== undefined) {
|
} else if (_.get(window, 'SOFA') !== undefined) {
|
||||||
return ProviderType.CoinbaseWallet;
|
return ProviderType.CoinbaseWallet;
|
||||||
} else if (_.get(window, '__CIPHER__') !== undefined) {
|
} else if (_.get(window, '__CIPHER__') !== undefined) {
|
||||||
@ -58,7 +60,7 @@ export const envUtil = {
|
|||||||
} else if (envUtil.getBrowser() === Browser.Opera && !anyProvider.isMetaMask) {
|
} else if (envUtil.getBrowser() === Browser.Opera && !anyProvider.isMetaMask) {
|
||||||
return ProviderType.Opera;
|
return ProviderType.Opera;
|
||||||
}
|
}
|
||||||
return;
|
return undefined;
|
||||||
},
|
},
|
||||||
getProviderName(provider: ZeroExProvider): string {
|
getProviderName(provider: ZeroExProvider): string {
|
||||||
const providerTypeIfExists = envUtil.getProviderType(provider);
|
const providerTypeIfExists = envUtil.getProviderType(provider);
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { providerUtils } from '@0x/utils';
|
import { providerUtils } from '@0x/utils';
|
||||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||||
import { SupportedProvider, ZeroExProvider } from 'ethereum-types';
|
import { SupportedProvider, ZeroExProvider } from 'ethereum-types';
|
||||||
import * as _ from 'lodash';
|
import * as Fortmatic from 'fortmatic';
|
||||||
|
|
||||||
import { LOADING_ACCOUNT, NO_ACCOUNT } from '../constants';
|
import { FORTMATIC_API_KEY, LOCKED_ACCOUNT, NO_ACCOUNT } from '../constants';
|
||||||
import { Maybe, Network, OrderSource, ProviderState } from '../types';
|
import { Maybe, Network, OrderSource, ProviderState, ProviderType } from '../types';
|
||||||
import { envUtil } from '../util/env';
|
import { envUtil } from '../util/env';
|
||||||
|
|
||||||
import { assetSwapperFactory } from './asset_swapper_factory';
|
import { assetSwapperFactory } from './asset_swapper_factory';
|
||||||
@ -50,7 +50,9 @@ export const providerStateFactory = {
|
|||||||
web3Wrapper: new Web3Wrapper(provider),
|
web3Wrapper: new Web3Wrapper(provider),
|
||||||
swapQuoter: assetSwapperFactory.getSwapQuoter(provider, orderSource, network),
|
swapQuoter: assetSwapperFactory.getSwapQuoter(provider, orderSource, network),
|
||||||
swapQuoteConsumer: assetSwapperFactory.getSwapQuoteConsumer(provider, network),
|
swapQuoteConsumer: assetSwapperFactory.getSwapQuoteConsumer(provider, network),
|
||||||
account: LOADING_ACCOUNT,
|
account: LOCKED_ACCOUNT,
|
||||||
|
orderSource,
|
||||||
|
isProviderInjected: false,
|
||||||
};
|
};
|
||||||
return providerState;
|
return providerState;
|
||||||
},
|
},
|
||||||
@ -68,7 +70,9 @@ export const providerStateFactory = {
|
|||||||
web3Wrapper: new Web3Wrapper(injectedProviderIfExists),
|
web3Wrapper: new Web3Wrapper(injectedProviderIfExists),
|
||||||
swapQuoter: assetSwapperFactory.getSwapQuoter(injectedProviderIfExists, orderSource, network),
|
swapQuoter: assetSwapperFactory.getSwapQuoter(injectedProviderIfExists, orderSource, network),
|
||||||
swapQuoteConsumer: assetSwapperFactory.getSwapQuoteConsumer(injectedProviderIfExists, network),
|
swapQuoteConsumer: assetSwapperFactory.getSwapQuoteConsumer(injectedProviderIfExists, network),
|
||||||
account: LOADING_ACCOUNT,
|
account: LOCKED_ACCOUNT,
|
||||||
|
orderSource,
|
||||||
|
isProviderInjected: true,
|
||||||
};
|
};
|
||||||
return providerState;
|
return providerState;
|
||||||
} else {
|
} else {
|
||||||
@ -89,7 +93,66 @@ export const providerStateFactory = {
|
|||||||
swapQuoter: assetSwapperFactory.getSwapQuoter(provider, orderSource, network),
|
swapQuoter: assetSwapperFactory.getSwapQuoter(provider, orderSource, network),
|
||||||
swapQuoteConsumer: assetSwapperFactory.getSwapQuoteConsumer(provider, network),
|
swapQuoteConsumer: assetSwapperFactory.getSwapQuoteConsumer(provider, network),
|
||||||
account: NO_ACCOUNT,
|
account: NO_ACCOUNT,
|
||||||
|
orderSource,
|
||||||
|
isProviderInjected: true,
|
||||||
};
|
};
|
||||||
return providerState;
|
return providerState;
|
||||||
},
|
},
|
||||||
|
// function to call getInitialProviderState with parameters retreived from a provided ProviderState
|
||||||
|
getInitialProviderStateWithCurrentProviderState: (currentProviderState: ProviderState): ProviderState => {
|
||||||
|
const orderSource = currentProviderState.orderSource;
|
||||||
|
const chainId = currentProviderState.swapQuoter.chainId;
|
||||||
|
// If provider is provided to instant, use that and the displayName
|
||||||
|
if (!currentProviderState.isProviderInjected) {
|
||||||
|
return providerStateFactory.getInitialProviderState(
|
||||||
|
orderSource,
|
||||||
|
chainId,
|
||||||
|
currentProviderState.provider,
|
||||||
|
currentProviderState.displayName,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const newProviderState = providerStateFactory.getInitialProviderState(orderSource, chainId);
|
||||||
|
newProviderState.account = LOCKED_ACCOUNT;
|
||||||
|
return newProviderState;
|
||||||
|
},
|
||||||
|
getProviderStateBasedOnProviderType: (
|
||||||
|
currentProviderState: ProviderState,
|
||||||
|
providerType: ProviderType,
|
||||||
|
): ProviderState => {
|
||||||
|
const chainId = currentProviderState.swapQuoter.chainId;
|
||||||
|
const orderSource = currentProviderState.orderSource;
|
||||||
|
// Returns current provider if the provider type selected is not found
|
||||||
|
if (providerType === ProviderType.MetaMask) {
|
||||||
|
const provider = providerFactory.getInjectedProviderIfExists();
|
||||||
|
if (provider) {
|
||||||
|
return {
|
||||||
|
displayName: envUtil.getProviderDisplayName(provider),
|
||||||
|
name: envUtil.getProviderName(provider),
|
||||||
|
provider,
|
||||||
|
web3Wrapper: new Web3Wrapper(provider),
|
||||||
|
swapQuoter: assetSwapperFactory.getSwapQuoter(provider, orderSource, chainId),
|
||||||
|
swapQuoteConsumer: assetSwapperFactory.getSwapQuoteConsumer(provider, chainId),
|
||||||
|
account: LOCKED_ACCOUNT,
|
||||||
|
orderSource,
|
||||||
|
isProviderInjected: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (providerType === ProviderType.Fortmatic) {
|
||||||
|
const fm = new Fortmatic(FORTMATIC_API_KEY);
|
||||||
|
const fmProvider = fm.getProvider();
|
||||||
|
return {
|
||||||
|
displayName: envUtil.getProviderDisplayName(fmProvider),
|
||||||
|
name: envUtil.getProviderName(fmProvider),
|
||||||
|
provider: fmProvider,
|
||||||
|
web3Wrapper: new Web3Wrapper(fmProvider),
|
||||||
|
swapQuoter: assetSwapperFactory.getSwapQuoter(fmProvider, orderSource, chainId),
|
||||||
|
swapQuoteConsumer: assetSwapperFactory.getSwapQuoteConsumer(fmProvider, chainId),
|
||||||
|
account: LOCKED_ACCOUNT,
|
||||||
|
orderSource,
|
||||||
|
isProviderInjected: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return providerStateFactory.getInitialProviderState(orderSource, chainId);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
@ -94,11 +94,17 @@ const generateConfig = (dischargeTarget, heapConfigOptions, rollbarConfigOptions
|
|||||||
? process.env.INSTANT_INFURA_PROJECT_ID_PRODUCTION
|
? process.env.INSTANT_INFURA_PROJECT_ID_PRODUCTION
|
||||||
: process.env.INSTANT_INFURA_PROJECT_ID_DEVELOPMENT;
|
: process.env.INSTANT_INFURA_PROJECT_ID_DEVELOPMENT;
|
||||||
|
|
||||||
|
const fortmaticApiKey =
|
||||||
|
dischargeTarget === 'production'
|
||||||
|
? process.env.INSTANT_FORTMATIC_API_KEY_PRODUCTION
|
||||||
|
: process.env.INSTANT_FORTMATIC_API_KEY_DEVELOPMENT;
|
||||||
|
|
||||||
const envVars = {
|
const envVars = {
|
||||||
GIT_SHA: JSON.stringify(GIT_SHA),
|
GIT_SHA: JSON.stringify(GIT_SHA),
|
||||||
NPM_PACKAGE_VERSION: JSON.stringify(process.env.npm_package_version),
|
NPM_PACKAGE_VERSION: JSON.stringify(process.env.npm_package_version),
|
||||||
ROLLBAR_ENABLED: rollbarEnabled,
|
ROLLBAR_ENABLED: rollbarEnabled,
|
||||||
HEAP_ENABLED: heapEnabled,
|
HEAP_ENABLED: heapEnabled,
|
||||||
|
INSTANT_FORTMATIC_API_KEY: JSON.stringify(fortmaticApiKey),
|
||||||
INSTANT_INFURA_PROJECT_ID: JSON.stringify(infuraProjectId),
|
INSTANT_INFURA_PROJECT_ID: JSON.stringify(infuraProjectId),
|
||||||
};
|
};
|
||||||
if (dischargeTarget) {
|
if (dischargeTarget) {
|
||||||
|
17
yarn.lock
17
yarn.lock
@ -984,6 +984,12 @@
|
|||||||
core-js "^2.6.5"
|
core-js "^2.6.5"
|
||||||
regenerator-runtime "^0.13.2"
|
regenerator-runtime "^0.13.2"
|
||||||
|
|
||||||
|
"@babel/runtime@7.3.4":
|
||||||
|
version "7.3.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.3.4.tgz#73d12ba819e365fcf7fd152aed56d6df97d21c83"
|
||||||
|
dependencies:
|
||||||
|
regenerator-runtime "^0.12.0"
|
||||||
|
|
||||||
"@babel/runtime@^7.1.5", "@babel/runtime@^7.3.1":
|
"@babel/runtime@^7.1.5", "@babel/runtime@^7.3.1":
|
||||||
version "7.5.5"
|
version "7.5.5"
|
||||||
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132"
|
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.5.tgz#74fba56d35efbeca444091c7850ccd494fd2f132"
|
||||||
@ -7759,6 +7765,13 @@ format-util@^1.0.3:
|
|||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.npmjs.org/format-util/-/format-util-1.0.3.tgz#032dca4a116262a12c43f4c3ec8566416c5b2d95"
|
resolved "https://registry.npmjs.org/format-util/-/format-util-1.0.3.tgz#032dca4a116262a12c43f4c3ec8566416c5b2d95"
|
||||||
|
|
||||||
|
fortmatic@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/fortmatic/-/fortmatic-1.0.1.tgz#ecb2c6777cd25658befe5e86c5eeddcb6c4db472"
|
||||||
|
integrity sha512-D48g0talOofK6AdwppO2VL/rRjLZb69Qf6fBR1lYUZ2rqMCM8WbBqoEDgFgJyjO1YV7XCJGbm+mW0/y2RxxbEg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "7.3.4"
|
||||||
|
|
||||||
forwarded@~0.1.2:
|
forwarded@~0.1.2:
|
||||||
version "0.1.2"
|
version "0.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
|
||||||
@ -14102,6 +14115,10 @@ regenerator-runtime@^0.11.0:
|
|||||||
version "0.11.1"
|
version "0.11.1"
|
||||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
|
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
|
||||||
|
|
||||||
|
regenerator-runtime@^0.12.0:
|
||||||
|
version "0.12.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de"
|
||||||
|
|
||||||
regenerator-runtime@^0.13.2:
|
regenerator-runtime@^0.13.2:
|
||||||
version "0.13.2"
|
version "0.13.2"
|
||||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447"
|
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user