diff --git a/src/constants/tokens.ts b/src/constants/tokens.ts index c36e4f6943..4b79d9e8de 100644 --- a/src/constants/tokens.ts +++ b/src/constants/tokens.ts @@ -6,6 +6,11 @@ import { SupportedChainId } from './chains' export const NATIVE_CHAIN_ID = 'NATIVE' +// When decimals are not specified for an ERC20 token +// use default ERC20 token decimals as specified here: +// https://docs.openzeppelin.com/contracts/3.x/erc20 +export const DEFAULT_ERC20_DECIMALS = 18 + export const USDC_MAINNET = new Token( SupportedChainId.MAINNET, '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', diff --git a/src/lib/hooks/useCurrency.ts b/src/lib/hooks/useCurrency.ts index a49b05b4ae..b805146d9b 100644 --- a/src/lib/hooks/useCurrency.ts +++ b/src/lib/hooks/useCurrency.ts @@ -12,6 +12,7 @@ import useNativeCurrency from 'lib/hooks/useNativeCurrency' import { useEffect, useMemo, useState } from 'react' import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo' +import { DEFAULT_ERC20_DECIMALS } from '../../constants/tokens' import { TOKEN_SHORTHANDS } from '../../constants/tokens' import { getContract, isAddress } from '../../utils' import { supportedChainId } from '../../utils/supportedChainId' @@ -121,7 +122,8 @@ export function useTokenFromActiveNetwork(tokenAddress: string | undefined): Tok () => decimals.loading || symbol.loading || tokenName.loading, [decimals.loading, symbol.loading, tokenName.loading] ) - const parsedDecimals = useMemo(() => decimals.result?.[0], [decimals.result]) + const parsedDecimals = useMemo(() => decimals?.result?.[0] ?? DEFAULT_ERC20_DECIMALS, [decimals.result]) + const parsedSymbol = useMemo( () => parseStringOrBytes32(symbol.result?.[0], symbolBytes32.result?.[0], 'UNKNOWN'), [symbol.result, symbolBytes32.result] @@ -134,9 +136,7 @@ export function useTokenFromActiveNetwork(tokenAddress: string | undefined): Tok return useMemo(() => { // If the token is on another chain, we cannot fetch it on-chain, and it is invalid. if (typeof tokenAddress !== 'string' || !isSupportedChain(chainId) || !formattedAddress) return undefined - if (isLoading || !chainId) return null - if (!parsedDecimals) return undefined return new Token(chainId, formattedAddress, parsedDecimals, parsedSymbol, parsedName) }, [chainId, tokenAddress, formattedAddress, isLoading, parsedDecimals, parsedSymbol, parsedName]) @@ -152,7 +152,6 @@ type TokenMap = { [address: string]: Token } export function useTokenFromMapOrNetwork(tokens: TokenMap, tokenAddress?: string | null): Token | null | undefined { const address = isAddress(tokenAddress) const token: Token | undefined = address ? tokens[address] : undefined - const tokenFromNetwork = useTokenFromActiveNetwork(token ? undefined : address ? address : undefined) return tokenFromNetwork ?? token diff --git a/src/utils/index.ts b/src/utils/index.ts index d289758a48..98165c9474 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -8,7 +8,9 @@ import { ChainTokenMap } from 'lib/hooks/useTokenList/utils' // returns the checksummed address if the address is valid, otherwise returns false export function isAddress(value: any): string | false { try { - return getAddress(value) + // Alphabetical letters must be made lowercase for getAddress to work. + // See documentation here: https://docs.ethers.io/v5/api/utils/address/ + return getAddress(value.toLowerCase()) } catch { return false }