From de3a33dfcbc53d5a6a0e12422fc12a1fcd440fd5 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 5 Apr 2022 10:45:21 -0700 Subject: [PATCH] fix: stale data edge cases (#3657) * fix: stale chain block * chore: simplify atom usage * fix: support single-token chain * fix: avoid extra rpcs * chore: rename isDisabled * fix: simplify useUSDCPrice * fix: simplify useComputeSwapInfo * chore: include type * fix: guard hasAmounts --- src/hooks/useAutoSlippageTolerance.ts | 2 +- src/lib/components/Swap/index.tsx | 24 +++++-------- src/lib/hooks/swap/useSwapInfo.tsx | 7 ++-- src/lib/hooks/useBlockNumber.ts | 51 +++++++++++++-------------- src/lib/state/multicall.tsx | 2 +- 5 files changed, 40 insertions(+), 46 deletions(-) diff --git a/src/hooks/useAutoSlippageTolerance.ts b/src/hooks/useAutoSlippageTolerance.ts index 07696d8b72..c0005acd05 100644 --- a/src/hooks/useAutoSlippageTolerance.ts +++ b/src/hooks/useAutoSlippageTolerance.ts @@ -41,7 +41,7 @@ export default function useAutoSlippageTolerance( const gasEstimate = guesstimateGas(trade) const nativeCurrency = useNativeCurrency() - const nativeCurrencyPrice = useUSDCPrice(nativeCurrency ?? undefined) + const nativeCurrencyPrice = useUSDCPrice((trade && nativeCurrency) ?? undefined) return useMemo(() => { if (!trade || onL2) return ONE_TENTHS_PERCENT diff --git a/src/lib/components/Swap/index.tsx b/src/lib/components/Swap/index.tsx index f854bafa9a..4fed15874b 100644 --- a/src/lib/components/Swap/index.tsx +++ b/src/lib/components/Swap/index.tsx @@ -8,10 +8,10 @@ import { usePendingTransactions } from 'lib/hooks/transactions' import useActiveWeb3React from 'lib/hooks/useActiveWeb3React' import useHasFocus from 'lib/hooks/useHasFocus' import useOnSupportedNetwork from 'lib/hooks/useOnSupportedNetwork' -import useTokenList, { useSyncTokenList } from 'lib/hooks/useTokenList' +import { useSyncTokenList } from 'lib/hooks/useTokenList' import { displayTxHashAtom } from 'lib/state/swap' import { SwapTransactionInfo, Transaction, TransactionType, WrapTransactionInfo } from 'lib/state/transactions' -import { useMemo, useState } from 'react' +import { useState } from 'react' import Dialog from '../Dialog' import Header from '../Header' @@ -63,32 +63,26 @@ export default function Swap(props: SwapProps) { const pendingTxs = usePendingTransactions() const displayTx = getTransactionFromMap(pendingTxs, displayTxHash) - const tokenList = useTokenList() const onSupportedNetwork = useOnSupportedNetwork() - const isSwapSupported = useMemo( - () => Boolean(active && onSupportedNetwork && tokenList?.length), - [active, onSupportedNetwork, tokenList?.length] - ) + const isDisabled = !(active && onSupportedNetwork) const focused = useHasFocus(wrapper) - const isInteractive = Boolean(active && onSupportedNetwork) - return ( <> - +
Swap}> {active && } - +
- - - + + + - +
diff --git a/src/lib/hooks/swap/useSwapInfo.tsx b/src/lib/hooks/swap/useSwapInfo.tsx index 6872e62db9..017a2530c7 100644 --- a/src/lib/hooks/swap/useSwapInfo.tsx +++ b/src/lib/hooks/swap/useSwapInfo.tsx @@ -43,10 +43,11 @@ function useComputeSwapInfo(): SwapInfo { () => tryParseCurrencyAmount(amount, (isExactIn ? currencyIn : currencyOut) ?? undefined), [amount, isExactIn, currencyIn, currencyOut] ) + const hasAmounts = currencyIn && currencyOut && parsedAmount const trade = useBestTrade( isExactIn ? TradeType.EXACT_INPUT : TradeType.EXACT_OUTPUT, - parsedAmount, - (isExactIn ? currencyOut : currencyIn) ?? undefined + hasAmounts ? parsedAmount : undefined, + hasAmounts ? (isExactIn ? currencyOut : currencyIn) : undefined ) const amountIn = useMemo( @@ -111,7 +112,7 @@ const swapInfoAtom = atom({ export function SwapInfoUpdater() { const setSwapInfo = useUpdateAtom(swapInfoAtom) const swapInfo = useComputeSwapInfo() - useEffect(() => setSwapInfo(swapInfo), [swapInfo, setSwapInfo]) + useEffect(() => setSwapInfo(swapInfo), [setSwapInfo, swapInfo]) return null } diff --git a/src/lib/hooks/useBlockNumber.ts b/src/lib/hooks/useBlockNumber.ts index 751f2cfc89..76aa2e713d 100644 --- a/src/lib/hooks/useBlockNumber.ts +++ b/src/lib/hooks/useBlockNumber.ts @@ -1,32 +1,38 @@ import useActiveWeb3React from 'hooks/useActiveWeb3React' -import useDebounce from 'hooks/useDebounce' import useIsWindowVisible from 'hooks/useIsWindowVisible' import { atom } from 'jotai' import { useAtomValue, useUpdateAtom } from 'jotai/utils' -import { useCallback, useEffect, useState } from 'react' +import { useCallback, useEffect } from 'react' -function useBlock() { +interface ChainBlock { + chainId?: number + block?: number +} +const chainBlockAtom = atom({}) + +function useUpdateChainBlock() { const { chainId, library } = useActiveWeb3React() const windowVisible = useIsWindowVisible() - const [state, setState] = useState<{ chainId?: number; block?: number }>({ chainId }) + const setChainBlock = useUpdateAtom(chainBlockAtom) const onBlock = useCallback( (block: number) => { - setState((state) => { - if (state.chainId === chainId) { - if (typeof state.block !== 'number') return { chainId, block } - return { chainId, block: Math.max(block, state.block) } + setChainBlock((chainBlock) => { + if (chainBlock.chainId === chainId) { + if (chainBlock.block === block) return chainBlock + if (typeof chainBlock.block !== 'number') return { chainId, block } + return { chainId, block: Math.max(block, chainBlock.block) } } - return state + return chainBlock }) }, - [chainId] + [chainId, setChainBlock] ) useEffect(() => { if (library && chainId && windowVisible) { // If chainId hasn't changed, don't clear the block. This prevents re-fetching still valid data. - setState((state) => (state.chainId === chainId ? state : { chainId })) + setChainBlock((chainBlock) => (chainBlock.chainId === chainId ? chainBlock : { chainId })) library .getBlockNumber() @@ -41,30 +47,23 @@ function useBlock() { } } return undefined - }, [chainId, library, onBlock, windowVisible]) - - const debouncedBlock = useDebounce(state.block, 100) - return state.block ? debouncedBlock : undefined + }, [chainId, library, onBlock, setChainBlock, windowVisible]) } -const blockAtom = atom(undefined) - export function BlockUpdater() { - const setBlock = useUpdateAtom(blockAtom) - const block = useBlock() - useEffect(() => { - setBlock(block) - }, [block, setBlock]) + useUpdateChainBlock() return null } /** Requires that BlockUpdater be installed in the DOM tree. */ export default function useBlockNumber(): number | undefined { - const { chainId } = useActiveWeb3React() - const block = useAtomValue(blockAtom) - return chainId ? block : undefined + const { chainId: activeChainId } = useActiveWeb3React() + const { chainId, block } = useAtomValue(chainBlockAtom) + return activeChainId === chainId ? block : undefined } export function useFastForwardBlockNumber(): (block: number) => void { - return useUpdateAtom(blockAtom) + const { chainId } = useActiveWeb3React() + const setChainBlock = useUpdateAtom(chainBlockAtom) + return useCallback((block: number) => setChainBlock({ chainId, block }), [chainId, setChainBlock]) } diff --git a/src/lib/state/multicall.tsx b/src/lib/state/multicall.tsx index 9e52d51e82..24522fe605 100644 --- a/src/lib/state/multicall.tsx +++ b/src/lib/state/multicall.tsx @@ -11,8 +11,8 @@ export const store = createStore(reducer) export default multicall export function MulticallUpdater() { - const latestBlockNumber = useBlockNumber() const { chainId } = useActiveWeb3React() + const latestBlockNumber = useBlockNumber() const contract = useInterfaceMulticall() return }