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
This commit is contained in:
parent
99a084f230
commit
de3a33dfcb
@ -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
|
||||
|
@ -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 (
|
||||
<>
|
||||
<SwapPropValidator {...props} />
|
||||
<Updaters {...props} disabled={!isSwapSupported} />
|
||||
<Updaters {...props} disabled={isDisabled} />
|
||||
<Header title={<Trans>Swap</Trans>}>
|
||||
{active && <Wallet disabled={!account} onClick={props.onConnectWallet} />}
|
||||
<Settings disabled={!isInteractive} />
|
||||
<Settings disabled={isDisabled} />
|
||||
</Header>
|
||||
<div ref={setWrapper}>
|
||||
<BoundaryProvider value={wrapper}>
|
||||
<Input disabled={!isInteractive} focused={focused} />
|
||||
<ReverseButton disabled={!isInteractive} />
|
||||
<Output disabled={!isInteractive} focused={focused}>
|
||||
<Input disabled={isDisabled} focused={focused} />
|
||||
<ReverseButton disabled={isDisabled} />
|
||||
<Output disabled={isDisabled} focused={focused}>
|
||||
<Toolbar disabled={!active} />
|
||||
<SwapButton disabled={!isSwapSupported} />
|
||||
<SwapButton disabled={isDisabled} />
|
||||
</Output>
|
||||
</BoundaryProvider>
|
||||
</div>
|
||||
|
@ -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<SwapInfo>({
|
||||
export function SwapInfoUpdater() {
|
||||
const setSwapInfo = useUpdateAtom(swapInfoAtom)
|
||||
const swapInfo = useComputeSwapInfo()
|
||||
useEffect(() => setSwapInfo(swapInfo), [swapInfo, setSwapInfo])
|
||||
useEffect(() => setSwapInfo(swapInfo), [setSwapInfo, swapInfo])
|
||||
return null
|
||||
}
|
||||
|
||||
|
@ -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<ChainBlock>({})
|
||||
|
||||
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<number | undefined>(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])
|
||||
}
|
||||
|
@ -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 <multicall.Updater chainId={chainId} latestBlockNumber={latestBlockNumber} contract={contract} />
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user