From b4faa4851a08fd526a6ffc546eed575b796a5b3d Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Sun, 28 Jan 2018 10:28:17 +0100 Subject: Properly detect user signing cancellation on Metamask, Parity signer and Ledger --- packages/website/ts/components/token_balances.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'packages/website/ts/components/token_balances.tsx') diff --git a/packages/website/ts/components/token_balances.tsx b/packages/website/ts/components/token_balances.tsx index 2cef413c7..88f86fbf5 100644 --- a/packages/website/ts/components/token_balances.tsx +++ b/packages/website/ts/components/token_balances.tsx @@ -519,7 +519,7 @@ export class TokenBalances extends React.Component Date: Sun, 28 Jan 2018 16:19:55 +0100 Subject: Implement just-in-time loading of token balances & allowances --- packages/website/ts/components/token_balances.tsx | 146 +++++++++++++++++----- 1 file changed, 115 insertions(+), 31 deletions(-) (limited to 'packages/website/ts/components/token_balances.tsx') diff --git a/packages/website/ts/components/token_balances.tsx b/packages/website/ts/components/token_balances.tsx index 88f86fbf5..5b450c772 100644 --- a/packages/website/ts/components/token_balances.tsx +++ b/packages/website/ts/components/token_balances.tsx @@ -31,7 +31,6 @@ import { Styles, Token, TokenByAddress, - TokenStateByAddress, TokenVisibility, } from 'ts/types'; import { colors } from 'ts/utils/colors'; @@ -58,6 +57,14 @@ const styles: Styles = { }, }; +interface TokenStateByAddress { + [address: string]: { + balance: BigNumber; + allowance: BigNumber; + isLoaded: boolean; + }; +} + interface TokenBalancesProps { blockchain: Blockchain; blockchainErr: BlockchainErrs; @@ -65,10 +72,11 @@ interface TokenBalancesProps { dispatcher: Dispatcher; screenWidth: ScreenWidths; tokenByAddress: TokenByAddress; - tokenStateByAddress: TokenStateByAddress; + trackedTokens: Token[]; userAddress: string; userEtherBalance: BigNumber; networkId: number; + lastForceTokenStateRefetch: number; } interface TokenBalancesState { @@ -76,14 +84,15 @@ interface TokenBalancesState { isBalanceSpinnerVisible: boolean; isDharmaDialogVisible: boolean; isZRXSpinnerVisible: boolean; - currentZrxBalance?: BigNumber; isTokenPickerOpen: boolean; isAddingToken: boolean; + trackedTokenStateByAddress: TokenStateByAddress; } export class TokenBalances extends React.Component { public constructor(props: TokenBalancesProps) { super(props); + const initialTrackedTokenStateByAddress = this._getInitialTrackedTokenStateByAddress(props.trackedTokens); this.state = { errorType: undefined, isBalanceSpinnerVisible: false, @@ -91,8 +100,14 @@ export class TokenBalances extends React.Component t.symbol === ZRX_TOKEN_SYMBOL); - const nextZrxTokenBalance = nextProps.tokenStateByAddress[nextZrxToken.address].balance; - if (!_.isUndefined(this.state.currentZrxBalance) && !nextZrxTokenBalance.eq(this.state.currentZrxBalance)) { - if (this.state.isZRXSpinnerVisible) { - const receivedAmount = nextZrxTokenBalance.minus(this.state.currentZrxBalance); - const receiveAmountInUnits = ZeroEx.toUnitAmount(receivedAmount, constants.DECIMAL_PLACES_ZRX); - this.props.dispatcher.showFlashMessage(`Received ${receiveAmountInUnits.toString(10)} Kovan ZRX`); - } - this.setState({ - isZRXSpinnerVisible: false, - currentZrxBalance: undefined, - }); + + if ( + nextProps.userAddress !== this.props.userAddress || + nextProps.networkId !== this.props.networkId || + nextProps.lastForceTokenStateRefetch !== this.props.lastForceTokenStateRefetch + ) { + const trackedTokenAddresses = _.keys(this.state.trackedTokenStateByAddress); + // tslint:disable-next-line:no-floating-promises + this._fetchBalancesAndAllowancesAsync(trackedTokenAddresses); + } + + if (!_.isEqual(nextProps.trackedTokens, this.props.trackedTokens)) { + const newTokens = _.difference(nextProps.trackedTokens, this.props.trackedTokens); + const newTokenAddresses = _.map(newTokens, token => token.address); + this._fetchBalancesAndAllowancesAsync(newTokenAddresses); } } public componentDidMount() { @@ -303,8 +321,7 @@ export class TokenBalances extends React.Component t.isTracked); + const trackedTokens = this.props.trackedTokens; const trackedTokensStartingWithEtherToken = trackedTokens.sort( firstBy((t: Token) => t.symbol !== ETHER_TOKEN_SYMBOL) .thenBy((t: Token) => t.symbol !== ZRX_TOKEN_SYMBOL) @@ -317,7 +334,7 @@ export class TokenBalances extends React.Component - {this._renderAmount(tokenState.balance, token.decimals)} {token.symbol} - {this.state.isZRXSpinnerVisible && - token.symbol === ZRX_TOKEN_SYMBOL && ( - - - - )} + {tokenState.isLoaded ? ( + + {this._renderAmount(tokenState.balance, token.decimals)} {token.symbol} + {this.state.isZRXSpinnerVisible && + token.symbol === ZRX_TOKEN_SYMBOL && ( + + + + )} + + ) : ( + + )} @@ -383,11 +408,15 @@ export class TokenBalances extends React.Component )} @@ -414,7 +443,6 @@ export class TokenBalances extends React.Component { try { await this.props.blockchain.mintTestTokensAsync(token); + await this._refetchTokenStateAsync(token.address); const amount = ZeroEx.toUnitAmount(constants.MINT_AMOUNT, token.decimals); this.props.dispatcher.showFlashMessage(`Successfully minted ${amount.toString(10)} ${token.symbol}`); return true; @@ -569,15 +598,11 @@ export class TokenBalances extends React.Component t.symbol === ZRX_TOKEN_SYMBOL); - const zrxTokenState = this.props.tokenStateByAddress[zrxToken.address]; this.setState({ isZRXSpinnerVisible: true, - currentZrxBalance: zrxTokenState.balance, }); // tslint:disable-next-line:no-floating-promises - this.props.blockchain.pollTokenBalanceAsync(zrxToken); + this._startPollingZrxBalanceAsync(); } return true; } @@ -603,4 +628,63 @@ export class TokenBalances extends React.Component t.symbol === ZRX_TOKEN_SYMBOL); + + // tslint:disable-next-line:no-floating-promises + const balance = await this.props.blockchain.pollTokenBalanceAsync(zrxToken); + const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress; + trackedTokenStateByAddress[zrxToken.address] = { + ...trackedTokenStateByAddress[zrxToken.address], + balance, + }; + this.setState({ + isZRXSpinnerVisible: false, + }); + } + private async _fetchBalancesAndAllowancesAsync(tokenAddresses: string[]) { + const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress; + for (const tokenAddress of tokenAddresses) { + const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync( + this.props.userAddress, + tokenAddress, + ); + trackedTokenStateByAddress[tokenAddress] = { + balance, + allowance, + isLoaded: true, + }; + } + this.setState({ + trackedTokenStateByAddress, + }); + } + private _getInitialTrackedTokenStateByAddress(trackedTokens: Token[]) { + const trackedTokenStateByAddress: TokenStateByAddress = {}; + _.each(trackedTokens, token => { + trackedTokenStateByAddress[token.address] = { + balance: new BigNumber(0), + allowance: new BigNumber(0), + isLoaded: false, + }; + }); + return trackedTokenStateByAddress; + } + private async _refetchTokenStateAsync(tokenAddress: string) { + const [balance, allowance] = await this.props.blockchain.getTokenBalanceAndAllowanceAsync( + this.props.userAddress, + tokenAddress, + ); + this.setState({ + trackedTokenStateByAddress: { + ...this.state.trackedTokenStateByAddress, + [tokenAddress]: { + balance, + allowance, + isLoaded: true, + }, + }, + }); + } } // tslint:disable:max-file-line-count -- cgit From 542a1a11b9adc2db07e99cf1cba4b4f6fb24983d Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Mon, 29 Jan 2018 13:16:40 +0100 Subject: Add missing entries for Ropsten and Rinkeby testnets, added Ropsten to Ledger network dropdown --- packages/website/ts/components/token_balances.tsx | 33 ++++++++++++----------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'packages/website/ts/components/token_balances.tsx') diff --git a/packages/website/ts/components/token_balances.tsx b/packages/website/ts/components/token_balances.tsx index 5b450c772..ecafe5432 100644 --- a/packages/website/ts/components/token_balances.tsx +++ b/packages/website/ts/components/token_balances.tsx @@ -27,6 +27,7 @@ import { BlockchainCallErrs, BlockchainErrs, EtherscanLinkSuffixes, + Networks, ScreenWidths, Styles, Token, @@ -155,13 +156,13 @@ export class TokenBalances extends React.Component, ]; - const isTestNetwork = this.props.networkId === constants.NETWORK_ID_TESTNET; + const isKovanTestNetwork = this.props.networkId === constants.NETWORK_ID_KOVAN; const dharmaButtonColumnStyle = { paddingLeft: 3, - display: isTestNetwork ? 'table-cell' : 'none', + display: isKovanTestNetwork ? 'table-cell' : 'none', }; const stubColumnStyle = { - display: isTestNetwork ? 'none' : 'table-cell', + display: isKovanTestNetwork ? 'none' : 'table-cell', }; const allTokenRowHeight = _.size(this.props.tokenByAddress) * TOKEN_TABLE_ROW_HEIGHT; const tokenTableHeight = @@ -180,10 +181,10 @@ export class TokenBalances extends React.Component -

{isTestNetwork ? 'Test ether' : 'Ether'}

+

{isKovanTestNetwork ? 'Test ether' : 'Ether'}

- {isTestNetwork + {isKovanTestNetwork ? 'In order to try out the 0x Portal Dapp, request some test ether to pay for \ gas costs. It might take a bit of time for the test ether to show up.' : 'Ether must be converted to Ether Tokens in order to be tradable via 0x. \ @@ -195,12 +196,12 @@ export class TokenBalances extends React.ComponentCurrency Balance - {isTestNetwork && ( + {isKovanTestNetwork && ( {isSmallScreen ? 'Faucet' : 'Request from faucet'} )} - {isTestNetwork && ( + {isKovanTestNetwork && ( {isSmallScreen ? 'Loan' : 'Request Dharma loan'} @@ -222,7 +223,7 @@ export class TokenBalances extends React.Component - {isTestNetwork && ( + {isKovanTestNetwork && ( )} - {isTestNetwork && ( + {isKovanTestNetwork && (
-

{isTestNetwork ? 'Test tokens' : 'Tokens'}

+

{isKovanTestNetwork ? 'Test tokens' : 'Tokens'}

@@ -261,7 +262,7 @@ export class TokenBalances extends React.Component
- {isTestNetwork + {isKovanTestNetwork ? "Mint some test tokens you'd like to use to generate or fill an order using 0x." : "Set trading permissions for a token you'd like to start trading."}
@@ -391,7 +392,7 @@ export class TokenBalances extends React.Component )} {token.symbol === ZRX_TOKEN_SYMBOL && - this.props.networkId === constants.NETWORK_ID_TESTNET && ( + this.props.networkId === constants.NETWORK_ID_KOVAN && ( - Our faucet can only send test Ether to addresses on the {constants.TESTNET_NAME} testnet - (networkId {constants.NETWORK_ID_TESTNET}). Please make sure you are connected to the{' '} - {constants.TESTNET_NAME} testnet and try requesting ether again. + Our faucet can only send test Ether to addresses on the {Networks.kovan} testnet (networkId{' '} + {constants.NETWORK_ID_KOVAN}). Please make sure you are connected to the {Networks.kovan}{' '} + testnet and try requesting ether again.
); @@ -568,7 +569,7 @@ export class TokenBalances extends React.Component Date: Mon, 29 Jan 2018 13:25:51 +0100 Subject: Fix bug related to balance/allowance fetching being async --- packages/website/ts/components/token_balances.tsx | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'packages/website/ts/components/token_balances.tsx') diff --git a/packages/website/ts/components/token_balances.tsx b/packages/website/ts/components/token_balances.tsx index ecafe5432..776ccb16e 100644 --- a/packages/website/ts/components/token_balances.tsx +++ b/packages/website/ts/components/token_balances.tsx @@ -133,6 +133,20 @@ export class TokenBalances extends React.Component token.address); + // Add placeholder entry for this token to the state, since fetching the + // balance/allowance is asynchronous + const trackedTokenStateByAddress = this.state.trackedTokenStateByAddress; + for (const tokenAddress of newTokenAddresses) { + trackedTokenStateByAddress[tokenAddress] = { + balance: new BigNumber(0), + allowance: new BigNumber(0), + isLoaded: false, + }; + } + this.setState({ + trackedTokenStateByAddress, + }); + // Fetch the actual balance/allowance. this._fetchBalancesAndAllowancesAsync(newTokenAddresses); } } -- cgit From e219772b2a25712f41fb819be36917d3b889201f Mon Sep 17 00:00:00 2001 From: Fabio Berger Date: Tue, 30 Jan 2018 20:12:32 +0100 Subject: Fix all setState calls after unmounted errors. Decided to create our own flag rather then using a cancellablePromise since there was little to be gained from this alternative --- packages/website/ts/components/token_balances.tsx | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'packages/website/ts/components/token_balances.tsx') diff --git a/packages/website/ts/components/token_balances.tsx b/packages/website/ts/components/token_balances.tsx index 776ccb16e..c0df285cf 100644 --- a/packages/website/ts/components/token_balances.tsx +++ b/packages/website/ts/components/token_balances.tsx @@ -91,8 +91,10 @@ interface TokenBalancesState { } export class TokenBalances extends React.Component { + private _isUnmounted: boolean; public constructor(props: TokenBalancesProps) { super(props); + this._isUnmounted = false; const initialTrackedTokenStateByAddress = this._getInitialTrackedTokenStateByAddress(props.trackedTokens); this.state = { errorType: undefined, @@ -109,6 +111,9 @@ export class TokenBalances extends React.Component Date: Tue, 30 Jan 2018 20:45:09 +0100 Subject: Fix linter errors --- packages/website/ts/components/token_balances.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/website/ts/components/token_balances.tsx') diff --git a/packages/website/ts/components/token_balances.tsx b/packages/website/ts/components/token_balances.tsx index c0df285cf..9b9304e23 100644 --- a/packages/website/ts/components/token_balances.tsx +++ b/packages/website/ts/components/token_balances.tsx @@ -107,8 +107,8 @@ export class TokenBalances extends React.Component Date: Tue, 30 Jan 2018 21:01:16 +0100 Subject: Uppercase Networks enum values --- packages/website/ts/components/token_balances.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'packages/website/ts/components/token_balances.tsx') diff --git a/packages/website/ts/components/token_balances.tsx b/packages/website/ts/components/token_balances.tsx index 9b9304e23..c6a9a46be 100644 --- a/packages/website/ts/components/token_balances.tsx +++ b/packages/website/ts/components/token_balances.tsx @@ -497,8 +497,8 @@ export class TokenBalances extends React.Component - Our faucet can only send test Ether to addresses on the {Networks.kovan} testnet (networkId{' '} - {constants.NETWORK_ID_KOVAN}). Please make sure you are connected to the {Networks.kovan}{' '} + Our faucet can only send test Ether to addresses on the {Networks.Kovan} testnet (networkId{' '} + {constants.NETWORK_ID_KOVAN}). Please make sure you are connected to the {Networks.Kovan}{' '} testnet and try requesting ether again.
); -- cgit