aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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.ts23
-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/format.ts6
-rw-r--r--packages/instant/test/util/format.test.ts8
-rw-r--r--yarn.lock41
11 files changed, 79 insertions, 69 deletions
diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx
index 9e06604e0..13c1dc88c 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) => 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);
- return;
+ if (e instanceof Error) {
+ if (e.message === AssetBuyerError.SignatureRequestDenied) {
+ this.props.onSignatureDenied(buyQuote);
+ 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 758eabcb7..d01e9ff57 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) => 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 10734df96..500d6b88a 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,17 +1,16 @@
-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';
import { Dispatch } from 'redux';
+import { BuyOrderStateButtons } from '../components/buy_order_state_buttons';
import { Action, actions } from '../redux/actions';
import { State } from '../redux/reducer';
-import { OrderProcessState, OrderState } from '../types';
+import { OrderProcessState, OrderState, ZeroExInstantError } from '../types';
import { errorFlasher } from '../util/error_flasher';
import { etherscanUtil } from '../util/etherscan';
-import { BuyOrderStateButtons } from '../components/buy_order_state_buttons';
-
interface ConnectedState {
buyQuote?: BuyQuote;
buyOrderProcessingState: OrderProcessState;
@@ -20,12 +19,13 @@ interface ConnectedState {
}
interface ConnectedDispatch {
- onAwaitingSignature: (buyQuote: BuyQuote) => void;
+ onValidationPending: (buyQuote: BuyQuote) => void;
onSignatureDenied: (buyQuote: BuyQuote) => 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 => ({
@@ -55,8 +55,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) => {
@@ -72,6 +72,15 @@ const mapDispatchToProps = (
const errorMessage = 'You denied this transaction';
errorFlasher.flashNewErrorMessage(dispatch, errorMessage);
},
+ onValidationFail: (buyQuote, error) => {
+ dispatch(actions.updateBuyOrderState({ processState: OrderProcessState.NONE }));
+ if (error === ZeroExInstantError.InsufficientETH) {
+ const errorMessage = "You don't have enough ETH";
+ errorFlasher.flashNewErrorMessage(dispatch, errorMessage);
+ } else {
+ errorFlasher.flashNewErrorMessage(dispatch);
+ }
+ },
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 1e93a6deb..4767b15d4 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';
@@ -15,8 +16,6 @@ import { assetUtils } from '../util/asset';
import { BigNumberInput } from '../util/big_number_input';
import { errorFlasher } from '../util/error_flasher';
-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 e02a815f9..336465e43 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/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', () => {
diff --git a/yarn.lock b/yarn.lock
index aeddefa31..18d143ed5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1900,10 +1900,6 @@ aes-js@^0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/aes-js/-/aes-js-0.2.4.tgz#94b881ab717286d015fa219e08fb66709dda5a3d"
-aes-js@^3.1.1:
- version "3.1.1"
- resolved "https://registry.npmjs.org/aes-js/-/aes-js-3.1.1.tgz#89fd1f94ae51b4c72d62466adc1a7323ff52f072"
-
agent-base@4, agent-base@^4.1.0, agent-base@~4.2.0:
version "4.2.1"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9"
@@ -3341,7 +3337,7 @@ bs-logger@0.x:
dependencies:
fast-json-stable-stringify "^2.0.0"
-bs58@=4.0.1, bs58@^4.0.0:
+bs58@=4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a"
dependencies:
@@ -3364,14 +3360,6 @@ bs58check@^1.0.8:
bs58 "^3.1.0"
create-hash "^1.1.0"
-bs58check@^2.1.2:
- version "2.1.2"
- resolved "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc"
- dependencies:
- bs58 "^4.0.0"
- create-hash "^1.1.0"
- safe-buffer "^5.1.2"
-
bser@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/bser/-/bser-2.0.0.tgz#9ac78d3ed5d915804fd87acb158bc797147a1719"
@@ -5959,19 +5947,6 @@ ethereumjs-wallet@0.6.0:
utf8 "^2.1.1"
uuid "^2.0.1"
-ethereumjs-wallet@~0.6.0:
- version "0.6.2"
- resolved "https://registry.npmjs.org/ethereumjs-wallet/-/ethereumjs-wallet-0.6.2.tgz#67244b6af3e8113b53d709124b25477b64aeccda"
- dependencies:
- aes-js "^3.1.1"
- bs58check "^2.1.2"
- ethereumjs-util "^5.2.0"
- hdkey "^1.0.0"
- safe-buffer "^5.1.2"
- scrypt.js "^0.2.0"
- utf8 "^3.0.0"
- uuid "^3.3.2"
-
ethers@~4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/ethers/-/ethers-4.0.4.tgz#d3f85e8b27f4b59537e06526439b0fb15b44dc65"
@@ -6776,7 +6751,7 @@ ganache-core@0xProject/ganache-core#monorepo-dep:
ethereumjs-tx "0xProject/ethereumjs-tx#fake-tx-include-signature-by-default"
ethereumjs-util "^5.2.0"
ethereumjs-vm "2.3.5"
- ethereumjs-wallet "~0.6.0"
+ ethereumjs-wallet "0.6.0"
fake-merkle-patricia-tree "~1.0.1"
heap "~0.2.6"
js-scrypt "^0.2.0"
@@ -7501,14 +7476,6 @@ hdkey@^0.7.0, hdkey@^0.7.1:
coinstring "^2.0.0"
secp256k1 "^3.0.1"
-hdkey@^1.0.0:
- version "1.1.0"
- resolved "https://registry.npmjs.org/hdkey/-/hdkey-1.1.0.tgz#e74e7b01d2c47f797fa65d1d839adb7a44639f29"
- dependencies:
- coinstring "^2.0.0"
- safe-buffer "^5.1.1"
- secp256k1 "^3.0.1"
-
he@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
@@ -15595,10 +15562,6 @@ utf8@^2.1.1:
version "2.1.2"
resolved "https://registry.yarnpkg.com/utf8/-/utf8-2.1.2.tgz#1fa0d9270e9be850d9b05027f63519bf46457d96"
-utf8@^3.0.0:
- version "3.0.0"
- resolved "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1"
-
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"