Commit 33c24a3f authored by Zach Pomerantz's avatar Zach Pomerantz Committed by GitHub

fix: trade displays (#3594)

* fix: show syncing over insufficient balance

* fix: mv anti-janking up a level

* feat: add error caption for completeness

* chore: clarify naming
parent 9ef2b3a1
......@@ -48,6 +48,10 @@ export function InsufficientLiquidity() {
return <Caption caption={<Trans>Insufficient liquidity in the pool for your trade</Trans>} />
}
export function Error() {
return <Caption caption={<Trans>Error fetching trade</Trans>} />
}
export function Empty() {
return <Caption icon={Info} caption={<Trans>Enter an amount</Trans>} />
}
......
......@@ -25,7 +25,6 @@ export default memo(function Toolbar({ disabled }: { disabled?: boolean }) {
trade: { trade, state },
impact,
} = useSwapInfo()
const isRouteLoading = state === TradeState.SYNCING || state === TradeState.LOADING
const isAmountPopulated = useIsAmountPopulated()
const { type: wrapType } = useWrapCallback()
const caption = useMemo(() => {
......@@ -38,22 +37,23 @@ export default memo(function Toolbar({ disabled }: { disabled?: boolean }) {
}
if (inputCurrency && outputCurrency && isAmountPopulated) {
if (state === TradeState.SYNCING || state === TradeState.LOADING) {
return <Caption.LoadingTrade />
}
if (inputBalance && inputAmount?.greaterThan(inputBalance)) {
return <Caption.InsufficientBalance currency={inputCurrency} />
}
if (wrapType !== WrapType.NONE) {
return <Caption.WrapCurrency inputCurrency={inputCurrency} outputCurrency={outputCurrency} />
}
if (isRouteLoading) {
return <Caption.LoadingTrade />
if (state === TradeState.NO_ROUTE_FOUND || (trade && !trade.swaps)) {
return <Caption.InsufficientLiquidity />
}
if (trade?.inputAmount && trade.outputAmount) {
return <Caption.Trade trade={trade} outputUSDC={outputUSDC} impact={impact} />
}
if (trade) {
if (!trade.swaps) {
return <Caption.InsufficientLiquidity />
}
if (trade.inputAmount && trade.outputAmount) {
return <Caption.Trade trade={trade} outputUSDC={outputUSDC} impact={impact} />
}
if (state === TradeState.INVALID) {
return <Caption.Error />
}
}
......@@ -66,9 +66,9 @@ export default memo(function Toolbar({ disabled }: { disabled?: boolean }) {
inputBalance,
inputCurrency,
isAmountPopulated,
isRouteLoading,
outputCurrency,
outputUSDC,
state,
trade,
wrapType,
])
......
......@@ -4,7 +4,6 @@ import { Protocol } from '@uniswap/router-sdk'
import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
import { ChainId } from '@uniswap/smart-order-router'
import useDebounce from 'hooks/useDebounce'
import useLast from 'hooks/useLast'
import { useStablecoinAmountFromFiatValue } from 'hooks/useUSDCPrice'
import { useCallback, useMemo } from 'react'
import { GetQuoteResult, InterfaceTrade, TradeState } from 'state/routing/types'
......@@ -111,29 +110,19 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr
}
return
}, [gasUseEstimateUSD, route, tradeType])
const lastTrade = useLast(trade, Boolean) ?? undefined
return useMemo(() => {
if (!currencyIn || !currencyOut) {
return { state: TradeState.INVALID, trade: undefined }
}
// Returns the last trade state while syncing/loading to avoid jank from clearing the last trade while loading.
if (!trade && !error) {
// Dont return last trade if currencies dont match.
const isStale =
(currencyIn && !lastTrade?.inputAmount?.currency.equals(currencyIn)) ||
(currencyOut && !lastTrade?.outputAmount?.currency.equals(currencyOut))
if (isStale) {
if (isDebouncing) {
return { state: TradeState.SYNCING, trade: undefined }
} else if (!isValid) {
return { state: TradeState.LOADING, trade: undefined }
} else if (isDebouncing) {
return { state: TradeState.SYNCING, trade: lastTrade }
}
}
if (!isValid && !error) {
return { state: TradeState.LOADING, trade: lastTrade }
}
let otherAmount = undefined
if (quoteResult) {
......@@ -155,5 +144,5 @@ export default function useClientSideSmartOrderRouterTrade<TTradeType extends Tr
return { state: TradeState.VALID, trade }
}
return { state: TradeState.INVALID, trade: undefined }
}, [currencyIn, currencyOut, trade, error, isValid, quoteResult, route, isDebouncing, lastTrade, tradeType])
}, [currencyIn, currencyOut, trade, error, isValid, quoteResult, route, isDebouncing, tradeType])
}
import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
import { useClientSideV3Trade } from 'hooks/useClientSideV3Trade'
import useLast from 'hooks/useLast'
import { useMemo } from 'react'
import { InterfaceTrade, TradeState } from 'state/routing/types'
import useClientSideSmartOrderRouterTrade from '../routing/useClientSideSmartOrderRouterTrade'
......@@ -18,15 +20,38 @@ export function useBestTrade(
state: TradeState
trade: InterfaceTrade<Currency, Currency, TradeType> | undefined
} {
const clientSORTrade = useClientSideSmartOrderRouterTrade(tradeType, amountSpecified, otherCurrency)
const clientSORTradeObject = useClientSideSmartOrderRouterTrade(tradeType, amountSpecified, otherCurrency)
// Use a simple client side logic as backup if SOR is not available.
const useFallback = clientSORTrade.state === TradeState.NO_ROUTE_FOUND || clientSORTrade.state === TradeState.INVALID
const fallbackTrade = useClientSideV3Trade(
const useFallback =
clientSORTradeObject.state === TradeState.NO_ROUTE_FOUND || clientSORTradeObject.state === TradeState.INVALID
const fallbackTradeObject = useClientSideV3Trade(
tradeType,
useFallback ? amountSpecified : undefined,
useFallback ? otherCurrency : undefined
)
return useFallback ? fallbackTrade : clientSORTrade
const tradeObject = useFallback ? fallbackTradeObject : clientSORTradeObject
const lastTrade = useLast(tradeObject.trade, Boolean) ?? undefined
// Return the last trade while syncing/loading to avoid jank from clearing the last trade while loading.
// If the trade is unsettled and not stale, return the last trade as a placeholder during settling.
return useMemo(() => {
const { state, trade } = tradeObject
// If the trade is in a settled state, return it.
if ((state !== TradeState.LOADING && state !== TradeState.SYNCING) || trade) return tradeObject
const [currencyIn, currencyOut] =
tradeType === TradeType.EXACT_INPUT
? [amountSpecified?.currency, otherCurrency]
: [otherCurrency, amountSpecified?.currency]
// If the trade currencies have switched, consider it stale - do not return the last trade.
const isStale =
(currencyIn && !lastTrade?.inputAmount?.currency.equals(currencyIn)) ||
(currencyOut && !lastTrade?.outputAmount?.currency.equals(currencyOut))
if (isStale) return tradeObject
return { state, trade: lastTrade }
}, [amountSpecified?.currency, lastTrade, otherCurrency, tradeObject, tradeType])
}
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