Commit e1abd81a authored by Ian Lapham's avatar Ian Lapham Committed by GitHub

fix: add syncing state to trade loading (#3545)

* add syncing state to trade loading

* remove log statement

* update loading state

* update useLast trade logic

* nit fixes
parent 7d965786
...@@ -100,7 +100,11 @@ export async function getClientSideQuote( ...@@ -100,7 +100,11 @@ export async function getClientSideQuote(
) )
} }
export function useFreshQuote(quoteResult: GetQuoteResult | undefined, maxBlockAge = 10): GetQuoteResult | undefined { /** Used to keep quotes up to date given a certain block age. Returns undefined if past limit. */
export function useFilterFreshQuote(
quoteResult: GetQuoteResult | undefined,
maxBlockAge = 10
): GetQuoteResult | undefined {
const block = useBlockNumber() const block = useBlockNumber()
if (!block || !quoteResult) return undefined if (!block || !quoteResult) return undefined
if (block - (Number(quoteResult.blockNumber) || 0) > maxBlockAge) return undefined if (block - (Number(quoteResult.blockNumber) || 0) > maxBlockAge) return undefined
......
...@@ -2,6 +2,7 @@ import { Protocol } from '@uniswap/router-sdk' ...@@ -2,6 +2,7 @@ import { Protocol } from '@uniswap/router-sdk'
import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
import { ChainId } from '@uniswap/smart-order-router' import { ChainId } from '@uniswap/smart-order-router'
import useDebounce from 'hooks/useDebounce' import useDebounce from 'hooks/useDebounce'
import useLast from 'hooks/useLast'
import { useStablecoinAmountFromFiatValue } from 'hooks/useUSDCPrice' import { useStablecoinAmountFromFiatValue } from 'hooks/useUSDCPrice'
import { useCallback, useMemo } from 'react' import { useCallback, useMemo } from 'react'
import { GetQuoteResult, InterfaceTrade, TradeState } from 'state/routing/types' import { GetQuoteResult, InterfaceTrade, TradeState } from 'state/routing/types'
...@@ -10,7 +11,7 @@ import { computeRoutes, transformRoutesToTrade } from 'state/routing/utils' ...@@ -10,7 +11,7 @@ import { computeRoutes, transformRoutesToTrade } from 'state/routing/utils'
import useWrapCallback, { WrapType } from '../swap/useWrapCallback' import useWrapCallback, { WrapType } from '../swap/useWrapCallback'
import useActiveWeb3React from '../useActiveWeb3React' import useActiveWeb3React from '../useActiveWeb3React'
import usePoll from '../usePoll' import usePoll from '../usePoll'
import { getClientSideQuote, useFreshQuote } from './clientSideSmartOrderRouter' import { getClientSideQuote, useFilterFreshQuote } from './clientSideSmartOrderRouter'
import { useRoutingAPIArguments } from './useRoutingAPIArguments' import { useRoutingAPIArguments } from './useRoutingAPIArguments'
/** /**
...@@ -78,17 +79,22 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr ...@@ -78,17 +79,22 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr
return { error: true } return { error: true }
} }
}, [config, params, queryArgs, wrapType]) }, [config, params, queryArgs, wrapType])
const { data, error } = usePoll(getQuoteResult, JSON.stringify(queryArgs)) ?? { const { data, error } = usePoll(getQuoteResult, JSON.stringify(queryArgs)) ?? {
error: undefined, error: undefined,
} }
const quoteResult = useFreshQuote(data)
const quoteResult = useFilterFreshQuote(data)
const isLoading = !quoteResult
const route = useMemo( const route = useMemo(
() => computeRoutes(currencyIn, currencyOut, tradeType, quoteResult), () => computeRoutes(currencyIn, currencyOut, tradeType, quoteResult),
[currencyIn, currencyOut, quoteResult, tradeType] [currencyIn, currencyOut, quoteResult, tradeType]
) )
const gasUseEstimateUSD = useStablecoinAmountFromFiatValue(quoteResult?.gasUseEstimateUSD) ?? null const gasUseEstimateUSD = useStablecoinAmountFromFiatValue(quoteResult?.gasUseEstimateUSD) ?? null
const trade = useMemo(() => { const trade =
useLast(
useMemo(() => {
if (route) { if (route) {
try { try {
return route && transformRoutesToTrade(route, tradeType, gasUseEstimateUSD) return route && transformRoutesToTrade(route, tradeType, gasUseEstimateUSD)
...@@ -97,7 +103,14 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr ...@@ -97,7 +103,14 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr
} }
} }
return return
}, [gasUseEstimateUSD, route, tradeType]) }, [gasUseEstimateUSD, route, tradeType]),
Boolean
) ?? undefined
// Dont return old trade if currencies dont match.
const isStale =
(currencyIn && !trade?.inputAmount?.currency.equals(currencyIn)) ||
(currencyOut && !trade?.outputAmount?.currency.equals(currencyOut))
return useMemo(() => { return useMemo(() => {
if (!currencyIn || !currencyOut) { if (!currencyIn || !currencyOut) {
...@@ -106,9 +119,11 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr ...@@ -106,9 +119,11 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr
// Returns the last trade state while syncing/loading to avoid jank from clearing the last trade while loading. // Returns the last trade state while syncing/loading to avoid jank from clearing the last trade while loading.
if (!error) { if (!error) {
if (isDebouncing) { if (isStale) {
return { state: TradeState.LOADING, trade: undefined }
} else if (isDebouncing) {
return { state: TradeState.SYNCING, trade } return { state: TradeState.SYNCING, trade }
} else if (!quoteResult) { } else if (isLoading) {
return { state: TradeState.LOADING, trade } return { state: TradeState.LOADING, trade }
} }
} }
...@@ -133,5 +148,17 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr ...@@ -133,5 +148,17 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr
return { state: TradeState.VALID, trade } return { state: TradeState.VALID, trade }
} }
return { state: TradeState.INVALID, trade: undefined } return { state: TradeState.INVALID, trade: undefined }
}, [currencyIn, currencyOut, quoteResult, error, route, queryArgs, trade, isDebouncing, tradeType]) }, [
currencyIn,
currencyOut,
error,
quoteResult,
route,
queryArgs,
trade,
isStale,
isDebouncing,
isLoading,
tradeType,
])
} }
...@@ -2,7 +2,7 @@ import { skipToken } from '@reduxjs/toolkit/query/react' ...@@ -2,7 +2,7 @@ import { skipToken } from '@reduxjs/toolkit/query/react'
import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
import { IMetric, MetricLoggerUnit, setGlobalMetric } from '@uniswap/smart-order-router' import { IMetric, MetricLoggerUnit, setGlobalMetric } from '@uniswap/smart-order-router'
import { useStablecoinAmountFromFiatValue } from 'hooks/useUSDCPrice' import { useStablecoinAmountFromFiatValue } from 'hooks/useUSDCPrice'
import { useFreshQuote } from 'lib/hooks/routing/clientSideSmartOrderRouter' import { useFilterFreshQuote } from 'lib/hooks/routing/clientSideSmartOrderRouter'
import { useRoutingAPIArguments } from 'lib/hooks/routing/useRoutingAPIArguments' import { useRoutingAPIArguments } from 'lib/hooks/routing/useRoutingAPIArguments'
import ms from 'ms.macro' import ms from 'ms.macro'
import { useMemo } from 'react' import { useMemo } from 'react'
...@@ -50,7 +50,7 @@ export function useRoutingAPITrade<TTradeType extends TradeType>( ...@@ -50,7 +50,7 @@ export function useRoutingAPITrade<TTradeType extends TradeType>(
refetchOnFocus: true, refetchOnFocus: true,
}) })
const quoteResult: GetQuoteResult | undefined = useFreshQuote(data) const quoteResult: GetQuoteResult | undefined = useFilterFreshQuote(data)
const route = useMemo( const route = useMemo(
() => computeRoutes(currencyIn, currencyOut, tradeType, quoteResult), () => computeRoutes(currencyIn, currencyOut, tradeType, quoteResult),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment