aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant
diff options
context:
space:
mode:
Diffstat (limited to 'packages/instant')
-rw-r--r--packages/instant/README.md9
-rw-r--r--packages/instant/package.json20
-rw-r--r--packages/instant/src/components/animations/full_rotation.tsx5
-rw-r--r--packages/instant/src/components/animations/position_animation.tsx5
-rw-r--r--packages/instant/src/components/css_reset.tsx6
-rw-r--r--packages/instant/src/components/timed_progress_bar.tsx5
-rw-r--r--packages/instant/src/components/ui/circle.tsx19
-rw-r--r--packages/instant/src/components/ui/container.tsx5
-rw-r--r--packages/instant/src/components/ui/flex.tsx5
-rw-r--r--packages/instant/src/components/ui/input.tsx10
-rw-r--r--packages/instant/src/components/ui/overlay.tsx5
-rw-r--r--packages/instant/src/components/ui/text.tsx5
-rw-r--r--packages/instant/src/constants.ts2
-rw-r--r--packages/instant/src/containers/latest_error.tsx5
-rw-r--r--packages/instant/src/types.ts1
-rw-r--r--packages/instant/src/util/asset.ts26
-rw-r--r--packages/instant/src/util/buy_quote_updater.ts7
-rw-r--r--packages/instant/src/util/env.ts9
-rw-r--r--packages/instant/test/util/asset.test.ts43
19 files changed, 119 insertions, 73 deletions
diff --git a/packages/instant/README.md b/packages/instant/README.md
index 32abf76e0..8832e562d 100644
--- a/packages/instant/README.md
+++ b/packages/instant/README.md
@@ -17,9 +17,12 @@ The package is available as a UMD module named `zeroExInstant` at https://instan
<body>
<div id="zeroExInstantContainer"></div>
<script>
- zeroExInstant.render({
- // Initialization options
- }, '#zeroExInstantContainer');
+ zeroExInstant.render(
+ {
+ // Initialization options
+ },
+ '#zeroExInstantContainer',
+ );
</script>
</body>
```
diff --git a/packages/instant/package.json b/packages/instant/package.json
index 0a5e152ca..0888fc6a6 100644
--- a/packages/instant/package.json
+++ b/packages/instant/package.json
@@ -1,6 +1,6 @@
{
"name": "@0x/instant",
- "version": "1.0.4",
+ "version": "1.0.5",
"engines": {
"node": ">=6.12"
},
@@ -41,15 +41,15 @@
},
"homepage": "https://github.com/0xProject/0x-monorepo/packages/instant/README.md",
"dependencies": {
- "@0x/assert": "^1.0.20",
- "@0x/asset-buyer": "^3.0.4",
- "@0x/json-schemas": "^2.1.4",
- "@0x/order-utils": "^3.0.7",
- "@0x/subproviders": "^2.1.8",
- "@0x/types": "^1.4.1",
+ "@0x/assert": "^1.0.21",
+ "@0x/asset-buyer": "^3.0.5",
+ "@0x/json-schemas": "^2.1.5",
+ "@0x/order-utils": "^3.1.0",
+ "@0x/subproviders": "^2.1.9",
+ "@0x/types": "^1.5.0",
"@0x/typescript-typings": "^3.0.6",
- "@0x/utils": "^2.0.8",
- "@0x/web3-wrapper": "^3.2.1",
+ "@0x/utils": "^2.1.1",
+ "@0x/web3-wrapper": "^3.2.2",
"bowser": "^1.9.4",
"copy-to-clipboard": "^3.0.8",
"ethereum-types": "^1.1.4",
@@ -76,7 +76,7 @@
"@types/react-dom": "^16.0.8",
"@types/react-redux": "^6.0.9",
"@types/redux": "^3.6.0",
- "@types/styled-components": "^4.0.1",
+ "@types/styled-components": "4.0.1",
"awesome-typescript-loader": "^5.2.1",
"dotenv-cli": "^1.4.0",
"enzyme": "^3.6.0",
diff --git a/packages/instant/src/components/animations/full_rotation.tsx b/packages/instant/src/components/animations/full_rotation.tsx
index 9adb565f9..1dff1b1fc 100644
--- a/packages/instant/src/components/animations/full_rotation.tsx
+++ b/packages/instant/src/components/animations/full_rotation.tsx
@@ -14,10 +14,7 @@ to {
}
`;
-export const FullRotation =
- styled.div <
- FullRotationProps >
- `
+export const FullRotation = styled.div<FullRotationProps>`
animation: ${rotatingKeyframes} 2s linear infinite;
height: ${props => props.height};
width: ${props => props.width};
diff --git a/packages/instant/src/components/animations/position_animation.tsx b/packages/instant/src/components/animations/position_animation.tsx
index 8b3b294b7..4f8f25679 100644
--- a/packages/instant/src/components/animations/position_animation.tsx
+++ b/packages/instant/src/components/animations/position_animation.tsx
@@ -95,10 +95,7 @@ const animationForSize = (
return animationSettingsForSize && mediaFn`${generatePositionAnimationCss(animationSettingsForSize)}`;
};
-export const PositionAnimation =
- styled.div <
- PositionAnimationProps >
- `
+export const PositionAnimation = styled.div<PositionAnimationProps>`
&& {
${props => props.zIndex && stylesForMedia<number>('z-index', props.zIndex)}
${props => defaultAnimation(props.positionSettings)}
diff --git a/packages/instant/src/components/css_reset.tsx b/packages/instant/src/components/css_reset.tsx
index 0bef85389..d1b20f4c9 100644
--- a/packages/instant/src/components/css_reset.tsx
+++ b/packages/instant/src/components/css_reset.tsx
@@ -4,9 +4,9 @@ import { createGlobalStyle } from '../style/theme';
export interface CSSResetProps {}
/*
-* Derived from
-* https://github.com/jtrost/Complete-CSS-Reset
-*/
+ * Derived from
+ * https://github.com/jtrost/Complete-CSS-Reset
+ */
export const CSSReset = createGlobalStyle`
.${INJECTED_DIV_CLASS} {
a, abbr, area, article, aside, audio, b, bdo, blockquote, body, button,
diff --git a/packages/instant/src/components/timed_progress_bar.tsx b/packages/instant/src/components/timed_progress_bar.tsx
index b1644b871..287269af7 100644
--- a/packages/instant/src/components/timed_progress_bar.tsx
+++ b/packages/instant/src/components/timed_progress_bar.tsx
@@ -68,10 +68,7 @@ interface ProgressProps {
animationSettings?: WidthAnimationSettings;
}
-export const Progress =
- styled.div <
- ProgressProps >
- `
+export const Progress = styled.div<ProgressProps>`
&& {
background-color: ${props => props.theme[ColorOption.primaryColor]};
border-radius: 6px;
diff --git a/packages/instant/src/components/ui/circle.tsx b/packages/instant/src/components/ui/circle.tsx
index 4f9f56f12..e4f2c5260 100644
--- a/packages/instant/src/components/ui/circle.tsx
+++ b/packages/instant/src/components/ui/circle.tsx
@@ -8,16 +8,15 @@ export interface CircleProps {
}
export const Circle = withTheme(
- styled.div <
- CircleProps >
- `
- && {
- width: ${props => props.diameter}px;
- height: ${props => props.diameter}px;
- background-color: ${props => (props.rawColor ? props.rawColor : props.theme[props.color || ColorOption.white])};
- border-radius: 50%;
- }
-`,
+ styled.div<CircleProps>`
+ && {
+ width: ${props => props.diameter}px;
+ height: ${props => props.diameter}px;
+ background-color: ${props =>
+ props.rawColor ? props.rawColor : props.theme[props.color || ColorOption.white]};
+ border-radius: 50%;
+ }
+ `,
);
Circle.displayName = 'Circle';
diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx
index 58d7d5871..59b733f3e 100644
--- a/packages/instant/src/components/ui/container.tsx
+++ b/packages/instant/src/components/ui/container.tsx
@@ -51,10 +51,7 @@ const getBackgroundColor = (theme: any, backgroundColor?: ColorOption, rawBackgr
return 'none';
};
-export const Container =
- styled.div <
- ContainerProps >
- `
+export const Container = styled.div<ContainerProps>`
&& {
box-sizing: border-box;
${props => cssRuleIfExists(props, 'flex-grow')}
diff --git a/packages/instant/src/components/ui/flex.tsx b/packages/instant/src/components/ui/flex.tsx
index 274c46b9e..145e654f1 100644
--- a/packages/instant/src/components/ui/flex.tsx
+++ b/packages/instant/src/components/ui/flex.tsx
@@ -14,10 +14,7 @@ export interface FlexProps {
flexGrow?: number | string;
}
-export const Flex =
- styled.div <
- FlexProps >
- `
+export const Flex = styled.div<FlexProps>`
&& {
display: ${props => (props.inline ? 'inline-flex' : 'flex')};
flex-direction: ${props => props.direction};
diff --git a/packages/instant/src/components/ui/input.tsx b/packages/instant/src/components/ui/input.tsx
index 53c43ea0b..024e81b15 100644
--- a/packages/instant/src/components/ui/input.tsx
+++ b/packages/instant/src/components/ui/input.tsx
@@ -14,10 +14,7 @@ export interface InputProps extends React.HTMLAttributes<HTMLInputElement> {
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
}
-export const Input =
- styled.input <
- InputProps >
- `
+export const Input = styled.input<InputProps>`
&& {
all: initial;
font-size: ${props => props.fontSize};
@@ -32,10 +29,11 @@ export const Input =
color: ${props => props.theme[props.fontColor || 'white']} !important;
opacity: 0.5 !important;
}
- &::-webkit-outer-spin-button, &::-webkit-inner-spin-button {
+ &::-webkit-outer-spin-button,
+ &::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
- }
+ }
}
`;
diff --git a/packages/instant/src/components/ui/overlay.tsx b/packages/instant/src/components/ui/overlay.tsx
index 0b5eaf299..0b1be6a65 100644
--- a/packages/instant/src/components/ui/overlay.tsx
+++ b/packages/instant/src/components/ui/overlay.tsx
@@ -12,10 +12,7 @@ export interface OverlayProps {
showMaxWidth?: ScreenWidths;
}
-export const Overlay =
- styled.div <
- OverlayProps >
- `
+export const Overlay = styled.div<OverlayProps>`
&& {
position: fixed;
top: 0;
diff --git a/packages/instant/src/components/ui/text.tsx b/packages/instant/src/components/ui/text.tsx
index 282477758..ca120f3bd 100644
--- a/packages/instant/src/components/ui/text.tsx
+++ b/packages/instant/src/components/ui/text.tsx
@@ -31,10 +31,7 @@ export const Text: React.StatelessComponent<TextProps> = ({ href, onClick, ...re
};
const opacityOnHoverAmount = 0.5;
-export const StyledText =
- styled.div <
- TextProps >
- `
+export const StyledText = styled.div<TextProps>`
&& {
font-family: 'Inter UI', sans-serif;
font-style: ${props => props.fontStyle};
diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts
index 22f0cb6a4..bfd9e9098 100644
--- a/packages/instant/src/constants.ts
+++ b/packages/instant/src/constants.ts
@@ -16,6 +16,7 @@ export const ONE_SECOND_MS = 1000;
export const ONE_MINUTE_MS = ONE_SECOND_MS * 60;
export const GIT_SHA = process.env.GIT_SHA;
export const NODE_ENV = process.env.NODE_ENV;
+export const SLIPPAGE_PERCENTAGE = 0.2;
export const NPM_PACKAGE_VERSION = process.env.NPM_PACKAGE_VERSION;
export const DEFAULT_UNKOWN_ASSET_NAME = '???';
export const ACCOUNT_UPDATE_INTERVAL_TIME_MS = ONE_SECOND_MS * 5;
@@ -73,5 +74,6 @@ export const PROVIDER_TYPE_TO_NAME: { [key in ProviderType]: string } = {
[ProviderType.CoinbaseWallet]: 'Coinbase Wallet',
[ProviderType.Parity]: 'Parity',
[ProviderType.TrustWallet]: 'Trust Wallet',
+ [ProviderType.Opera]: 'Opera Wallet',
[ProviderType.Fallback]: 'Fallback',
};
diff --git a/packages/instant/src/containers/latest_error.tsx b/packages/instant/src/containers/latest_error.tsx
index 6da4558ef..57a2dbdc2 100644
--- a/packages/instant/src/containers/latest_error.tsx
+++ b/packages/instant/src/containers/latest_error.tsx
@@ -62,4 +62,7 @@ const mapDispatchToProps = (dispatch: Dispatch<Action>, _ownProps: LatestErrorPr
},
});
-export const LatestError = connect(mapStateToProps, mapDispatchToProps)(LatestErrorComponent);
+export const LatestError = connect(
+ mapStateToProps,
+ mapDispatchToProps,
+)(LatestErrorComponent);
diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts
index ae672c919..f07a407da 100644
--- a/packages/instant/src/types.ts
+++ b/packages/instant/src/types.ts
@@ -183,6 +183,7 @@ export enum ProviderType {
CoinbaseWallet = 'COINBASE_WALLET',
Cipher = 'CIPHER',
TrustWallet = 'TRUST_WALLET',
+ Opera = 'OPERA',
Fallback = 'FALLBACK',
}
diff --git a/packages/instant/src/util/asset.ts b/packages/instant/src/util/asset.ts
index faaeb7c22..709561dbc 100644
--- a/packages/instant/src/util/asset.ts
+++ b/packages/instant/src/util/asset.ts
@@ -1,8 +1,10 @@
-import { AssetBuyerError } from '@0x/asset-buyer';
+import { AssetBuyerError, InsufficientAssetLiquidityError } from '@0x/asset-buyer';
import { AssetProxyId, ObjectMap } from '@0x/types';
+import { BigNumber } from '@0x/utils';
+import { Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
-import { DEFAULT_UNKOWN_ASSET_NAME } from '../constants';
+import { BIG_NUMBER_ZERO, DEFAULT_UNKOWN_ASSET_NAME } from '../constants';
import { assetDataNetworkMapping } from '../data/asset_data_network_mapping';
import { Asset, AssetMetaData, ERC20Asset, Network, ZeroExInstantError } from '../types';
@@ -102,15 +104,29 @@ export const assetUtils = {
return assetDataGroupIfExists[Network.Mainnet];
},
getERC20AssetsFromAssets: (assets: Asset[]): ERC20Asset[] => {
- const erc20sOrUndefined = _.map(
- assets,
- asset => (asset.metaData.assetProxyId === AssetProxyId.ERC20 ? (asset as ERC20Asset) : undefined),
+ const erc20sOrUndefined = _.map(assets, asset =>
+ asset.metaData.assetProxyId === AssetProxyId.ERC20 ? (asset as ERC20Asset) : undefined,
);
return _.compact(erc20sOrUndefined);
},
assetBuyerErrorMessage: (asset: ERC20Asset, error: Error): string | undefined => {
if (error.message === AssetBuyerError.InsufficientAssetLiquidity) {
const assetName = assetUtils.bestNameForAsset(asset, 'of this asset');
+ if (
+ error instanceof InsufficientAssetLiquidityError &&
+ error.amountAvailableToFill.greaterThan(BIG_NUMBER_ZERO)
+ ) {
+ const unitAmountAvailableToFill = Web3Wrapper.toUnitAmount(
+ error.amountAvailableToFill,
+ asset.metaData.decimals,
+ );
+ const roundedUnitAmountAvailableToFill = unitAmountAvailableToFill.round(2, BigNumber.ROUND_DOWN);
+
+ if (roundedUnitAmountAvailableToFill.greaterThan(BIG_NUMBER_ZERO)) {
+ return `There are only ${roundedUnitAmountAvailableToFill} ${assetName} available to buy`;
+ }
+ }
+
return `Not enough ${assetName} available`;
} else if (error.message === AssetBuyerError.InsufficientZrxLiquidity) {
return 'Not enough ZRX available';
diff --git a/packages/instant/src/util/buy_quote_updater.ts b/packages/instant/src/util/buy_quote_updater.ts
index 6191c92e3..37974e71c 100644
--- a/packages/instant/src/util/buy_quote_updater.ts
+++ b/packages/instant/src/util/buy_quote_updater.ts
@@ -5,6 +5,7 @@ import * as _ from 'lodash';
import { Dispatch } from 'redux';
import { oc } from 'ts-optchain';
+import { SLIPPAGE_PERCENTAGE } from '../constants';
import { Action, actions } from '../redux/actions';
import { AffiliateInfo, ERC20Asset, QuoteFetchOrigin } from '../types';
import { analytics } from '../util/analytics';
@@ -33,8 +34,12 @@ export const buyQuoteUpdater = {
}
const feePercentage = oc(options.affiliateInfo).feePercentage();
let newBuyQuote: BuyQuote | undefined;
+ const slippagePercentage = SLIPPAGE_PERCENTAGE;
try {
- newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue, { feePercentage });
+ newBuyQuote = await assetBuyer.getBuyQuoteAsync(asset.assetData, baseUnitValue, {
+ feePercentage,
+ slippagePercentage,
+ });
} catch (error) {
const errorMessage = assetUtils.assetBuyerErrorMessage(asset, error);
diff --git a/packages/instant/src/util/env.ts b/packages/instant/src/util/env.ts
index aedf4f5d6..7d4f836ff 100644
--- a/packages/instant/src/util/env.ts
+++ b/packages/instant/src/util/env.ts
@@ -42,18 +42,21 @@ export const envUtil = {
}
},
getProviderType(provider: Provider): ProviderType | undefined {
+ const anyProvider = provider as any;
if (provider.constructor.name === 'EthereumProvider') {
return ProviderType.Mist;
- } else if ((provider as any).isTrust) {
+ } else if (anyProvider.isTrust) {
return ProviderType.TrustWallet;
- } else if ((provider as any).isParity) {
+ } else if (anyProvider.isParity) {
return ProviderType.Parity;
- } else if ((provider as any).isMetaMask) {
+ } else if (anyProvider.isMetaMask) {
return ProviderType.MetaMask;
} else if (!_.isUndefined(_.get(window, 'SOFA'))) {
return ProviderType.CoinbaseWallet;
} else if (!_.isUndefined(_.get(window, '__CIPHER__'))) {
return ProviderType.Cipher;
+ } else if (envUtil.getBrowser() === Browser.Opera && !anyProvider.isMetaMask) {
+ return ProviderType.Opera;
}
return;
},
diff --git a/packages/instant/test/util/asset.test.ts b/packages/instant/test/util/asset.test.ts
index fc4e4e2e4..402a556d5 100644
--- a/packages/instant/test/util/asset.test.ts
+++ b/packages/instant/test/util/asset.test.ts
@@ -1,5 +1,6 @@
-import { AssetBuyerError } from '@0x/asset-buyer';
+import { AssetBuyerError, BigNumber, InsufficientAssetLiquidityError } from '@0x/asset-buyer';
import { AssetProxyId, ObjectMap } from '@0x/types';
+import { Web3Wrapper } from '@0x/web3-wrapper';
import { Asset, AssetMetaData, ERC20Asset, ERC20AssetMetaData, Network, ZeroExInstantError } from '../../src/types';
import { assetUtils } from '../../src/util/asset';
@@ -19,6 +20,16 @@ const ZRX_ASSET: ERC20Asset = {
const META_DATA_MAP: ObjectMap<AssetMetaData> = {
[ZRX_ASSET_DATA]: ZRX_META_DATA,
};
+const WAX_ASSET: ERC20Asset = {
+ assetData: '0xf47261b000000000000000000000000039bb259f66e1c59d5abef88375979b4d20d98022',
+ metaData: {
+ assetProxyId: AssetProxyId.ERC20,
+ decimals: 8,
+ primaryColor: '#EDB740',
+ symbol: 'wax',
+ name: 'WAX',
+ },
+};
describe('assetDataUtil', () => {
describe('bestNameForAsset', () => {
@@ -47,13 +58,39 @@ describe('assetDataUtil', () => {
});
});
describe('assetBuyerErrorMessage', () => {
- it('should return message for InsufficientAssetLiquidity', () => {
+ it('should return message for generic InsufficientAssetLiquidity error', () => {
const insufficientAssetError = new Error(AssetBuyerError.InsufficientAssetLiquidity);
expect(assetUtils.assetBuyerErrorMessage(ZRX_ASSET, insufficientAssetError)).toEqual(
'Not enough ZRX available',
);
});
- it('should return message for InsufficientAssetLiquidity', () => {
+ describe('InsufficientAssetLiquidityError', () => {
+ it('should return custom message for token w/ 18 decimals', () => {
+ const amountAvailable = Web3Wrapper.toBaseUnitAmount(new BigNumber(20.059), 18);
+ expect(
+ assetUtils.assetBuyerErrorMessage(ZRX_ASSET, new InsufficientAssetLiquidityError(amountAvailable)),
+ ).toEqual('There are only 20.05 ZRX available to buy');
+ });
+ it('should return custom message for token w/ 18 decimals and small amount available', () => {
+ const amountAvailable = Web3Wrapper.toBaseUnitAmount(new BigNumber(0.01), 18);
+ expect(
+ assetUtils.assetBuyerErrorMessage(ZRX_ASSET, new InsufficientAssetLiquidityError(amountAvailable)),
+ ).toEqual('There are only 0.01 ZRX available to buy');
+ });
+ it('should return custom message for token w/ 8 decimals', () => {
+ const amountAvailable = Web3Wrapper.toBaseUnitAmount(new BigNumber(3), 8);
+ expect(
+ assetUtils.assetBuyerErrorMessage(WAX_ASSET, new InsufficientAssetLiquidityError(amountAvailable)),
+ ).toEqual('There are only 3 WAX available to buy');
+ });
+ it('should return generic message when amount available rounds to zero', () => {
+ const amountAvailable = Web3Wrapper.toBaseUnitAmount(new BigNumber(0.002), 18);
+ expect(
+ assetUtils.assetBuyerErrorMessage(ZRX_ASSET, new InsufficientAssetLiquidityError(amountAvailable)),
+ ).toEqual('Not enough ZRX available');
+ });
+ });
+ it('should return message for InsufficientZrxLiquidity', () => {
const insufficientZrxError = new Error(AssetBuyerError.InsufficientZrxLiquidity);
expect(assetUtils.assetBuyerErrorMessage(ZRX_ASSET, insufficientZrxError)).toEqual(
'Not enough ZRX available',