Create blockchainWatcher class and refactor Portal such that Ether amounts are always passed around as baseUnits

This commit is contained in:
Fabio Berger
2018-03-09 19:02:07 +01:00
parent 8f921a61da
commit 7ebebb5bd9
11 changed files with 114 additions and 94 deletions

View File

@@ -24,9 +24,11 @@ import {
RedundantRPCSubprovider, RedundantRPCSubprovider,
} from '@0xproject/subproviders'; } from '@0xproject/subproviders';
import { BigNumber, intervalUtils, promisify } from '@0xproject/utils'; import { BigNumber, intervalUtils, promisify } from '@0xproject/utils';
import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as _ from 'lodash'; import * as _ from 'lodash';
import * as React from 'react'; import * as React from 'react';
import contract = require('truffle-contract'); import contract = require('truffle-contract');
import { BlockchainWatcher } from 'ts/blockchain_watcher';
import { TokenSendCompleted } from 'ts/components/flash_messages/token_send_completed'; import { TokenSendCompleted } from 'ts/components/flash_messages/token_send_completed';
import { TransactionSubmitted } from 'ts/components/flash_messages/transaction_submitted'; import { TransactionSubmitted } from 'ts/components/flash_messages/transaction_submitted';
import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage'; import { trackedTokenStorage } from 'ts/local_storage/tracked_token_storage';
@@ -47,7 +49,6 @@ import { configs } from 'ts/utils/configs';
import { constants } from 'ts/utils/constants'; import { constants } from 'ts/utils/constants';
import { errorReporter } from 'ts/utils/error_reporter'; import { errorReporter } from 'ts/utils/error_reporter';
import { utils } from 'ts/utils/utils'; import { utils } from 'ts/utils/utils';
import { Web3Wrapper } from 'ts/web3_wrapper';
import Web3 = require('web3'); import Web3 = require('web3');
import ProviderEngine = require('web3-provider-engine'); import ProviderEngine = require('web3-provider-engine');
import FilterSubprovider = require('web3-provider-engine/subproviders/filters'); import FilterSubprovider = require('web3-provider-engine/subproviders/filters');
@@ -63,6 +64,7 @@ export class Blockchain {
private _zeroEx: ZeroEx; private _zeroEx: ZeroEx;
private _dispatcher: Dispatcher; private _dispatcher: Dispatcher;
private _web3Wrapper?: Web3Wrapper; private _web3Wrapper?: Web3Wrapper;
private _blockchainWatcher?: BlockchainWatcher;
private _userAddress: string; private _userAddress: string;
private _cachedProvider: Web3.Provider; private _cachedProvider: Web3.Provider;
private _cachedProviderNetworkId: number; private _cachedProviderNetworkId: number;
@@ -188,11 +190,11 @@ export class Blockchain {
// Cache injected provider so that we can switch the user back to it easily // Cache injected provider so that we can switch the user back to it easily
if (_.isUndefined(this._cachedProvider)) { if (_.isUndefined(this._cachedProvider)) {
this._cachedProvider = this._web3Wrapper.getProviderObj(); this._cachedProvider = this._web3Wrapper.getProvider();
this._cachedProviderNetworkId = this.networkId; this._cachedProviderNetworkId = this.networkId;
} }
this._web3Wrapper.destroy(); this._blockchainWatcher.destroy();
this._userAddress = ''; this._userAddress = '';
this._dispatcher.updateUserAddress(''); // Clear old userAddress this._dispatcher.updateUserAddress(''); // Clear old userAddress
@@ -210,9 +212,15 @@ export class Blockchain {
this.networkId = networkId; this.networkId = networkId;
this._dispatcher.updateNetworkId(this.networkId); this._dispatcher.updateNetworkId(this.networkId);
const shouldPollUserAddress = false; const shouldPollUserAddress = false;
this._web3Wrapper = new Web3Wrapper(this._dispatcher, provider, this.networkId, shouldPollUserAddress); this._web3Wrapper = new Web3Wrapper(provider);
this._blockchainWatcher = new BlockchainWatcher(
this._dispatcher,
this._web3Wrapper,
this.networkId,
shouldPollUserAddress,
);
this._zeroEx.setProvider(provider, this.networkId); this._zeroEx.setProvider(provider, this.networkId);
this._web3Wrapper.startEmittingNetworkConnectionAndUserBalanceState(); this._blockchainWatcher.startEmittingNetworkConnectionAndUserBalanceState();
this._dispatcher.updateProviderType(ProviderType.Ledger); this._dispatcher.updateProviderType(ProviderType.Ledger);
} }
public async updateProviderToInjectedAsync() { public async updateProviderToInjectedAsync() {
@@ -222,20 +230,26 @@ export class Blockchain {
return; // Going from injected to injected, so we noop return; // Going from injected to injected, so we noop
} }
this._web3Wrapper.destroy(); this._blockchainWatcher.destroy();
const provider = this._cachedProvider; const provider = this._cachedProvider;
this.networkId = this._cachedProviderNetworkId; this.networkId = this._cachedProviderNetworkId;
const shouldPollUserAddress = true; const shouldPollUserAddress = true;
this._web3Wrapper = new Web3Wrapper(this._dispatcher, provider, this.networkId, shouldPollUserAddress); this._web3Wrapper = new Web3Wrapper(provider);
this._blockchainWatcher = new BlockchainWatcher(
this._dispatcher,
this._web3Wrapper,
this.networkId,
shouldPollUserAddress,
);
this._userAddress = await this._web3Wrapper.getFirstAccountIfExistsAsync(); this._userAddress = await this.getFirstAccountIfExistsAsync();
this._zeroEx.setProvider(provider, this.networkId); this._zeroEx.setProvider(provider, this.networkId);
await this.fetchTokenInformationAsync(); await this.fetchTokenInformationAsync();
this._web3Wrapper.startEmittingNetworkConnectionAndUserBalanceState(); this._blockchainWatcher.startEmittingNetworkConnectionAndUserBalanceState();
this._dispatcher.updateProviderType(ProviderType.Injected); this._dispatcher.updateProviderType(ProviderType.Injected);
delete this._ledgerSubprovider; delete this._ledgerSubprovider;
delete this._cachedProvider; delete this._cachedProvider;
@@ -428,9 +442,9 @@ export class Blockchain {
gasPrice: this._defaultGasPrice, gasPrice: this._defaultGasPrice,
}); });
} }
public async getBalanceInEthAsync(owner: string): Promise<BigNumber> { public async getBalanceInWeiAsync(owner: string): Promise<BigNumber> {
const balance = await this._web3Wrapper.getBalanceInEthAsync(owner); const balanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(owner);
return balance; return balanceInWei;
} }
public async convertEthToWrappedEthTokensAsync(etherTokenAddress: string, amount: BigNumber): Promise<void> { public async convertEthToWrappedEthTokensAsync(etherTokenAddress: string, amount: BigNumber): Promise<void> {
utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.'); utils.assert(!_.isUndefined(this._zeroEx), 'ZeroEx must be instantiated.');
@@ -484,10 +498,10 @@ export class Blockchain {
// by-passes the web3Wrapper logic for updating the prevUserAddress. We therefore need to // by-passes the web3Wrapper logic for updating the prevUserAddress. We therefore need to
// manually update it. This should only be called by the LedgerConfigDialog. // manually update it. This should only be called by the LedgerConfigDialog.
public updateWeb3WrapperPrevUserAddress(newUserAddress: string) { public updateWeb3WrapperPrevUserAddress(newUserAddress: string) {
this._web3Wrapper.updatePrevUserAddress(newUserAddress); this._blockchainWatcher.updatePrevUserAddress(newUserAddress);
} }
public destroy() { public destroy() {
this._web3Wrapper.destroy(); this._blockchainWatcher.destroy();
this._stopWatchingExchangeLogFillEvents(); this._stopWatchingExchangeLogFillEvents();
} }
public async fetchTokenInformationAsync() { public async fetchTokenInformationAsync() {
@@ -540,6 +554,13 @@ export class Blockchain {
this._dispatcher.updateBlockchainIsLoaded(true); this._dispatcher.updateBlockchainIsLoaded(true);
} }
public async getFirstAccountIfExistsAsync() {
const addresses = await this._web3Wrapper.getAvailableAddressesAsync();
if (_.isEmpty(addresses)) {
return '';
}
return addresses[0];
}
private async _showEtherScanLinkAndAwaitTransactionMinedAsync( private async _showEtherScanLinkAndAwaitTransactionMinedAsync(
txHash: string, txHash: string,
): Promise<TransactionReceiptWithDecodedLogs> { ): Promise<TransactionReceiptWithDecodedLogs> {
@@ -736,11 +757,18 @@ export class Blockchain {
this._zeroEx = new ZeroEx(provider, zeroExConfigs); this._zeroEx = new ZeroEx(provider, zeroExConfigs);
this._updateProviderName(injectedWeb3); this._updateProviderName(injectedWeb3);
const shouldPollUserAddress = true; const shouldPollUserAddress = true;
this._web3Wrapper = new Web3Wrapper(this._dispatcher, provider, this.networkId, shouldPollUserAddress); this._web3Wrapper = new Web3Wrapper(provider);
this._userAddress = await this._web3Wrapper.getFirstAccountIfExistsAsync(); this._blockchainWatcher = new BlockchainWatcher(
this._dispatcher,
this._web3Wrapper,
this.networkId,
shouldPollUserAddress,
);
this._userAddress = await this.getFirstAccountIfExistsAsync();
this._dispatcher.updateUserAddress(this._userAddress); this._dispatcher.updateUserAddress(this._userAddress);
await this.fetchTokenInformationAsync(); await this.fetchTokenInformationAsync();
this._web3Wrapper.startEmittingNetworkConnectionAndUserBalanceState(); this._blockchainWatcher.startEmittingNetworkConnectionAndUserBalanceState();
await this._rehydrateStoreWithContractEvents(); await this._rehydrateStoreWithContractEvents();
} }
private _updateProviderName(injectedWeb3: Web3) { private _updateProviderName(injectedWeb3: Web3) {
@@ -752,7 +780,7 @@ export class Blockchain {
} }
private async _instantiateContractIfExistsAsync(artifact: any, address?: string): Promise<ContractInstance> { private async _instantiateContractIfExistsAsync(artifact: any, address?: string): Promise<ContractInstance> {
const c = await contract(artifact); const c = await contract(artifact);
const providerObj = this._web3Wrapper.getProviderObj(); const providerObj = this._web3Wrapper.getProvider();
c.setProvider(providerObj); c.setProvider(providerObj);
const artifactNetworkConfigs = artifact.networks[this.networkId]; const artifactNetworkConfigs = artifact.networks[this.networkId];

View File

@@ -1,60 +1,32 @@
import { BigNumber, intervalUtils, promisify } from '@0xproject/utils'; import { BigNumber, intervalUtils, promisify } from '@0xproject/utils';
import { Web3Wrapper as Web3WrapperBase } from '@0xproject/web3-wrapper'; import { Web3Wrapper } from '@0xproject/web3-wrapper';
import * as _ from 'lodash'; import * as _ from 'lodash';
import { Dispatcher } from 'ts/redux/dispatcher'; import { Dispatcher } from 'ts/redux/dispatcher';
import { utils } from 'ts/utils/utils'; import { utils } from 'ts/utils/utils';
import * as Web3 from 'web3';
export class Web3Wrapper extends Web3WrapperBase { export class BlockchainWatcher {
private _dispatcher: Dispatcher; private _dispatcher: Dispatcher;
private _web3: Web3; private _web3Wrapper: Web3Wrapper;
private _prevNetworkId: number; private _prevNetworkId: number;
private _shouldPollUserAddress: boolean; private _shouldPollUserAddress: boolean;
private _watchNetworkAndBalanceIntervalId: NodeJS.Timer; private _watchNetworkAndBalanceIntervalId: NodeJS.Timer;
private _prevUserEtherBalanceInEth: BigNumber; private _prevUserEtherBalanceInWei: BigNumber;
private _prevUserAddress: string; private _prevUserAddress: string;
constructor( constructor(
dispatcher: Dispatcher, dispatcher: Dispatcher,
provider: Web3.Provider, web3Wrapper: Web3Wrapper,
networkIdIfExists: number, networkIdIfExists: number,
shouldPollUserAddress: boolean, shouldPollUserAddress: boolean,
) { ) {
super(provider);
this._dispatcher = dispatcher; this._dispatcher = dispatcher;
this._prevNetworkId = networkIdIfExists; this._prevNetworkId = networkIdIfExists;
this._shouldPollUserAddress = shouldPollUserAddress; this._shouldPollUserAddress = shouldPollUserAddress;
this._web3Wrapper = web3Wrapper;
this._web3 = new Web3();
this._web3.setProvider(provider);
}
public async getFirstAccountIfExistsAsync() {
const addresses = await this.getAvailableAddressesAsync();
if (_.isEmpty(addresses)) {
return '';
}
return addresses[0];
}
public getProviderObj() {
return this._web3.currentProvider;
}
public async getNetworkIdIfExistsAsync(): Promise<number | undefined> {
try {
const networkId = await this.getNetworkIdAsync();
return Number(networkId);
} catch (err) {
return undefined;
}
}
public async getBalanceInEthAsync(owner: string): Promise<BigNumber> {
const balanceInWei = await this.getBalanceInWeiAsync(owner);
const balanceEthOldBigNumber = this._web3.fromWei(balanceInWei, 'ether');
const balanceEth = new BigNumber(balanceEthOldBigNumber);
return balanceEth;
} }
public destroy() { public destroy() {
this._stopEmittingNetworkConnectionAndUserBalanceStateAsync(); this._stopEmittingNetworkConnectionAndUserBalanceStateAsync();
// HACK: stop() is only available on providerEngine instances // HACK: stop() is only available on providerEngine instances
const provider = this._web3.currentProvider; const provider = this._web3Wrapper.getProvider();
if (!_.isUndefined((provider as any).stop)) { if (!_.isUndefined((provider as any).stop)) {
(provider as any).stop(); (provider as any).stop();
} }
@@ -69,26 +41,32 @@ export class Web3Wrapper extends Web3WrapperBase {
} }
let prevNodeVersion: string; let prevNodeVersion: string;
this._prevUserEtherBalanceInEth = new BigNumber(0); this._prevUserEtherBalanceInWei = new BigNumber(0);
this._dispatcher.updateNetworkId(this._prevNetworkId); this._dispatcher.updateNetworkId(this._prevNetworkId);
this._watchNetworkAndBalanceIntervalId = intervalUtils.setAsyncExcludingInterval( this._watchNetworkAndBalanceIntervalId = intervalUtils.setAsyncExcludingInterval(
async () => { async () => {
// Check for network state changes // Check for network state changes
const currentNetworkId = await this.getNetworkIdIfExistsAsync(); let currentNetworkId;
try {
currentNetworkId = await this._web3Wrapper.getNetworkIdAsync();
} catch (err) {
// Noop
}
if (currentNetworkId !== this._prevNetworkId) { if (currentNetworkId !== this._prevNetworkId) {
this._prevNetworkId = currentNetworkId; this._prevNetworkId = currentNetworkId;
this._dispatcher.updateNetworkId(currentNetworkId); this._dispatcher.updateNetworkId(currentNetworkId);
} }
// Check for node version changes // Check for node version changes
const currentNodeVersion = await this.getNodeVersionAsync(); const currentNodeVersion = await this._web3Wrapper.getNodeVersionAsync();
if (currentNodeVersion !== prevNodeVersion) { if (currentNodeVersion !== prevNodeVersion) {
prevNodeVersion = currentNodeVersion; prevNodeVersion = currentNodeVersion;
this._dispatcher.updateNodeVersion(currentNodeVersion); this._dispatcher.updateNodeVersion(currentNodeVersion);
} }
if (this._shouldPollUserAddress) { if (this._shouldPollUserAddress) {
const userAddressIfExists = await this.getFirstAccountIfExistsAsync(); const addresses = await this._web3Wrapper.getAvailableAddressesAsync();
const userAddressIfExists = addresses[0] || '';
// Update makerAddress on network change // Update makerAddress on network change
if (this._prevUserAddress !== userAddressIfExists) { if (this._prevUserAddress !== userAddressIfExists) {
this._prevUserAddress = userAddressIfExists; this._prevUserAddress = userAddressIfExists;
@@ -97,13 +75,13 @@ export class Web3Wrapper extends Web3WrapperBase {
// Check for user ether balance changes // Check for user ether balance changes
if (!_.isEmpty(userAddressIfExists)) { if (!_.isEmpty(userAddressIfExists)) {
await this._updateUserEtherBalanceAsync(userAddressIfExists); await this._updateUserWeiBalanceAsync(userAddressIfExists);
} }
} else { } else {
// This logic is primarily for the Ledger, since we don't regularly poll for the address // This logic is primarily for the Ledger, since we don't regularly poll for the address
// we simply update the balance for the last fetched address. // we simply update the balance for the last fetched address.
if (!_.isEmpty(this._prevUserAddress)) { if (!_.isEmpty(this._prevUserAddress)) {
await this._updateUserEtherBalanceAsync(this._prevUserAddress); await this._updateUserWeiBalanceAsync(this._prevUserAddress);
} }
} }
}, },
@@ -114,11 +92,11 @@ export class Web3Wrapper extends Web3WrapperBase {
}, },
); );
} }
private async _updateUserEtherBalanceAsync(userAddress: string) { private async _updateUserWeiBalanceAsync(userAddress: string) {
const balance = await this.getBalanceInEthAsync(userAddress); const balanceInWei = await this._web3Wrapper.getBalanceInWeiAsync(userAddress);
if (!balance.eq(this._prevUserEtherBalanceInEth)) { if (!balanceInWei.eq(this._prevUserEtherBalanceInWei)) {
this._prevUserEtherBalanceInEth = balance; this._prevUserEtherBalanceInWei = balanceInWei;
this._dispatcher.updateUserEtherBalance(balance); this._dispatcher.updateUserWeiBalance(balanceInWei);
} }
} }
private _stopEmittingNetworkConnectionAndUserBalanceStateAsync() { private _stopEmittingNetworkConnectionAndUserBalanceStateAsync() {

View File

@@ -1,3 +1,4 @@
import { ZeroEx } from '0x.js';
import { colors } from '@0xproject/react-shared'; import { colors } from '@0xproject/react-shared';
import { BigNumber } from '@0xproject/utils'; import { BigNumber } from '@0xproject/utils';
import Dialog from 'material-ui/Dialog'; import Dialog from 'material-ui/Dialog';
@@ -7,6 +8,7 @@ import { Blockchain } from 'ts/blockchain';
import { EthAmountInput } from 'ts/components/inputs/eth_amount_input'; import { EthAmountInput } from 'ts/components/inputs/eth_amount_input';
import { TokenAmountInput } from 'ts/components/inputs/token_amount_input'; import { TokenAmountInput } from 'ts/components/inputs/token_amount_input';
import { Side, Token } from 'ts/types'; import { Side, Token } from 'ts/types';
import { constants } from 'ts/utils/constants';
interface EthWethConversionDialogProps { interface EthWethConversionDialogProps {
blockchain: Blockchain; blockchain: Blockchain;
@@ -17,7 +19,7 @@ interface EthWethConversionDialogProps {
onCancelled: () => void; onCancelled: () => void;
isOpen: boolean; isOpen: boolean;
token: Token; token: Token;
etherBalance: BigNumber; etherBalanceInWei: BigNumber;
lastForceTokenStateRefetch: number; lastForceTokenStateRefetch: number;
} }
@@ -75,6 +77,7 @@ export class EthWethConversionDialog extends React.Component<
? 'Convert your Ether into a tokenized, tradable form.' ? 'Convert your Ether into a tokenized, tradable form.'
: "Convert your Wrapped Ether back into it's native form."; : "Convert your Wrapped Ether back into it's native form.";
const isWrappedVersion = this.props.direction === Side.Receive; const isWrappedVersion = this.props.direction === Side.Receive;
const etherBalanceInEth = ZeroEx.toUnitAmount(this.props.etherBalanceInWei, constants.DECIMAL_PLACES_ETH);
return ( return (
<div> <div>
<div className="pb2">{explanation}</div> <div className="pb2">{explanation}</div>
@@ -103,7 +106,7 @@ export class EthWethConversionDialog extends React.Component<
/> />
) : ( ) : (
<EthAmountInput <EthAmountInput
balance={this.props.etherBalance} balance={etherBalanceInEth}
amount={this.state.value} amount={this.state.value}
onChange={this._onValueChange.bind(this)} onChange={this._onValueChange.bind(this)}
shouldCheckBalance={true} shouldCheckBalance={true}

View File

@@ -1,3 +1,4 @@
import { ZeroEx } from '0x.js';
import { colors, constants as sharedConstants } from '@0xproject/react-shared'; import { colors, constants as sharedConstants } from '@0xproject/react-shared';
import { BigNumber } from '@0xproject/utils'; import { BigNumber } from '@0xproject/utils';
import * as _ from 'lodash'; import * as _ from 'lodash';
@@ -160,14 +161,15 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
} }
private _renderAddressTableRows() { private _renderAddressTableRows() {
const rows = _.map(this.state.userAddresses, (userAddress: string, i: number) => { const rows = _.map(this.state.userAddresses, (userAddress: string, i: number) => {
const balance = this.state.addressBalances[i]; const balanceInWei = this.state.addressBalances[i];
const addressTooltipId = `address-${userAddress}`; const addressTooltipId = `address-${userAddress}`;
const balanceTooltipId = `balance-${userAddress}`; const balanceTooltipId = `balance-${userAddress}`;
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId]; const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
// We specifically prefix kovan ETH. // We specifically prefix kovan ETH.
// TODO: We should probably add prefixes for all networks // TODO: We should probably add prefixes for all networks
const isKovanNetwork = networkName === 'Kovan'; const isKovanNetwork = networkName === 'Kovan';
const balanceString = `${balance.toString()} ${isKovanNetwork ? 'Kovan ' : ''}ETH`; const balanceInEth = ZeroEx.toUnitAmount(balanceInWei, constants.DECIMAL_PLACES_ETH);
const balanceString = `${balanceInEth.toString()} ${isKovanNetwork ? 'Kovan ' : ''}ETH`;
return ( return (
<TableRow key={userAddress} style={{ height: 40 }}> <TableRow key={userAddress} style={{ height: 40 }}>
<TableRowColumn colSpan={2}> <TableRowColumn colSpan={2}>
@@ -204,7 +206,7 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
this.props.blockchain.updateWeb3WrapperPrevUserAddress(selectedAddress); this.props.blockchain.updateWeb3WrapperPrevUserAddress(selectedAddress);
// tslint:disable-next-line:no-floating-promises // tslint:disable-next-line:no-floating-promises
this.props.blockchain.fetchTokenInformationAsync(); this.props.blockchain.fetchTokenInformationAsync();
this.props.dispatcher.updateUserEtherBalance(selectAddressBalance); this.props.dispatcher.updateUserWeiBalance(selectAddressBalance);
this.setState({ this.setState({
stepIndex: LedgerSteps.CONNECT, stepIndex: LedgerSteps.CONNECT,
}); });
@@ -233,8 +235,8 @@ export class LedgerConfigDialog extends React.Component<LedgerConfigDialogProps,
try { try {
userAddresses = await this._getUserAddressesAsync(); userAddresses = await this._getUserAddressesAsync();
for (const address of userAddresses) { for (const address of userAddresses) {
const balance = await this.props.blockchain.getBalanceInEthAsync(address); const balanceInWei = await this.props.blockchain.getBalanceInWeiAsync(address);
addressBalances.push(balance); addressBalances.push(balanceInWei);
} }
} catch (err) { } catch (err) {
utils.consoleLog(`Ledger error: ${JSON.stringify(err)}`); utils.consoleLog(`Ledger error: ${JSON.stringify(err)}`);

View File

@@ -18,7 +18,7 @@ interface EthWethConversionButtonProps {
ethToken: Token; ethToken: Token;
dispatcher: Dispatcher; dispatcher: Dispatcher;
blockchain: Blockchain; blockchain: Blockchain;
userEtherBalance: BigNumber; userEtherBalanceInWei: BigNumber;
isOutdatedWrappedEther: boolean; isOutdatedWrappedEther: boolean;
onConversionSuccessful?: () => void; onConversionSuccessful?: () => void;
isDisabled?: boolean; isDisabled?: boolean;
@@ -74,7 +74,7 @@ export class EthWethConversionButton extends React.Component<
isOpen={this.state.isEthConversionDialogVisible} isOpen={this.state.isEthConversionDialogVisible}
onComplete={this._onConversionAmountSelectedAsync.bind(this)} onComplete={this._onConversionAmountSelectedAsync.bind(this)}
onCancelled={this._toggleConversionDialog.bind(this)} onCancelled={this._toggleConversionDialog.bind(this)}
etherBalance={this.props.userEtherBalance} etherBalanceInWei={this.props.userEtherBalanceInWei}
token={this.props.ethToken} token={this.props.ethToken}
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
/> />

View File

@@ -34,7 +34,7 @@ interface EthWrappersProps {
dispatcher: Dispatcher; dispatcher: Dispatcher;
tokenByAddress: TokenByAddress; tokenByAddress: TokenByAddress;
userAddress: string; userAddress: string;
userEtherBalance: BigNumber; userEtherBalanceInWei: BigNumber;
lastForceTokenStateRefetch: number; lastForceTokenStateRefetch: number;
} }
@@ -98,6 +98,10 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
EtherscanLinkSuffixes.Address, EtherscanLinkSuffixes.Address,
); );
const tokenLabel = this._renderToken('Wrapped Ether', etherToken.address, configs.ICON_URL_BY_SYMBOL.WETH); const tokenLabel = this._renderToken('Wrapped Ether', etherToken.address, configs.ICON_URL_BY_SYMBOL.WETH);
const userEtherBalanceInEth = ZeroEx.toUnitAmount(
this.props.userEtherBalanceInWei,
constants.DECIMAL_PLACES_ETH,
);
return ( return (
<div className="clearfix lg-px4 md-px4 sm-px2" style={{ minHeight: 600 }}> <div className="clearfix lg-px4 md-px4 sm-px2" style={{ minHeight: 600 }}>
<div className="relative"> <div className="relative">
@@ -143,9 +147,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
</div> </div>
</div> </div>
</TableRowColumn> </TableRowColumn>
<TableRowColumn> <TableRowColumn>{userEtherBalanceInEth.toFixed(PRECISION)} ETH</TableRowColumn>
{this.props.userEtherBalance.toFixed(PRECISION)} ETH
</TableRowColumn>
<TableRowColumn> <TableRowColumn>
<EthWethConversionButton <EthWethConversionButton
refetchEthTokenStateAsync={this._refetchEthTokenStateAsync.bind(this)} refetchEthTokenStateAsync={this._refetchEthTokenStateAsync.bind(this)}
@@ -157,7 +159,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
ethToken={etherToken} ethToken={etherToken}
dispatcher={this.props.dispatcher} dispatcher={this.props.dispatcher}
blockchain={this.props.blockchain} blockchain={this.props.blockchain}
userEtherBalance={this.props.userEtherBalance} userEtherBalanceInWei={this.props.userEtherBalanceInWei}
/> />
</TableRowColumn> </TableRowColumn>
</TableRow> </TableRow>
@@ -184,7 +186,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
ethToken={etherToken} ethToken={etherToken}
dispatcher={this.props.dispatcher} dispatcher={this.props.dispatcher}
blockchain={this.props.blockchain} blockchain={this.props.blockchain}
userEtherBalance={this.props.userEtherBalance} userEtherBalanceInWei={this.props.userEtherBalanceInWei}
/> />
</TableRowColumn> </TableRowColumn>
</TableRow> </TableRow>
@@ -304,7 +306,7 @@ export class EthWrappers extends React.Component<EthWrappersProps, EthWrappersSt
ethToken={outdatedEtherToken} ethToken={outdatedEtherToken}
dispatcher={this.props.dispatcher} dispatcher={this.props.dispatcher}
blockchain={this.props.blockchain} blockchain={this.props.blockchain}
userEtherBalance={this.props.userEtherBalance} userEtherBalanceInWei={this.props.userEtherBalanceInWei}
onConversionSuccessful={onConversionSuccessful} onConversionSuccessful={onConversionSuccessful}
/> />
</TableRowColumn> </TableRowColumn>

View File

@@ -46,7 +46,7 @@ export interface PortalAllProps {
providerType: ProviderType; providerType: ProviderType;
screenWidth: ScreenWidths; screenWidth: ScreenWidths;
tokenByAddress: TokenByAddress; tokenByAddress: TokenByAddress;
userEtherBalance: BigNumber; userEtherBalanceInWei: BigNumber;
userAddress: string; userAddress: string;
shouldBlockchainErrDialogBeOpen: boolean; shouldBlockchainErrDialogBeOpen: boolean;
userSuppliedOrderCache: Order; userSuppliedOrderCache: Order;
@@ -279,7 +279,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
dispatcher={this.props.dispatcher} dispatcher={this.props.dispatcher}
tokenByAddress={this.props.tokenByAddress} tokenByAddress={this.props.tokenByAddress}
userAddress={this.props.userAddress} userAddress={this.props.userAddress}
userEtherBalance={this.props.userEtherBalance} userEtherBalanceInWei={this.props.userEtherBalanceInWei}
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
/> />
); );
@@ -306,7 +306,7 @@ export class Portal extends React.Component<PortalAllProps, PortalAllState> {
tokenByAddress={this.props.tokenByAddress} tokenByAddress={this.props.tokenByAddress}
trackedTokens={trackedTokens} trackedTokens={trackedTokens}
userAddress={this.props.userAddress} userAddress={this.props.userAddress}
userEtherBalance={this.props.userEtherBalance} userEtherBalanceInWei={this.props.userEtherBalanceInWei}
networkId={this.props.networkId} networkId={this.props.networkId}
lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch} lastForceTokenStateRefetch={this.props.lastForceTokenStateRefetch}
/> />

View File

@@ -79,7 +79,7 @@ interface TokenBalancesProps {
tokenByAddress: TokenByAddress; tokenByAddress: TokenByAddress;
trackedTokens: Token[]; trackedTokens: Token[];
userAddress: string; userAddress: string;
userEtherBalance: BigNumber; userEtherBalanceInWei: BigNumber;
networkId: number; networkId: number;
lastForceTokenStateRefetch: number; lastForceTokenStateRefetch: number;
} }
@@ -119,11 +119,14 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
this._isUnmounted = true; this._isUnmounted = true;
} }
public componentWillReceiveProps(nextProps: TokenBalancesProps) { public componentWillReceiveProps(nextProps: TokenBalancesProps) {
if (nextProps.userEtherBalance !== this.props.userEtherBalance) { if (nextProps.userEtherBalanceInWei !== this.props.userEtherBalanceInWei) {
if (this.state.isBalanceSpinnerVisible) { if (this.state.isBalanceSpinnerVisible) {
const receivedAmount = nextProps.userEtherBalance.minus(this.props.userEtherBalance); const receivedAmountInWei = nextProps.userEtherBalanceInWei.minus(this.props.userEtherBalanceInWei);
const receivedAmountInEth = ZeroEx.toUnitAmount(receivedAmountInWei, constants.DECIMAL_PLACES_ETH);
const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId]; const networkName = sharedConstants.NETWORK_NAME_BY_ID[this.props.networkId];
this.props.dispatcher.showFlashMessage(`Received ${receivedAmount.toString(10)} ${networkName} Ether`); this.props.dispatcher.showFlashMessage(
`Received ${receivedAmountInEth.toString(10)} ${networkName} Ether`,
);
} }
this.setState({ this.setState({
isBalanceSpinnerVisible: false, isBalanceSpinnerVisible: false,
@@ -205,6 +208,10 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
token balances in order to execute trades.<br> \ token balances in order to execute trades.<br> \
Toggling sets an allowance for the<br> \ Toggling sets an allowance for the<br> \
smart contract so you can start trading that token.'; smart contract so you can start trading that token.';
const userEtherBalanceInEth = ZeroEx.toUnitAmount(
this.props.userEtherBalanceInWei,
constants.DECIMAL_PLACES_ETH,
);
return ( return (
<div className="lg-px4 md-px4 sm-px1 pb2"> <div className="lg-px4 md-px4 sm-px1 pb2">
<h3>{isTestNetwork ? 'Test ether' : 'Ether'}</h3> <h3>{isTestNetwork ? 'Test ether' : 'Ether'}</h3>
@@ -241,7 +248,7 @@ export class TokenBalances extends React.Component<TokenBalancesProps, TokenBala
<img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={ETHER_ICON_PATH} /> <img style={{ width: ICON_DIMENSION, height: ICON_DIMENSION }} src={ETHER_ICON_PATH} />
</TableRowColumn> </TableRowColumn>
<TableRowColumn> <TableRowColumn>
{this.props.userEtherBalance.toFixed(PRECISION)} ETH {userEtherBalanceInEth.toFixed(PRECISION)} ETH
{this.state.isBalanceSpinnerVisible && ( {this.state.isBalanceSpinnerVisible && (
<span className="pl1"> <span className="pl1">
<i className="zmdi zmdi-spinner zmdi-hc-spin" /> <i className="zmdi zmdi-spinner zmdi-hc-spin" />

View File

@@ -21,7 +21,7 @@ interface ConnectedState {
providerType: ProviderType; providerType: ProviderType;
tokenByAddress: TokenByAddress; tokenByAddress: TokenByAddress;
lastForceTokenStateRefetch: number; lastForceTokenStateRefetch: number;
userEtherBalance: BigNumber; userEtherBalanceInWei: BigNumber;
screenWidth: ScreenWidths; screenWidth: ScreenWidths;
shouldBlockchainErrDialogBeOpen: boolean; shouldBlockchainErrDialogBeOpen: boolean;
userAddress: string; userAddress: string;
@@ -72,7 +72,7 @@ const mapStateToProps = (state: State, ownProps: PortalComponentAllProps): Conne
tokenByAddress: state.tokenByAddress, tokenByAddress: state.tokenByAddress,
lastForceTokenStateRefetch: state.lastForceTokenStateRefetch, lastForceTokenStateRefetch: state.lastForceTokenStateRefetch,
userAddress: state.userAddress, userAddress: state.userAddress,
userEtherBalance: state.userEtherBalance, userEtherBalanceInWei: state.userEtherBalanceInWei,
userSuppliedOrderCache: state.userSuppliedOrderCache, userSuppliedOrderCache: state.userSuppliedOrderCache,
flashMessage: state.flashMessage, flashMessage: state.flashMessage,
translate: state.translate, translate: state.translate,

View File

@@ -155,7 +155,7 @@ export class Dispatcher {
type: ActionTypes.UpdateOrderECSignature, type: ActionTypes.UpdateOrderECSignature,
}); });
} }
public updateUserEtherBalance(balance: BigNumber) { public updateUserWeiBalance(balance: BigNumber) {
this._dispatch({ this._dispatch({
data: balance, data: balance,
type: ActionTypes.UpdateUserEtherBalance, type: ActionTypes.UpdateUserEtherBalance,

View File

@@ -38,7 +38,7 @@ export interface State {
tokenByAddress: TokenByAddress; tokenByAddress: TokenByAddress;
lastForceTokenStateRefetch: number; lastForceTokenStateRefetch: number;
userAddress: string; userAddress: string;
userEtherBalance: BigNumber; userEtherBalanceInWei: BigNumber;
// Note: cache of supplied orderJSON in fill order step. Do not use for anything else. // Note: cache of supplied orderJSON in fill order step. Do not use for anything else.
userSuppliedOrderCache: Order; userSuppliedOrderCache: Order;
@@ -77,7 +77,7 @@ const INITIAL_STATE: State = {
tokenByAddress: {}, tokenByAddress: {},
lastForceTokenStateRefetch: moment().unix(), lastForceTokenStateRefetch: moment().unix(),
userAddress: '', userAddress: '',
userEtherBalance: new BigNumber(0), userEtherBalanceInWei: new BigNumber(0),
userSuppliedOrderCache: undefined, userSuppliedOrderCache: undefined,
// Docs // Docs
@@ -138,7 +138,7 @@ export function reducer(state: State = INITIAL_STATE, action: Action) {
case ActionTypes.UpdateUserEtherBalance: { case ActionTypes.UpdateUserEtherBalance: {
return { return {
...state, ...state,
userEtherBalance: action.data, userEtherBalanceInWei: action.data,
}; };
} }