Skip to content

Commit

Permalink
Handling custom token decimal fetch failure due to network error (#10956
Browse files Browse the repository at this point in the history
)
  • Loading branch information
NiranjanaBinoy authored May 18, 2021
1 parent 9d78c8b commit 0e11818
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 57 deletions.
9 changes: 8 additions & 1 deletion app/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@
"message": "Some of your account data was backed up during a previous installation of MetaMask. This could include your settings, contacts, and tokens. Would you like to restore this data now?"
},
"decimal": {
"message": "Decimals of Precision"
"message": "Token Decimal"
},
"decimalsMustZerotoTen": {
"message": "Decimals must be at least 0, and not over 36."
Expand Down Expand Up @@ -2205,6 +2205,9 @@
"tokenContractAddress": {
"message": "Token Contract Address"
},
"tokenDecimalFetchFailed": {
"message": "Token decimal required."
},
"tokenSymbol": {
"message": "Token Symbol"
},
Expand Down Expand Up @@ -2336,6 +2339,10 @@
"userName": {
"message": "Username"
},
"verifyThisTokenDecimalOn": {
"message": "Token decimal can be found on $1",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
},
"verifyThisTokenOn": {
"message": "Verify this token on $1",
"description": "Points the user to etherscan as a place they can verify information about a token. $1 is replaced with the translation for \"etherscan\""
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
"@metamask/controllers": "^8.0.0",
"@metamask/eth-ledger-bridge-keyring": "^0.5.0",
"@metamask/eth-token-tracker": "^3.0.1",
"@metamask/etherscan-link": "^2.0.0",
"@metamask/etherscan-link": "^2.1.0",
"@metamask/jazzicon": "^2.0.0",
"@metamask/logo": "^2.5.0",
"@metamask/obs-store": "^5.0.0",
Expand Down
22 changes: 1 addition & 21 deletions ui/helpers/utils/token-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const casedContractMap = Object.keys(contractMap).reduce((acc, base) => {
}, {});

const DEFAULT_SYMBOL = '';
const DEFAULT_DECIMALS = '0';

async function getSymbolFromContract(tokenAddress) {
const token = util.getContractAtAddress(tokenAddress);
Expand Down Expand Up @@ -78,25 +77,6 @@ async function getDecimals(tokenAddress) {
return decimals;
}

export async function fetchSymbolAndDecimals(tokenAddress) {
let symbol, decimals;

try {
symbol = await getSymbol(tokenAddress);
decimals = await getDecimals(tokenAddress);
} catch (error) {
log.warn(
`symbol() and decimal() calls for token at address ${tokenAddress} resulted in error:`,
error,
);
}

return {
symbol: symbol || DEFAULT_SYMBOL,
decimals: decimals || DEFAULT_DECIMALS,
};
}

export async function getSymbolAndDecimals(tokenAddress, existingTokens = []) {
const existingToken = existingTokens.find(
({ address }) => tokenAddress === address,
Expand All @@ -123,7 +103,7 @@ export async function getSymbolAndDecimals(tokenAddress, existingTokens = []) {

return {
symbol: symbol || DEFAULT_SYMBOL,
decimals: decimals || DEFAULT_DECIMALS,
decimals,
};
}

Expand Down
97 changes: 78 additions & 19 deletions ui/pages/add-token/add-token.component.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { getTokenTrackerLink } from '@metamask/etherscan-link';
import { checkExistingAddresses } from '../../helpers/utils/util';
import { tokenInfoGetter } from '../../helpers/utils/token-util';
import { CONFIRM_ADD_TOKEN_ROUTE } from '../../helpers/constants/routes';
Expand All @@ -8,8 +9,12 @@ import PageContainer from '../../components/ui/page-container';
import { Tabs, Tab } from '../../components/ui/tabs';
import { addHexPrefix } from '../../../app/scripts/lib/util';
import { isValidHexAddress } from '../../../shared/modules/hexstring-utils';
import TokenList from './token-list';
import ActionableMessage from '../swaps/actionable-message';
import Typography from '../../components/ui/typography';
import { TYPOGRAPHY, FONT_WEIGHT } from '../../helpers/constants/design-system';
import Button from '../../components/ui/button';
import TokenSearch from './token-search';
import TokenList from './token-list';

const emptyAddr = '0x0000000000000000000000000000000000000000';

Expand All @@ -30,6 +35,8 @@ class AddToken extends Component {
identities: PropTypes.object,
showSearchTab: PropTypes.bool.isRequired,
mostRecentOverviewPage: PropTypes.string.isRequired,
chainId: PropTypes.string,
rpcPrefs: PropTypes.object,
};

state = {
Expand All @@ -42,8 +49,9 @@ class AddToken extends Component {
customAddressError: null,
customSymbolError: null,
customDecimalsError: null,
autoFilled: false,
forceEditSymbol: false,
symbolAutoFilled: false,
decimalAutoFilled: false,
};

componentDidMount() {
Expand Down Expand Up @@ -148,10 +156,11 @@ class AddToken extends Component {
}

async attemptToAutoFillTokenParams(address) {
const { symbol = '', decimals = 0 } = await this.tokenInfoGetter(address);
const { symbol = '', decimals } = await this.tokenInfoGetter(address);

const autoFilled = Boolean(symbol && decimals);
this.setState({ autoFilled });
const symbolAutoFilled = Boolean(symbol);
const decimalAutoFilled = Boolean(decimals);
this.setState({ symbolAutoFilled, decimalAutoFilled });
this.handleCustomSymbolChange(symbol || '');
this.handleCustomDecimalsChange(decimals);
}
Expand All @@ -162,7 +171,8 @@ class AddToken extends Component {
customAddress,
customAddressError: null,
tokenSelectorError: null,
autoFilled: false,
symbolAutoFilled: false,
decimalAutoFilled: false,
});

const addressIsValid = isValidHexAddress(customAddress, {
Expand Down Expand Up @@ -213,16 +223,18 @@ class AddToken extends Component {
}

handleCustomDecimalsChange(value) {
const customDecimals = value.trim();
const validDecimals =
customDecimals !== null &&
customDecimals !== '' &&
customDecimals >= MIN_DECIMAL_VALUE &&
customDecimals <= MAX_DECIMAL_VALUE;
let customDecimals;
let customDecimalsError = null;

if (!validDecimals) {
customDecimalsError = this.context.t('decimalsMustZerotoTen');
if (value) {
customDecimals = Number(value.trim());
customDecimalsError =
value < MIN_DECIMAL_VALUE || value > MAX_DECIMAL_VALUE
? this.context.t('decimalsMustZerotoTen')
: null;
} else {
customDecimals = '';
customDecimalsError = this.context.t('tokenDecimalFetchFailed');
}

this.setState({ customDecimals, customDecimalsError });
Expand All @@ -236,10 +248,23 @@ class AddToken extends Component {
customAddressError,
customSymbolError,
customDecimalsError,
autoFilled,
forceEditSymbol,
symbolAutoFilled,
decimalAutoFilled,
} = this.state;

const { chainId, rpcPrefs } = this.props;
const blockExplorerTokenLink = getTokenTrackerLink(
customAddress,
chainId,
null,
null,
{ blockExplorerUrl: rpcPrefs?.blockExplorerUrl ?? null },
);
const blockExplorerLabel = rpcPrefs?.blockExplorerUrl
? new URL(blockExplorerTokenLink).hostname
: this.context.t('etherscan');

return (
<div className="add-token__custom-token-form">
<TextField
Expand All @@ -260,7 +285,7 @@ class AddToken extends Component {
<span className="add-token__custom-symbol__label">
{this.context.t('tokenSymbol')}
</span>
{autoFilled && !forceEditSymbol && (
{symbolAutoFilled && !forceEditSymbol && (
<div
className="add-token__custom-symbol__edit"
onClick={() => this.setState({ forceEditSymbol: true })}
Expand All @@ -276,21 +301,55 @@ class AddToken extends Component {
error={customSymbolError}
fullWidth
margin="normal"
disabled={autoFilled && !forceEditSymbol}
disabled={symbolAutoFilled && !forceEditSymbol}
/>
<TextField
id="custom-decimals"
label={this.context.t('decimal')}
type="number"
value={customDecimals}
onChange={(e) => this.handleCustomDecimalsChange(e.target.value)}
error={customDecimalsError}
error={customDecimals ? customDecimalsError : null}
fullWidth
margin="normal"
disabled={autoFilled}
disabled={decimalAutoFilled}
min={MIN_DECIMAL_VALUE}
max={MAX_DECIMAL_VALUE}
/>
{customDecimals === '' && (
<ActionableMessage
message={
<>
<Typography
variant={TYPOGRAPHY.H7}
fontWeight={FONT_WEIGHT.BOLD}
>
{this.context.t('tokenDecimalFetchFailed')}
</Typography>
<Typography
variant={TYPOGRAPHY.H7}
fontWeight={FONT_WEIGHT.NORMAL}
>
{this.context.t('verifyThisTokenDecimalOn', [
<Button
type="link"
key="add-token-verify-token-decimal"
className="add-token__link"
rel="noopener noreferrer"
target="_blank"
href={blockExplorerTokenLink}
>
{blockExplorerLabel}
</Button>,
])}
</Typography>
</>
}
type="warning"
withRightButton
className="add-token__decimal-warning"
/>
)}
</div>
);
}
Expand Down
14 changes: 12 additions & 2 deletions ui/pages/add-token/add-token.container.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,29 @@ import { connect } from 'react-redux';

import { setPendingTokens, clearPendingTokens } from '../../store/actions';
import { getMostRecentOverviewPage } from '../../ducks/history/history';
import { getIsMainnet } from '../../selectors/selectors';
import {
getIsMainnet,
getRpcPrefsForCurrentProvider,
} from '../../selectors/selectors';
import AddToken from './add-token.component';

const mapStateToProps = (state) => {
const {
metamask: { identities, tokens, pendingTokens },
metamask: {
identities,
tokens,
pendingTokens,
provider: { chainId },
},
} = state;
return {
identities,
mostRecentOverviewPage: getMostRecentOverviewPage(state),
tokens,
pendingTokens,
showSearchTab: getIsMainnet(state) || process.env.IN_TEST === 'true',
chainId,
rpcPrefs: getRpcPrefsForCurrentProvider(state),
};
};

Expand Down
2 changes: 1 addition & 1 deletion ui/pages/add-token/add-token.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe('Add Token', () => {

expect(
wrapper.find('AddToken').instance().state.customDecimals,
).toStrictEqual(tokenPrecision);
).toStrictEqual(Number(tokenPrecision));
});

it('next', () => {
Expand Down
13 changes: 13 additions & 0 deletions ui/pages/add-token/index.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
@import 'token-list/index';

.add-token {
$self: &;

&__custom-token-form {
padding: 8px 16px 16px;

Expand All @@ -13,6 +15,9 @@
-webkit-appearance: none;
display: none;
}
& #{$self}__decimal-warning {
margin-top: 5px;
}
}

&__search-token {
Expand Down Expand Up @@ -41,4 +46,12 @@
cursor: pointer;
}
}

&__link {
@include H7;

display: inline;
color: $primary-blue;
padding-left: 0;
}
}
14 changes: 6 additions & 8 deletions ui/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
loadRelativeTimeFormatLocaleData,
} from '../helpers/utils/i18n-helper';
import { getMethodDataAsync } from '../helpers/utils/transactions.util';
import { fetchSymbolAndDecimals } from '../helpers/utils/token-util';
import { getSymbolAndDecimals } from '../helpers/utils/token-util';
import switchDirection from '../helpers/utils/switch-direction';
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../shared/constants/app';
import { hasUnconfirmedTransactions } from '../helpers/utils/confirm-tx.util';
Expand Down Expand Up @@ -2251,7 +2251,7 @@ export function setPendingTokens(pendingTokens) {
const { customToken = {}, selectedTokens = {} } = pendingTokens;
const { address, symbol, decimals } = customToken;
const tokens =
address && symbol && decimals
address && symbol && decimals >= 0 <= 36
? {
...selectedTokens,
[address]: {
Expand Down Expand Up @@ -2653,12 +2653,10 @@ export function getTokenParams(tokenAddress) {
dispatch(loadingTokenParamsStarted());
log.debug(`loadingTokenParams`);

return fetchSymbolAndDecimals(tokenAddress, existingTokens).then(
({ symbol, decimals }) => {
dispatch(addToken(tokenAddress, symbol, Number(decimals)));
dispatch(loadingTokenParamsFinished());
},
);
return getSymbolAndDecimals(tokenAddress).then(({ symbol, decimals }) => {
dispatch(addToken(tokenAddress, symbol, Number(decimals)));
dispatch(loadingTokenParamsFinished());
});
};
}

Expand Down
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2739,10 +2739,10 @@
human-standard-token-abi "^1.0.2"
safe-event-emitter "^1.0.1"

"@metamask/etherscan-link@^2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@metamask/etherscan-link/-/etherscan-link-2.0.0.tgz#89035736515a39532ba1142d87b9a8c2b4f920f1"
integrity sha512-/YS32hS2UTTxs0KyUmAgaDj1w4dzAvOrT+p4TJtpICeH3E/k51r2FO0Or7WJJI/mpzTqNKgcH5yyS2oCtupGiA==
"@metamask/etherscan-link@^2.1.0":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@metamask/etherscan-link/-/etherscan-link-2.1.0.tgz#c0be8e68445b7b83cf85bcc03a56cdf8e256c973"
integrity sha512-ADuWlTUkFfN2vXlz81Bg/0BA+XRor+CdK1055p6k7H6BLIPoDKn9SBOFld9haQFuR9cKh/JYHcnlSIv5R4fUEw==

"@metamask/forwarder@^1.1.0":
version "1.1.0"
Expand Down

0 comments on commit 0e11818

Please sign in to comment.