diff options
Diffstat (limited to 'packages/instant/src/components')
4 files changed, 75 insertions, 38 deletions
diff --git a/packages/instant/src/components/buy_button.tsx b/packages/instant/src/components/buy_button.tsx index 12ac62601..9d9a8540c 100644 --- a/packages/instant/src/components/buy_button.tsx +++ b/packages/instant/src/components/buy_button.tsx @@ -1,4 +1,5 @@ import { AssetBuyer, AssetBuyerError, BuyQuote } from '@0x/asset-buyer'; +import { Web3Wrapper } from '@0x/web3-wrapper'; import * as _ from 'lodash'; import * as React from 'react'; import { oc } from 'ts-optchain'; @@ -10,7 +11,6 @@ import { getBestAddress } from '../util/address'; import { balanceUtil } from '../util/balance'; import { gasPriceEstimator } from '../util/gas_price_estimator'; import { util } from '../util/util'; -import { web3Wrapper } from '../util/web3_wrapper'; import { Button, Text } from './ui'; @@ -50,7 +50,8 @@ export class BuyButton extends React.Component<BuyButtonProps> { } this.props.onValidationPending(buyQuote); - const takerAddress = await getBestAddress(); + const web3Wrapper = new Web3Wrapper(assetBuyer.provider); + const takerAddress = await getBestAddress(web3Wrapper); const hasSufficientEth = await balanceUtil.hasSufficientEth(takerAddress, buyQuote, web3Wrapper); if (!hasSufficientEth) { diff --git a/packages/instant/src/components/erc20_asset_amount_input.tsx b/packages/instant/src/components/erc20_asset_amount_input.tsx index 5e07dcf2f..6ad0e92e7 100644 --- a/packages/instant/src/components/erc20_asset_amount_input.tsx +++ b/packages/instant/src/components/erc20_asset_amount_input.tsx @@ -1,10 +1,10 @@ +import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; import { ColorOption, transparentWhite } from '../style/theme'; import { ERC20Asset, SimpleHandler } from '../types'; import { assetUtils } from '../util/asset'; -import { BigNumberInput } from '../util/big_number_input'; import { util } from '../util/util'; import { ScalingAmountInput } from './scaling_amount_input'; @@ -13,8 +13,8 @@ import { Container, Flex, Icon, Text } from './ui'; // Asset amounts only apply to ERC20 assets export interface ERC20AssetAmountInputProps { asset?: ERC20Asset; - value?: BigNumberInput; - onChange: (value?: BigNumberInput, asset?: ERC20Asset) => void; + value?: BigNumber; + onChange: (value?: BigNumber, asset?: ERC20Asset) => void; onSelectAssetClick?: (asset?: ERC20Asset) => void; startingFontSizePx: number; fontColor?: ColorOption; @@ -56,7 +56,7 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput {...rest} textLengthThreshold={this._textLengthThresholdForAsset(asset)} maxFontSizePx={this.props.startingFontSizePx} - onChange={this._handleChange} + onAmountChange={this._handleChange} onFontSizeChange={this._handleFontSizeChange} /> </Container> @@ -113,7 +113,7 @@ export class ERC20AssetAmountInput extends React.Component<ERC20AssetAmountInput </Container> ); }; - private readonly _handleChange = (value?: BigNumberInput): void => { + private readonly _handleChange = (value?: BigNumber): void => { this.props.onChange(value, this.props.asset); }; private readonly _handleFontSizeChange = (fontSizePx: number): void => { diff --git a/packages/instant/src/components/scaling_amount_input.tsx b/packages/instant/src/components/scaling_amount_input.tsx index cfbf3b7cc..5dc719293 100644 --- a/packages/instant/src/components/scaling_amount_input.tsx +++ b/packages/instant/src/components/scaling_amount_input.tsx @@ -1,8 +1,11 @@ +import { BigNumber } from '@0x/utils'; import * as _ from 'lodash'; import * as React from 'react'; +import { Maybe } from '../types'; + import { ColorOption } from '../style/theme'; -import { BigNumberInput } from '../util/big_number_input'; +import { maybeBigNumberUtil } from '../util/maybe_big_number'; import { util } from '../util/util'; import { ScalingInput } from './scaling_input'; @@ -12,19 +15,44 @@ export interface ScalingAmountInputProps { maxFontSizePx: number; textLengthThreshold: number; fontColor?: ColorOption; - value?: BigNumberInput; - onChange: (value?: BigNumberInput) => void; + value?: BigNumber; + onAmountChange: (value?: BigNumber) => void; onFontSizeChange: (fontSizePx: number) => void; } +interface ScalingAmountInputState { + stringValue: string; +} -export class ScalingAmountInput extends React.Component<ScalingAmountInputProps> { +const { stringToMaybeBigNumber, areMaybeBigNumbersEqual } = maybeBigNumberUtil; +export class ScalingAmountInput extends React.Component<ScalingAmountInputProps, ScalingAmountInputState> { public static defaultProps = { - onChange: util.boundNoop, + onAmountChange: util.boundNoop, onFontSizeChange: util.boundNoop, isDisabled: false, }; + public constructor(props: ScalingAmountInputProps) { + super(props); + this.state = { + stringValue: _.isUndefined(props.value) ? '' : props.value.toString(), + }; + } + public componentDidUpdate(): void { + const parsedStateValue = stringToMaybeBigNumber(this.state.stringValue); + const currentValue = this.props.value; + + if (!areMaybeBigNumbersEqual(parsedStateValue, currentValue)) { + // we somehow got into the state in which the value passed in and the string value + // in state have differed, reset state + // we dont expect to ever get into this state, but let's make sure + // we reset if we do since we're dealing with important numbers + this.setState({ + stringValue: _.isUndefined(currentValue) ? '' : currentValue.toString(), + }); + } + } + public render(): React.ReactNode { - const { textLengthThreshold, fontColor, maxFontSizePx, value, onFontSizeChange } = this.props; + const { textLengthThreshold, fontColor, maxFontSizePx, onFontSizeChange } = this.props; return ( <ScalingInput maxFontSizePx={maxFontSizePx} @@ -32,7 +60,7 @@ export class ScalingAmountInput extends React.Component<ScalingAmountInputProps> onFontSizeChange={onFontSizeChange} fontColor={fontColor} onChange={this._handleChange} - value={!_.isUndefined(value) ? value.toDisplayString() : ''} + value={this.state.stringValue} placeholder="0.00" emptyInputWidthCh={3.5} isDisabled={this.props.isDisabled} @@ -40,16 +68,16 @@ export class ScalingAmountInput extends React.Component<ScalingAmountInputProps> ); } private readonly _handleChange = (event: React.ChangeEvent<HTMLInputElement>): void => { - const value = event.target.value; - let bigNumberValue; - if (!_.isEmpty(value)) { - try { - bigNumberValue = new BigNumberInput(value); - } catch { - // We don't want to allow values that can't be a BigNumber, so don't even call onChange. - return; - } - } - this.props.onChange(bigNumberValue); + const sanitizedValue = event.target.value.replace(/[^0-9.]/g, ''); // only allow numbers and "." + this.setState({ + stringValue: sanitizedValue, + }); + + // Trigger onAmountChange with a valid BigNumber, or undefined if the sanitizedValue is invalid or empty + const bigNumberValue: Maybe<BigNumber> = _.isEmpty(sanitizedValue) + ? undefined + : stringToMaybeBigNumber(sanitizedValue); + + this.props.onAmountChange(bigNumberValue); }; } diff --git a/packages/instant/src/components/zero_ex_instant_provider.tsx b/packages/instant/src/components/zero_ex_instant_provider.tsx index 59a850bc5..0b9408329 100644 --- a/packages/instant/src/components/zero_ex_instant_provider.tsx +++ b/packages/instant/src/components/zero_ex_instant_provider.tsx @@ -1,8 +1,12 @@ import { AssetBuyer } from '@0x/asset-buyer'; import { ObjectMap, SignedOrder } from '@0x/types'; +import { BigNumber } from '@0x/utils'; +import { Web3Wrapper } from '@0x/web3-wrapper'; +import { Provider } from 'ethereum-types'; import * as _ from 'lodash'; import * as React from 'react'; -import { Provider } from 'react-redux'; +import { Provider as ReduxProvider } from 'react-redux'; +import { oc } from 'ts-optchain'; import { SelectedAssetThemeProvider } from '../containers/selected_asset_theme_provider'; import { asyncData } from '../redux/async_data'; @@ -11,11 +15,9 @@ import { store, Store } from '../redux/store'; import { fonts } from '../style/fonts'; import { AffiliateInfo, AssetMetaData, Network } from '../types'; import { assetUtils } from '../util/asset'; -import { BigNumberInput } from '../util/big_number_input'; import { errorFlasher } from '../util/error_flasher'; import { gasPriceEstimator } from '../util/gas_price_estimator'; -import { getProvider } from '../util/provider'; -import { web3Wrapper } from '../util/web3_wrapper'; +import { getInjectedProvider } from '../util/injected_provider'; fonts.include(); @@ -27,6 +29,7 @@ export interface ZeroExInstantProviderRequiredProps { } export interface ZeroExInstantProviderOptionalProps { + provider: Provider; availableAssetDatas: string[]; defaultAssetBuyAmount: number; defaultSelectedAssetData: string; @@ -40,8 +43,8 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider // TODO(fragosti): Write tests for this beast once we inject a provider. private static _mergeInitialStateWithProps(props: ZeroExInstantProviderProps, state: State = INITIAL_STATE): State { const networkId = props.networkId || state.network; - // TODO: Provider needs to not be hard-coded to injected web3. - const provider = getProvider(); + // TODO: Proper wallet connect flow + const provider = props.provider || getInjectedProvider(); const assetBuyerOptions = { networkId, }; @@ -72,7 +75,7 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider ), selectedAssetAmount: _.isUndefined(props.defaultAssetBuyAmount) ? state.selectedAssetAmount - : new BigNumberInput(props.defaultAssetBuyAmount), + : new BigNumber(props.defaultAssetBuyAmount), availableAssets: _.isUndefined(props.availableAssetDatas) ? undefined : assetUtils.createAssetsFromAssetDatas(props.availableAssetDatas, completeAssetMetaDataMap, networkId), @@ -108,19 +111,24 @@ export class ZeroExInstantProvider extends React.Component<ZeroExInstantProvider public render(): React.ReactNode { return ( - <Provider store={this._store}> + <ReduxProvider store={this._store}> <SelectedAssetThemeProvider>{this.props.children}</SelectedAssetThemeProvider> - </Provider> + </ReduxProvider> ); } private readonly _flashErrorIfWrongNetwork = async (): Promise<void> => { const msToShowError = 30000; // 30 seconds const network = this._store.getState().network; - const networkOfProvider = await web3Wrapper.getNetworkIdAsync(); - if (network !== networkOfProvider) { - const errorMessage = `Wrong network detected. Try switching to ${Network[network]}.`; - errorFlasher.flashNewErrorMessage(this._store.dispatch, errorMessage, msToShowError); + const assetBuyerIfExists = this._store.getState().assetBuyer; + const providerIfExists = oc(assetBuyerIfExists).provider(); + if (!_.isUndefined(providerIfExists)) { + const web3Wrapper = new Web3Wrapper(providerIfExists); + const networkOfProvider = await web3Wrapper.getNetworkIdAsync(); + if (network !== networkOfProvider) { + const errorMessage = `Wrong network detected. Try switching to ${Network[network]}.`; + errorFlasher.flashNewErrorMessage(this._store.dispatch, errorMessage, msToShowError); + } } }; } |