diff --git a/src/hooks/useUSDCPrice.ts b/src/hooks/useUSDCPrice.ts index bcfa90f071..03e60d2340 100644 --- a/src/hooks/useUSDCPrice.ts +++ b/src/hooks/useUSDCPrice.ts @@ -1,7 +1,7 @@ import { Currency, CurrencyAmount, Price, Token, TradeType } from '@uniswap/sdk-core' import useActiveWeb3React from 'hooks/useActiveWeb3React' +import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import { useMemo } from 'react' -import { tryParseAmount } from 'state/swap/hooks' import { SupportedChainId } from '../constants/chains' import { DAI_OPTIMISM, USDC, USDC_ARBITRUM, USDC_POLYGON } from '../constants/tokens' @@ -87,7 +87,7 @@ export function useStablecoinAmountFromFiatValue(fiatValue: string | null | unde try { // parse USD string into CurrencyAmount based on stablecoin decimals - return tryParseAmount(parsedForDecimals, stablecoin) + return tryParseCurrencyAmount(parsedForDecimals, stablecoin) } catch (error) { return undefined } diff --git a/src/hooks/useWrapCallback.tsx b/src/hooks/useWrapCallback.tsx index d7425038d1..2210876d07 100644 --- a/src/hooks/useWrapCallback.tsx +++ b/src/hooks/useWrapCallback.tsx @@ -2,10 +2,10 @@ import { Trans } from '@lingui/macro' import { Currency } from '@uniswap/sdk-core' import useActiveWeb3React from 'hooks/useActiveWeb3React' import useNativeCurrency from 'lib/hooks/useNativeCurrency' +import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import { useMemo } from 'react' import { WRAPPED_NATIVE_CURRENCY } from '../constants/tokens' -import { tryParseAmount } from '../state/swap/hooks' import { TransactionType } from '../state/transactions/actions' import { useTransactionAdder } from '../state/transactions/hooks' import { useCurrencyBalance } from '../state/wallet/hooks' @@ -61,7 +61,10 @@ export default function useWrapCallback( const wethContract = useWETHContract() const balance = useCurrencyBalance(account ?? undefined, inputCurrency ?? undefined) // we can always parse the amount typed as the input currency, since wrapping is 1:1 - const inputAmount = useMemo(() => tryParseAmount(typedValue, inputCurrency ?? undefined), [inputCurrency, typedValue]) + const inputAmount = useMemo( + () => tryParseCurrencyAmount(typedValue, inputCurrency ?? undefined), + [inputCurrency, typedValue] + ) const addTransaction = useTransactionAdder() return useMemo(() => { diff --git a/src/lib/utils/tryParseCurrencyAmount.ts b/src/lib/utils/tryParseCurrencyAmount.ts new file mode 100644 index 0000000000..3940bbd612 --- /dev/null +++ b/src/lib/utils/tryParseCurrencyAmount.ts @@ -0,0 +1,26 @@ +import { parseUnits } from '@ethersproject/units' +import { Currency, CurrencyAmount } from '@uniswap/sdk-core' +import JSBI from 'jsbi' + +/** + * Parses a CurrencyAmount from the passed string. + * Returns the CurrencyAmount, or undefined if parsing fails. + */ +export default function tryParseCurrencyAmount( + value?: string, + currency?: T +): CurrencyAmount | undefined { + if (!value || !currency) { + return undefined + } + try { + const typedValueParsed = parseUnits(value, currency.decimals).toString() + if (typedValueParsed !== '0') { + return CurrencyAmount.fromRawAmount(currency, JSBI.BigInt(typedValueParsed)) + } + } catch (error) { + // fails if the user specifies too many decimal places of precision (or maybe exceed max uint?) + console.debug(`Failed to parse input amount: "${value}"`, error) + } + return undefined +} diff --git a/src/pages/CreateProposal/index.tsx b/src/pages/CreateProposal/index.tsx index 2fd7a77e01..f206430669 100644 --- a/src/pages/CreateProposal/index.tsx +++ b/src/pages/CreateProposal/index.tsx @@ -7,6 +7,7 @@ import { BlueCard } from 'components/Card' import { AutoColumn } from 'components/Column' import useActiveWeb3React from 'hooks/useActiveWeb3React' import JSBI from 'jsbi' +import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import { Wrapper } from 'pages/Pool/styleds' import React, { useCallback, useMemo, useState } from 'react' import { @@ -18,7 +19,6 @@ import { useProposalThreshold, useUserVotes, } from 'state/governance/hooks' -import { tryParseAmount } from 'state/swap/hooks' import styled from 'styled-components/macro' import { ExternalLink, ThemedText } from 'theme' @@ -184,7 +184,7 @@ export default function CreateProposal() { if (!createProposalCallback || !proposalAction || !currencyValue.isToken) return - const tokenAmount = tryParseAmount(amountValue, currencyValue) + const tokenAmount = tryParseCurrencyAmount(amountValue, currencyValue) if (!tokenAmount) return createProposalData.targets = [currencyValue.address] diff --git a/src/state/burn/hooks.tsx b/src/state/burn/hooks.tsx index 49aae65c74..e4082f50f9 100644 --- a/src/state/burn/hooks.tsx +++ b/src/state/burn/hooks.tsx @@ -3,13 +3,13 @@ import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core' import { Pair } from '@uniswap/v2-sdk' import useActiveWeb3React from 'hooks/useActiveWeb3React' import JSBI from 'jsbi' +import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import { ReactNode, useCallback } from 'react' import { useAppDispatch, useAppSelector } from 'state/hooks' import { useTotalSupply } from '../../hooks/useTotalSupply' import { useV2Pair } from '../../hooks/useV2Pairs' import { AppState } from '../index' -import { tryParseAmount } from '../swap/hooks' import { useTokenBalances } from '../wallet/hooks' import { Field, typeInput } from './actions' @@ -81,7 +81,7 @@ export function useDerivedBurnInfo( // user specified a specific amount of liquidity tokens else if (independentField === Field.LIQUIDITY) { if (pair?.liquidityToken) { - const independentAmount = tryParseAmount(typedValue, pair.liquidityToken) + const independentAmount = tryParseCurrencyAmount(typedValue, pair.liquidityToken) if (independentAmount && userLiquidity && !independentAmount.greaterThan(userLiquidity)) { percentToRemove = new Percent(independentAmount.quotient, userLiquidity.quotient) } @@ -90,7 +90,7 @@ export function useDerivedBurnInfo( // user specified a specific amount of token a or b else { if (tokens[independentField]) { - const independentAmount = tryParseAmount(typedValue, tokens[independentField]) + const independentAmount = tryParseCurrencyAmount(typedValue, tokens[independentField]) const liquidityValue = liquidityValues[independentField] if (independentAmount && liquidityValue && !independentAmount.greaterThan(liquidityValue)) { percentToRemove = new Percent(independentAmount.quotient, liquidityValue.quotient) diff --git a/src/state/mint/hooks.tsx b/src/state/mint/hooks.tsx index 4ad392cbbd..245c3ac36d 100644 --- a/src/state/mint/hooks.tsx +++ b/src/state/mint/hooks.tsx @@ -3,13 +3,13 @@ import { Currency, CurrencyAmount, Percent, Price, Token } from '@uniswap/sdk-co import { Pair } from '@uniswap/v2-sdk' import useActiveWeb3React from 'hooks/useActiveWeb3React' import JSBI from 'jsbi' +import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import { ReactNode, useCallback, useMemo } from 'react' import { useAppDispatch, useAppSelector } from 'state/hooks' import { useTotalSupply } from '../../hooks/useTotalSupply' import { PairState, useV2Pair } from '../../hooks/useV2Pairs' import { AppState } from '../index' -import { tryParseAmount } from '../swap/hooks' import { useCurrencyBalances } from '../wallet/hooks' import { Field, typeInput } from './actions' @@ -101,14 +101,14 @@ export function useDerivedMintInfo( } // amounts - const independentAmount: CurrencyAmount | undefined = tryParseAmount( + const independentAmount: CurrencyAmount | undefined = tryParseCurrencyAmount( typedValue, currencies[independentField] ) const dependentAmount: CurrencyAmount | undefined = useMemo(() => { if (noLiquidity) { if (otherTypedValue && currencies[dependentField]) { - return tryParseAmount(otherTypedValue, currencies[dependentField]) + return tryParseCurrencyAmount(otherTypedValue, currencies[dependentField]) } return undefined } else if (independentAmount) { diff --git a/src/state/mint/v3/hooks.tsx b/src/state/mint/v3/hooks.tsx index 1011ee3a5d..2caf0ff750 100644 --- a/src/state/mint/v3/hooks.tsx +++ b/src/state/mint/v3/hooks.tsx @@ -14,6 +14,7 @@ import { import useActiveWeb3React from 'hooks/useActiveWeb3React' import { usePool } from 'hooks/usePools' import JSBI from 'jsbi' +import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import { ReactNode, useCallback, useMemo } from 'react' import { useAppDispatch, useAppSelector } from 'state/hooks' import { getTickToPrice } from 'utils/getTickToPrice' @@ -21,7 +22,6 @@ import { getTickToPrice } from 'utils/getTickToPrice' import { BIG_INT_ZERO } from '../../../constants/misc' import { PoolState } from '../../../hooks/usePools' import { AppState } from '../../index' -import { tryParseAmount } from '../../swap/hooks' import { useCurrencyBalances } from '../../wallet/hooks' import { Bound, @@ -170,9 +170,9 @@ export function useV3DerivedMintInfo( const price: Price | undefined = useMemo(() => { // if no liquidity use typed value if (noLiquidity) { - const parsedQuoteAmount = tryParseAmount(startPriceTypedValue, invertPrice ? token0 : token1) + const parsedQuoteAmount = tryParseCurrencyAmount(startPriceTypedValue, invertPrice ? token0 : token1) if (parsedQuoteAmount && token0 && token1) { - const baseAmount = tryParseAmount('1', invertPrice ? token1 : token0) + const baseAmount = tryParseCurrencyAmount('1', invertPrice ? token1 : token0) const price = baseAmount && parsedQuoteAmount ? new Price( @@ -294,7 +294,7 @@ export function useV3DerivedMintInfo( ) // amounts - const independentAmount: CurrencyAmount | undefined = tryParseAmount( + const independentAmount: CurrencyAmount | undefined = tryParseCurrencyAmount( typedValue, currencies[independentField] ) diff --git a/src/state/stake/hooks.tsx b/src/state/stake/hooks.tsx index b18a1cf6a9..0b89e70cd0 100644 --- a/src/state/stake/hooks.tsx +++ b/src/state/stake/hooks.tsx @@ -7,10 +7,10 @@ import useActiveWeb3React from 'hooks/useActiveWeb3React' import useCurrentBlockTimestamp from 'hooks/useCurrentBlockTimestamp' import JSBI from 'jsbi' import { NEVER_RELOAD, useMultipleContractSingleData } from 'lib/hooks/multicall' +import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import { ReactNode, useMemo } from 'react' import { DAI, UNI, USDC, USDT, WBTC, WRAPPED_NATIVE_CURRENCY } from '../../constants/tokens' -import { tryParseAmount } from '../swap/hooks' const STAKING_REWARDS_INTERFACE = new Interface(STAKING_REWARDS_ABI) @@ -254,7 +254,7 @@ export function useDerivedStakeInfo( } { const { account } = useActiveWeb3React() - const parsedInput: CurrencyAmount | undefined = tryParseAmount(typedValue, stakingToken) + const parsedInput: CurrencyAmount | undefined = tryParseCurrencyAmount(typedValue, stakingToken) const parsedAmount = parsedInput && userLiquidityUnstaked && JSBI.lessThanOrEqual(parsedInput.quotient, userLiquidityUnstaked.quotient) diff --git a/src/state/swap/hooks.tsx b/src/state/swap/hooks.tsx index 0542933959..8c3c61fea1 100644 --- a/src/state/swap/hooks.tsx +++ b/src/state/swap/hooks.tsx @@ -1,9 +1,8 @@ -import { parseUnits } from '@ethersproject/units' import { Trans } from '@lingui/macro' import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core' import useActiveWeb3React from 'hooks/useActiveWeb3React' import { useBestTrade } from 'hooks/useBestTrade' -import JSBI from 'jsbi' +import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import { ParsedQs } from 'qs' import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react' import { useAppDispatch, useAppSelector } from 'state/hooks' @@ -68,24 +67,6 @@ export function useSwapActionHandlers(): { } } -// try to parse a user entered amount for a given token -export function tryParseAmount(value?: string, currency?: T): CurrencyAmount | undefined { - if (!value || !currency) { - return undefined - } - try { - const typedValueParsed = parseUnits(value, currency.decimals).toString() - if (typedValueParsed !== '0') { - return CurrencyAmount.fromRawAmount(currency, JSBI.BigInt(typedValueParsed)) - } - } catch (error) { - // should fail if the user specifies too many decimal places of precision (or maybe exceed max uint?) - console.debug(`Failed to parse input amount: "${value}"`, error) - } - // necessary for all paths to return a value - return undefined -} - const BAD_RECIPIENT_ADDRESSES: { [address: string]: true } = { '0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f': true, // v2 factory '0xf164fC0Ec4E93095b804a4795bBe1e041497b92a': true, // v2 router 01 @@ -126,7 +107,7 @@ export function useDerivedSwapInfo(): { const isExactIn: boolean = independentField === Field.INPUT const parsedAmount = useMemo( - () => tryParseAmount(typedValue, (isExactIn ? inputCurrency : outputCurrency) ?? undefined), + () => tryParseCurrencyAmount(typedValue, (isExactIn ? inputCurrency : outputCurrency) ?? undefined), [inputCurrency, isExactIn, outputCurrency, typedValue] )