aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant
diff options
context:
space:
mode:
authorSteve Klebanoff <steve@0xproject.com>2018-10-30 01:12:44 +0800
committerGitHub <noreply@github.com>2018-10-30 01:12:44 +0800
commit4e4291eccdd6c837bbec70603aa6eb64d3aa8d85 (patch)
treeedf8006576143d5cd1c32b052164ac898c57c8b2 /packages/instant
parentae6202ed3d777605a3fd02cd29141a3ba40f4b34 (diff)
parent7ed44f7b2f0224b4169f0a8f34bae09e8c6b986f (diff)
downloaddexon-0x-contracts-4e4291eccdd6c837bbec70603aa6eb64d3aa8d85.tar
dexon-0x-contracts-4e4291eccdd6c837bbec70603aa6eb64d3aa8d85.tar.gz
dexon-0x-contracts-4e4291eccdd6c837bbec70603aa6eb64d3aa8d85.tar.bz2
dexon-0x-contracts-4e4291eccdd6c837bbec70603aa6eb64d3aa8d85.tar.lz
dexon-0x-contracts-4e4291eccdd6c837bbec70603aa6eb64d3aa8d85.tar.xz
dexon-0x-contracts-4e4291eccdd6c837bbec70603aa6eb64d3aa8d85.tar.zst
dexon-0x-contracts-4e4291eccdd6c837bbec70603aa6eb64d3aa8d85.zip
Merge pull request #1193 from 0xProject/feature/not-enough-eth
[instant] Not enough ETH error message
Diffstat (limited to 'packages/instant')
-rw-r--r--packages/instant/src/components/buy_button.tsx29
-rw-r--r--packages/instant/src/components/buy_order_state_buttons.tsx12
-rw-r--r--packages/instant/src/constants.ts2
-rw-r--r--packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts18
-rw-r--r--packages/instant/src/containers/selected_erc20_asset_amount_input.ts3
-rw-r--r--packages/instant/src/types.ts5
-rw-r--r--packages/instant/src/util/address.ts6
-rw-r--r--packages/instant/src/util/balance.ts13
-rw-r--r--packages/instant/src/util/error.ts5
-rw-r--r--packages/instant/src/util/format.ts6
-rw-r--r--packages/instant/test/util/format.test.ts8
11 files changed, 77 insertions, 30 deletions
diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx
index a70269dde..bcd435250 100644
--- a/packages/instant/src/components/buy_button.tsx
+++ b/packages/instant/src/components/buy_button.tsx
@@ -4,6 +4,9 @@ import * as React from 'react';
import { WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX } from '../constants';
import { ColorOption } from '../style/theme';
+import { ZeroExInstantError } from '../types';
+import { getBestAddress } from '../util/address';
+import { balanceUtil } from '../util/balance';
import { util } from '../util/util';
import { web3Wrapper } from '../util/web3_wrapper';
@@ -12,7 +15,8 @@ import { Button, Text } from './ui';
export interface BuyButtonProps {
buyQuote?: BuyQuote;
assetBuyer?: AssetBuyer;
- onAwaitingSignature: (buyQuote: BuyQuote) => void;
+ onValidationPending: (buyQuote: BuyQuote) => void;
+ onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void;
onSignatureDenied: (buyQuote: BuyQuote, preventedError: Error) => void;
onBuyProcessing: (buyQuote: BuyQuote, txHash: string) => void;
onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void;
@@ -42,14 +46,27 @@ export class BuyButton extends React.Component<BuyButtonProps> {
return;
}
+ this.props.onValidationPending(buyQuote);
+ const takerAddress = await getBestAddress();
+
+ const hasSufficentEth = await balanceUtil.hasSufficentEth(takerAddress, buyQuote, web3Wrapper);
+ if (!hasSufficentEth) {
+ this.props.onValidationFail(buyQuote, ZeroExInstantError.InsufficientETH);
+ return;
+ }
+
let txHash: string | undefined;
- this.props.onAwaitingSignature(buyQuote);
try {
- txHash = await assetBuyer.executeBuyQuoteAsync(buyQuote);
+ txHash = await assetBuyer.executeBuyQuoteAsync(buyQuote, { takerAddress });
} catch (e) {
- if (e instanceof Error && e.message === AssetBuyerError.SignatureRequestDenied) {
- this.props.onSignatureDenied(buyQuote, e);
- return;
+ if (e instanceof Error) {
+ if (e.message === AssetBuyerError.SignatureRequestDenied) {
+ this.props.onSignatureDenied(buyQuote, e);
+ return;
+ } else if (e.message === AssetBuyerError.TransactionValueTooLow) {
+ this.props.onValidationFail(buyQuote, AssetBuyerError.TransactionValueTooLow);
+ return;
+ }
}
throw e;
}
diff --git a/packages/instant/src/components/buy_order_state_buttons.tsx b/packages/instant/src/components/buy_order_state_buttons.tsx
index b9e92e763..7c06ff31b 100644
--- a/packages/instant/src/components/buy_order_state_buttons.tsx
+++ b/packages/instant/src/components/buy_order_state_buttons.tsx
@@ -1,4 +1,4 @@
-import { AssetBuyer, BuyQuote } from '@0x/asset-buyer';
+import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
import * as React from 'react';
import { BuyButton } from '../components/buy_button';
@@ -7,7 +7,7 @@ import { Flex } from '../components/ui/flex';
import { PlacingOrderButton } from '../components/placing_order_button';
import { ColorOption } from '../style/theme';
-import { OrderProcessState } from '../types';
+import { OrderProcessState, ZeroExInstantError } from '../types';
import { Button } from './ui/button';
import { Text } from './ui/text';
@@ -17,7 +17,8 @@ export interface BuyOrderStateButtonProps {
buyOrderProcessingState: OrderProcessState;
assetBuyer?: AssetBuyer;
onViewTransaction: () => void;
- onAwaitingSignature: (buyQuote: BuyQuote) => void;
+ onValidationPending: (buyQuote: BuyQuote) => void;
+ onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void;
onSignatureDenied: (buyQuote: BuyQuote, error: Error) => void;
onBuyProcessing: (buyQuote: BuyQuote, txHash: string) => void;
onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void;
@@ -45,7 +46,7 @@ export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonP
props.buyOrderProcessingState === OrderProcessState.PROCESSING
) {
return <SecondaryButton onClick={props.onViewTransaction}>View Transaction</SecondaryButton>;
- } else if (props.buyOrderProcessingState === OrderProcessState.AWAITING_SIGNATURE) {
+ } else if (props.buyOrderProcessingState === OrderProcessState.VALIDATING) {
return <PlacingOrderButton />;
}
@@ -53,7 +54,8 @@ export const BuyOrderStateButtons: React.StatelessComponent<BuyOrderStateButtonP
<BuyButton
buyQuote={props.buyQuote}
assetBuyer={props.assetBuyer}
- onAwaitingSignature={props.onAwaitingSignature}
+ onValidationPending={props.onValidationPending}
+ onValidationFail={props.onValidationFail}
onSignatureDenied={props.onSignatureDenied}
onBuyProcessing={props.onBuyProcessing}
onBuySuccess={props.onBuySuccess}
diff --git a/packages/instant/src/constants.ts b/packages/instant/src/constants.ts
index 48d0d4aa2..e4281d54a 100644
--- a/packages/instant/src/constants.ts
+++ b/packages/instant/src/constants.ts
@@ -1,5 +1,5 @@
import { BigNumber } from '@0x/utils';
export const BIG_NUMBER_ZERO = new BigNumber(0);
-export const ethDecimals = 18;
+export const ETH_DECIMALS = 18;
export const DEFAULT_ZERO_EX_CONTAINER_SELECTOR = '#zeroExInstantContainer';
export const WEB_3_WRAPPER_TRANSACTION_FAILED_ERROR_MSG_PREFIX = 'Transaction failed';
diff --git a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts
index 8927b8954..241c0192c 100644
--- a/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts
+++ b/packages/instant/src/containers/selected_asset_buy_order_state_buttons.ts
@@ -1,4 +1,4 @@
-import { AssetBuyer, BuyQuote } from '@0x/asset-buyer';
+import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer';
import * as _ from 'lodash';
import * as React from 'react';
import { connect } from 'react-redux';
@@ -6,10 +6,11 @@ import { Dispatch } from 'redux';
import { Action, actions } from '../redux/actions';
import { State } from '../redux/reducer';
-import { OrderProcessState, OrderState } from '../types';
+import { OrderProcessState, OrderState, ZeroExInstantError } from '../types';
import { etherscanUtil } from '../util/etherscan';
import { BuyOrderStateButtons } from '../components/buy_order_state_buttons';
+import { errorUtil } from '../util/error';
interface ConnectedState {
buyQuote?: BuyQuote;
@@ -19,12 +20,13 @@ interface ConnectedState {
}
interface ConnectedDispatch {
- onAwaitingSignature: (buyQuote: BuyQuote) => void;
+ onValidationPending: (buyQuote: BuyQuote) => void;
onSignatureDenied: (buyQuote: BuyQuote, error: Error) => void;
onBuyProcessing: (buyQuote: BuyQuote, txHash: string) => void;
onBuySuccess: (buyQuote: BuyQuote, txHash: string) => void;
onBuyFailure: (buyQuote: BuyQuote, txHash: string) => void;
onRetry: () => void;
+ onValidationFail: (buyQuote: BuyQuote, errorMessage: AssetBuyerError | ZeroExInstantError) => void;
}
export interface SelectedAssetBuyOrderStateButtons {}
const mapStateToProps = (state: State, _ownProps: SelectedAssetBuyOrderStateButtons): ConnectedState => ({
@@ -54,8 +56,8 @@ const mapDispatchToProps = (
dispatch: Dispatch<Action>,
ownProps: SelectedAssetBuyOrderStateButtons,
): ConnectedDispatch => ({
- onAwaitingSignature: (buyQuote: BuyQuote) => {
- const newOrderState: OrderState = { processState: OrderProcessState.AWAITING_SIGNATURE };
+ onValidationPending: (buyQuote: BuyQuote) => {
+ const newOrderState: OrderState = { processState: OrderProcessState.VALIDATING };
dispatch(actions.updateBuyOrderState(newOrderState));
},
onBuyProcessing: (buyQuote: BuyQuote, txHash: string) => {
@@ -68,7 +70,11 @@ const mapDispatchToProps = (
dispatch(actions.updateBuyOrderState({ processState: OrderProcessState.FAILURE, txHash })),
onSignatureDenied: (buyQuote, error) => {
dispatch(actions.resetAmount());
- dispatch(actions.setError(error));
+ errorUtil.errorFlasher.flashNewError(dispatch, error);
+ },
+ onValidationFail: (buyQuote, error) => {
+ dispatch(actions.updateBuyOrderState({ processState: OrderProcessState.NONE }));
+ errorUtil.errorFlasher.flashNewError(dispatch, new Error(error));
},
onRetry: () => {
dispatch(actions.resetAmount());
diff --git a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
index 3d741ae97..41ed974a2 100644
--- a/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
+++ b/packages/instant/src/containers/selected_erc20_asset_amount_input.ts
@@ -7,6 +7,7 @@ import * as React from 'react';
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
+import { ERC20AssetAmountInput } from '../components/erc20_asset_amount_input';
import { Action, actions } from '../redux/actions';
import { State } from '../redux/reducer';
import { ColorOption } from '../style/theme';
@@ -14,8 +15,6 @@ import { ERC20Asset, OrderProcessState } from '../types';
import { BigNumberInput } from '../util/big_number_input';
import { errorUtil } from '../util/error';
-import { ERC20AssetAmountInput } from '../components/erc20_asset_amount_input';
-
export interface SelectedERC20AssetAmountInputProps {
fontColor?: ColorOption;
startingFontSizePx: number;
diff --git a/packages/instant/src/types.ts b/packages/instant/src/types.ts
index c63371fb4..c02b66990 100644
--- a/packages/instant/src/types.ts
+++ b/packages/instant/src/types.ts
@@ -10,14 +10,14 @@ export enum AsyncProcessState {
export enum OrderProcessState {
NONE = 'None',
- AWAITING_SIGNATURE = 'Awaiting Signature',
+ VALIDATING = 'Validating',
PROCESSING = 'Processing',
SUCCESS = 'Success',
FAILURE = 'Failure',
}
interface OrderStatePreTx {
- processState: OrderProcessState.NONE | OrderProcessState.AWAITING_SIGNATURE;
+ processState: OrderProcessState.NONE | OrderProcessState.VALIDATING;
}
interface OrderStatePostTx {
processState: OrderProcessState.PROCESSING | OrderProcessState.SUCCESS | OrderProcessState.FAILURE;
@@ -72,4 +72,5 @@ export enum Network {
export enum ZeroExInstantError {
AssetMetaDataNotAvailable = 'ASSET_META_DATA_NOT_AVAILABLE',
+ InsufficientETH = 'INSUFFICIENT_ETH',
}
diff --git a/packages/instant/src/util/address.ts b/packages/instant/src/util/address.ts
new file mode 100644
index 000000000..14d42d8c0
--- /dev/null
+++ b/packages/instant/src/util/address.ts
@@ -0,0 +1,6 @@
+import { web3Wrapper } from '../util/web3_wrapper';
+
+export const getBestAddress = async (): Promise<string | undefined> => {
+ const addresses = await web3Wrapper.getAvailableAddressesAsync();
+ return addresses[0];
+};
diff --git a/packages/instant/src/util/balance.ts b/packages/instant/src/util/balance.ts
new file mode 100644
index 000000000..533656858
--- /dev/null
+++ b/packages/instant/src/util/balance.ts
@@ -0,0 +1,13 @@
+import { BuyQuote } from '@0x/asset-buyer';
+import { Web3Wrapper } from '@0x/web3-wrapper';
+import * as _ from 'lodash';
+
+export const balanceUtil = {
+ hasSufficentEth: async (takerAddress: string | undefined, buyQuote: BuyQuote, web3Wrapper: Web3Wrapper) => {
+ if (_.isUndefined(takerAddress)) {
+ return false;
+ }
+ const balanceWei = await web3Wrapper.getBalanceInWeiAsync(takerAddress);
+ return balanceWei >= buyQuote.worstCaseQuoteInfo.totalEthAmount;
+ },
+};
diff --git a/packages/instant/src/util/error.ts b/packages/instant/src/util/error.ts
index 64c1f4885..39c563c75 100644
--- a/packages/instant/src/util/error.ts
+++ b/packages/instant/src/util/error.ts
@@ -2,7 +2,7 @@ import { AssetBuyerError } from '@0x/asset-buyer';
import { Dispatch } from 'redux';
import { Action, actions } from '../redux/actions';
-import { Asset } from '../types';
+import { Asset, ZeroExInstantError } from '../types';
import { assetUtils } from './asset';
@@ -49,6 +49,9 @@ const humanReadableMessageForError = (error: Error, asset?: Asset): string | und
if (error.message === AssetBuyerError.SignatureRequestDenied) {
return 'You denied this transaction';
}
+ if (error.message === ZeroExInstantError.InsufficientETH) {
+ return "You don't have enough ETH";
+ }
return undefined;
};
diff --git a/packages/instant/src/util/format.ts b/packages/instant/src/util/format.ts
index ca7c01359..4a48dec9d 100644
--- a/packages/instant/src/util/format.ts
+++ b/packages/instant/src/util/format.ts
@@ -2,7 +2,7 @@ import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
import * as _ from 'lodash';
-import { ethDecimals } from '../constants';
+import { ETH_DECIMALS } from '../constants';
export const format = {
ethBaseAmount: (
@@ -13,7 +13,7 @@ export const format = {
if (_.isUndefined(ethBaseAmount)) {
return defaultText;
}
- const ethUnitAmount = Web3Wrapper.toUnitAmount(ethBaseAmount, ethDecimals);
+ const ethUnitAmount = Web3Wrapper.toUnitAmount(ethBaseAmount, ETH_DECIMALS);
return format.ethUnitAmount(ethUnitAmount, decimalPlaces);
},
ethUnitAmount: (
@@ -36,7 +36,7 @@ export const format = {
if (_.isUndefined(ethBaseAmount) || _.isUndefined(ethUsdPrice)) {
return defaultText;
}
- const ethUnitAmount = Web3Wrapper.toUnitAmount(ethBaseAmount, ethDecimals);
+ const ethUnitAmount = Web3Wrapper.toUnitAmount(ethBaseAmount, ETH_DECIMALS);
return format.ethUnitAmountInUsd(ethUnitAmount, ethUsdPrice, decimalPlaces);
},
ethUnitAmountInUsd: (
diff --git a/packages/instant/test/util/format.test.ts b/packages/instant/test/util/format.test.ts
index 2c9294c78..c346b7604 100644
--- a/packages/instant/test/util/format.test.ts
+++ b/packages/instant/test/util/format.test.ts
@@ -1,15 +1,15 @@
import { BigNumber } from '@0x/utils';
import { Web3Wrapper } from '@0x/web3-wrapper';
-import { ethDecimals } from '../../src/constants';
+import { ETH_DECIMALS } from '../../src/constants';
import { format } from '../../src/util/format';
const BIG_NUMBER_ONE = new BigNumber(1);
const BIG_NUMBER_DECIMAL = new BigNumber(0.432414);
const BIG_NUMBER_IRRATIONAL = new BigNumber(5.3014059295032);
-const ONE_ETH_IN_BASE_UNITS = Web3Wrapper.toBaseUnitAmount(BIG_NUMBER_ONE, ethDecimals);
-const DECIMAL_ETH_IN_BASE_UNITS = Web3Wrapper.toBaseUnitAmount(BIG_NUMBER_DECIMAL, ethDecimals);
-const IRRATIONAL_ETH_IN_BASE_UNITS = Web3Wrapper.toBaseUnitAmount(BIG_NUMBER_IRRATIONAL, ethDecimals);
+const ONE_ETH_IN_BASE_UNITS = Web3Wrapper.toBaseUnitAmount(BIG_NUMBER_ONE, ETH_DECIMALS);
+const DECIMAL_ETH_IN_BASE_UNITS = Web3Wrapper.toBaseUnitAmount(BIG_NUMBER_DECIMAL, ETH_DECIMALS);
+const IRRATIONAL_ETH_IN_BASE_UNITS = Web3Wrapper.toBaseUnitAmount(BIG_NUMBER_IRRATIONAL, ETH_DECIMALS);
const BIG_NUMBER_FAKE_ETH_USD_PRICE = new BigNumber(2.534);
describe('format', () => {