fix: Remove double client side quoting (#7121)
* remove double client side quoting * remove additional file * remove file * remove file * MOVE YET ANOTHER FILE * remove unused tokens * fix export * remove unused token constant and swap out for wbtc
This commit is contained in:
parent
b98e62cac8
commit
cc52da9fc4
@ -2,11 +2,9 @@
|
||||
import { ChainId, Currency, Token } from '@uniswap/sdk-core'
|
||||
|
||||
import {
|
||||
AMPL,
|
||||
ARB,
|
||||
BTC_BSC,
|
||||
BUSD_BSC,
|
||||
CAKE_BSC,
|
||||
CEUR_CELO,
|
||||
CEUR_CELO_ALFAJORES,
|
||||
CMC02_CELO,
|
||||
@ -19,21 +17,10 @@ import {
|
||||
DAI_OPTIMISM,
|
||||
DAI_POLYGON,
|
||||
ETH_BSC,
|
||||
ETH2X_FLI,
|
||||
FEI,
|
||||
FRAX,
|
||||
FRAX_BSC,
|
||||
FXS,
|
||||
MATIC_BSC,
|
||||
nativeOnChain,
|
||||
OP,
|
||||
PORTAL_ETH_CELO,
|
||||
PORTAL_USDC_CELO,
|
||||
renBTC,
|
||||
rETH2,
|
||||
sETH2,
|
||||
SWISE,
|
||||
TRIBE,
|
||||
USDC_ARBITRUM,
|
||||
USDC_ARBITRUM_GOERLI,
|
||||
USDC_AVALANCHE,
|
||||
@ -72,66 +59,6 @@ const WRAPPED_NATIVE_CURRENCIES_ONLY: ChainTokenList = Object.fromEntries(
|
||||
.filter(Boolean)
|
||||
)
|
||||
|
||||
// used to construct intermediary pairs for trading
|
||||
export const BASES_TO_CHECK_TRADES_AGAINST: ChainTokenList = {
|
||||
...WRAPPED_NATIVE_CURRENCIES_ONLY,
|
||||
[ChainId.MAINNET]: [...WRAPPED_NATIVE_CURRENCIES_ONLY[ChainId.MAINNET], DAI, USDC_MAINNET, USDT, WBTC],
|
||||
[ChainId.OPTIMISM]: [...WRAPPED_NATIVE_CURRENCIES_ONLY[ChainId.OPTIMISM], DAI_OPTIMISM, USDT_OPTIMISM, WBTC_OPTIMISM],
|
||||
[ChainId.ARBITRUM_ONE]: [
|
||||
...WRAPPED_NATIVE_CURRENCIES_ONLY[ChainId.ARBITRUM_ONE],
|
||||
DAI_ARBITRUM_ONE,
|
||||
USDT_ARBITRUM_ONE,
|
||||
WBTC_ARBITRUM_ONE,
|
||||
],
|
||||
[ChainId.POLYGON]: [
|
||||
...WRAPPED_NATIVE_CURRENCIES_ONLY[ChainId.POLYGON],
|
||||
DAI_POLYGON,
|
||||
USDC_POLYGON,
|
||||
USDT_POLYGON,
|
||||
WETH_POLYGON,
|
||||
],
|
||||
[ChainId.BNB]: [
|
||||
...WRAPPED_NATIVE_CURRENCIES_ONLY[ChainId.BNB],
|
||||
DAI_BSC,
|
||||
USDC_BSC,
|
||||
USDT_BSC,
|
||||
BUSD_BSC,
|
||||
FRAX_BSC,
|
||||
MATIC_BSC,
|
||||
CAKE_BSC,
|
||||
],
|
||||
[ChainId.AVALANCHE]: [
|
||||
...WRAPPED_NATIVE_CURRENCIES_ONLY[ChainId.AVALANCHE],
|
||||
DAI_AVALANCHE,
|
||||
USDC_AVALANCHE,
|
||||
USDT_AVALANCHE,
|
||||
WETH_AVALANCHE,
|
||||
],
|
||||
[ChainId.CELO]: [CUSD_CELO, CEUR_CELO, CMC02_CELO, PORTAL_USDC_CELO, PORTAL_ETH_CELO],
|
||||
}
|
||||
export const ADDITIONAL_BASES: { [chainId: number]: { [tokenAddress: string]: Token[] } } = {
|
||||
[ChainId.MAINNET]: {
|
||||
'0xF16E4d813f4DcfDe4c5b44f305c908742De84eF0': [ETH2X_FLI],
|
||||
[rETH2.address]: [sETH2],
|
||||
[SWISE.address]: [sETH2],
|
||||
[FEI.address]: [TRIBE],
|
||||
[TRIBE.address]: [FEI],
|
||||
[FRAX.address]: [FXS],
|
||||
[FXS.address]: [FRAX],
|
||||
[WBTC.address]: [renBTC],
|
||||
[renBTC.address]: [WBTC],
|
||||
},
|
||||
}
|
||||
/**
|
||||
* Some tokens can only be swapped via certain pairs, so we override the list of bases that are considered for these
|
||||
* tokens.
|
||||
*/
|
||||
export const CUSTOM_BASES: { [chainId: number]: { [tokenAddress: string]: Token[] } } = {
|
||||
[ChainId.MAINNET]: {
|
||||
[AMPL.address]: [DAI, WRAPPED_NATIVE_CURRENCY[ChainId.MAINNET] as Token],
|
||||
},
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows up in the currency select for swap and add liquidity
|
||||
*/
|
||||
|
@ -80,7 +80,7 @@ export const USDC_BASE = new Token(
|
||||
'USD Base Coin',
|
||||
'USDbC'
|
||||
)
|
||||
export const AMPL = new Token(ChainId.MAINNET, '0xD46bA6D942050d489DBd938a2C909A5d5039A161', 9, 'AMPL', 'Ampleforth')
|
||||
|
||||
export const DAI = new Token(ChainId.MAINNET, '0x6B175474E89094C44Da98b954EedeAC495271d0F', 18, 'DAI', 'Dai Stablecoin')
|
||||
export const DAI_ARBITRUM_ONE = new Token(
|
||||
ChainId.ARBITRUM_ONE,
|
||||
@ -147,33 +147,7 @@ export const WBTC_OPTIMISM = new Token(
|
||||
'WBTC',
|
||||
'Wrapped BTC'
|
||||
)
|
||||
export const FEI = new Token(ChainId.MAINNET, '0x956F47F50A910163D8BF957Cf5846D573E7f87CA', 18, 'FEI', 'Fei USD')
|
||||
export const TRIBE = new Token(ChainId.MAINNET, '0xc7283b66Eb1EB5FB86327f08e1B5816b0720212B', 18, 'TRIBE', 'Tribe')
|
||||
export const FRAX = new Token(ChainId.MAINNET, '0x853d955aCEf822Db058eb8505911ED77F175b99e', 18, 'FRAX', 'Frax')
|
||||
export const FXS = new Token(ChainId.MAINNET, '0x3432B6A60D23Ca0dFCa7761B7ab56459D9C964D0', 18, 'FXS', 'Frax Share')
|
||||
export const renBTC = new Token(ChainId.MAINNET, '0xEB4C2781e4ebA804CE9a9803C67d0893436bB27D', 8, 'renBTC', 'renBTC')
|
||||
export const ETH2X_FLI = new Token(
|
||||
ChainId.MAINNET,
|
||||
'0xAa6E8127831c9DE45ae56bB1b0d4D4Da6e5665BD',
|
||||
18,
|
||||
'ETH2x-FLI',
|
||||
'ETH 2x Flexible Leverage Index'
|
||||
)
|
||||
export const sETH2 = new Token(
|
||||
ChainId.MAINNET,
|
||||
'0xFe2e637202056d30016725477c5da089Ab0A043A',
|
||||
18,
|
||||
'sETH2',
|
||||
'StakeWise Staked ETH2'
|
||||
)
|
||||
export const rETH2 = new Token(
|
||||
ChainId.MAINNET,
|
||||
'0x20BC832ca081b91433ff6c17f85701B6e92486c5',
|
||||
18,
|
||||
'rETH2',
|
||||
'StakeWise Reward ETH2'
|
||||
)
|
||||
export const SWISE = new Token(ChainId.MAINNET, '0x48C3399719B582dD63eB5AADf12A40B4C3f52FA2', 18, 'SWISE', 'StakeWise')
|
||||
|
||||
export const WETH_POLYGON_MUMBAI = new Token(
|
||||
ChainId.POLYGON_MUMBAI,
|
||||
'0xa6fa4fb5f76172d178d61b04b0ecd319c5d1c0aa',
|
||||
@ -243,10 +217,7 @@ export const CEUR_CELO_ALFAJORES = new Token(
|
||||
export const USDC_BSC = new Token(ChainId.BNB, '0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d', 18, 'USDC', 'USDC')
|
||||
export const USDT_BSC = new Token(ChainId.BNB, '0x55d398326f99059fF775485246999027B3197955', 18, 'USDT', 'USDT')
|
||||
export const ETH_BSC = new Token(ChainId.BNB, '0x2170Ed0880ac9A755fd29B2688956BD959F933F8', 18, 'ETH', 'Ethereum')
|
||||
export const MATIC_BSC = new Token(ChainId.BNB, '0xCC42724C6683B7E57334c4E856f4c9965ED682bD', 18, 'MATIC', 'Matic')
|
||||
export const FRAX_BSC = new Token(ChainId.BNB, '0x90C97F71E18723b0Cf0dfa30ee176Ab653E89F40', 18, 'FRAX', 'FRAX')
|
||||
export const BTC_BSC = new Token(ChainId.BNB, '0x7130d2A12B9BCbFAe4f2634d864A1Ee1Ce3Ead9c', 18, 'BTCB', 'BTCB')
|
||||
export const CAKE_BSC = new Token(ChainId.BNB, '0x0E09FaBB73Bd3Ade0a17ECC321fD13a19e81cE82', 18, 'CAKE', 'Cake')
|
||||
export const BUSD_BSC = new Token(ChainId.BNB, '0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56', 18, 'BUSD', 'BUSD')
|
||||
export const DAI_BSC = new Token(ChainId.BNB, '0x1AF3F329e8BE154074D8769D1FFa4eE058B1DBc3', 18, 'DAI', 'DAI')
|
||||
|
||||
|
@ -1,72 +0,0 @@
|
||||
import { Currency, Token } from '@uniswap/sdk-core'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { ADDITIONAL_BASES, BASES_TO_CHECK_TRADES_AGAINST, CUSTOM_BASES } from '../constants/routing'
|
||||
|
||||
export function useAllCurrencyCombinations(currencyA?: Currency, currencyB?: Currency): [Token, Token][] {
|
||||
const chainId = currencyA?.chainId
|
||||
|
||||
const [tokenA, tokenB] = chainId ? [currencyA?.wrapped, currencyB?.wrapped] : [undefined, undefined]
|
||||
|
||||
const bases: Token[] = useMemo(() => {
|
||||
if (!chainId || chainId !== tokenB?.chainId) return []
|
||||
|
||||
const common = BASES_TO_CHECK_TRADES_AGAINST[chainId] ?? []
|
||||
const additionalA = tokenA ? ADDITIONAL_BASES[chainId]?.[tokenA.address] ?? [] : []
|
||||
const additionalB = tokenB ? ADDITIONAL_BASES[chainId]?.[tokenB.address] ?? [] : []
|
||||
|
||||
return [...common, ...additionalA, ...additionalB]
|
||||
}, [chainId, tokenA, tokenB])
|
||||
|
||||
const basePairs: [Token, Token][] = useMemo(
|
||||
() =>
|
||||
bases
|
||||
.flatMap((base): [Token, Token][] => bases.map((otherBase) => [base, otherBase]))
|
||||
// though redundant with the first filter below, that expression runs more often, so this is probably worthwhile
|
||||
.filter(([t0, t1]) => !t0.equals(t1)),
|
||||
[bases]
|
||||
)
|
||||
|
||||
return useMemo(
|
||||
() =>
|
||||
tokenA && tokenB
|
||||
? [
|
||||
// the direct pair
|
||||
[tokenA, tokenB] as [Token, Token],
|
||||
// token A against all bases
|
||||
...bases.map((base): [Token, Token] => [tokenA, base]),
|
||||
// token B against all bases
|
||||
...bases.map((base): [Token, Token] => [tokenB, base]),
|
||||
// each base against all bases
|
||||
...basePairs,
|
||||
]
|
||||
// filter out invalid pairs comprised of the same asset (e.g. WETH<>WETH)
|
||||
.filter(([t0, t1]) => !t0.equals(t1))
|
||||
// filter out duplicate pairs
|
||||
.filter(([t0, t1], i, otherPairs) => {
|
||||
// find the first index in the array at which there are the same 2 tokens as the current
|
||||
const firstIndexInOtherPairs = otherPairs.findIndex(([t0Other, t1Other]) => {
|
||||
return (t0.equals(t0Other) && t1.equals(t1Other)) || (t0.equals(t1Other) && t1.equals(t0Other))
|
||||
})
|
||||
// only accept the first occurrence of the same 2 tokens
|
||||
return firstIndexInOtherPairs === i
|
||||
})
|
||||
// optionally filter out some pairs for tokens with custom bases defined
|
||||
.filter(([tokenA, tokenB]) => {
|
||||
if (!chainId) return true
|
||||
const customBases = CUSTOM_BASES[chainId]
|
||||
|
||||
const customBasesA: Token[] | undefined = customBases?.[tokenA.address]
|
||||
const customBasesB: Token[] | undefined = customBases?.[tokenB.address]
|
||||
|
||||
if (!customBasesA && !customBasesB) return true
|
||||
|
||||
if (customBasesA && !customBasesA.find((base) => tokenB.equals(base))) return false
|
||||
if (customBasesB && !customBasesB.find((base) => tokenA.equals(base))) return false
|
||||
|
||||
return true
|
||||
})
|
||||
: [],
|
||||
[tokenA, tokenB, bases, basePairs, chainId]
|
||||
)
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import { Pool, Route } from '@uniswap/v3-sdk'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { useV3SwapPools } from './useV3SwapPools'
|
||||
|
||||
/**
|
||||
* Returns true if poolA is equivalent to poolB
|
||||
* @param poolA one of the two pools
|
||||
* @param poolB the other pool
|
||||
*/
|
||||
function poolEquals(poolA: Pool, poolB: Pool): boolean {
|
||||
return (
|
||||
poolA === poolB ||
|
||||
(poolA.token0.equals(poolB.token0) && poolA.token1.equals(poolB.token1) && poolA.fee === poolB.fee)
|
||||
)
|
||||
}
|
||||
|
||||
function computeAllRoutes(
|
||||
currencyIn: Currency,
|
||||
currencyOut: Currency,
|
||||
pools: Pool[],
|
||||
chainId: number,
|
||||
currentPath: Pool[] = [],
|
||||
allPaths: Route<Currency, Currency>[] = [],
|
||||
startCurrencyIn: Currency = currencyIn,
|
||||
maxHops = 2
|
||||
): Route<Currency, Currency>[] {
|
||||
const tokenIn = currencyIn?.wrapped
|
||||
const tokenOut = currencyOut?.wrapped
|
||||
if (!tokenIn || !tokenOut) throw new Error('Missing tokenIn/tokenOut')
|
||||
|
||||
for (const pool of pools) {
|
||||
if (!pool.involvesToken(tokenIn) || currentPath.find((pathPool) => poolEquals(pool, pathPool))) continue
|
||||
|
||||
const outputToken = pool.token0.equals(tokenIn) ? pool.token1 : pool.token0
|
||||
if (outputToken.equals(tokenOut)) {
|
||||
allPaths.push(new Route([...currentPath, pool], startCurrencyIn, currencyOut))
|
||||
} else if (maxHops > 1) {
|
||||
computeAllRoutes(
|
||||
outputToken,
|
||||
currencyOut,
|
||||
pools,
|
||||
chainId,
|
||||
[...currentPath, pool],
|
||||
allPaths,
|
||||
startCurrencyIn,
|
||||
maxHops - 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return allPaths
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the routes from an input currency to an output currency
|
||||
* @param currencyIn the input currency
|
||||
* @param currencyOut the output currency
|
||||
*/
|
||||
export function useAllV3Routes(
|
||||
currencyIn?: Currency,
|
||||
currencyOut?: Currency
|
||||
): { loading: boolean; routes: Route<Currency, Currency>[] } {
|
||||
const { chainId } = useWeb3React()
|
||||
const { pools, loading: poolsLoading } = useV3SwapPools(currencyIn, currencyOut)
|
||||
|
||||
return useMemo(() => {
|
||||
if (poolsLoading || !chainId || !pools || !currencyIn || !currencyOut) return { loading: true, routes: [] }
|
||||
|
||||
const routes = computeAllRoutes(currencyIn, currencyOut, pools, chainId, [], [], currencyIn, 2)
|
||||
return { loading: false, routes }
|
||||
}, [chainId, currencyIn, currencyOut, pools, poolsLoading])
|
||||
}
|
@ -1,200 +0,0 @@
|
||||
import { renderHook } from '@testing-library/react'
|
||||
import { CurrencyAmount, TradeType } from '@uniswap/sdk-core'
|
||||
import { DAI, USDC_MAINNET } from 'constants/tokens'
|
||||
import { RouterPreference, TradeState } from 'state/routing/types'
|
||||
import { useRouterPreference } from 'state/user/hooks'
|
||||
import { mocked } from 'test-utils/mocked'
|
||||
|
||||
import { useRoutingAPITrade } from '../state/routing/useRoutingAPITrade'
|
||||
import useAutoRouterSupported from './useAutoRouterSupported'
|
||||
import { useBestTrade } from './useBestTrade'
|
||||
import { useClientSideV3Trade } from './useClientSideV3Trade'
|
||||
import useDebounce from './useDebounce'
|
||||
import useIsWindowVisible from './useIsWindowVisible'
|
||||
|
||||
const USDCAmount = CurrencyAmount.fromRawAmount(USDC_MAINNET, '10000')
|
||||
const DAIAmount = CurrencyAmount.fromRawAmount(DAI, '10000')
|
||||
|
||||
jest.mock('./useAutoRouterSupported')
|
||||
jest.mock('./useClientSideV3Trade')
|
||||
jest.mock('./useDebounce')
|
||||
jest.mock('./useIsWindowVisible')
|
||||
jest.mock('state/routing/useRoutingAPITrade')
|
||||
jest.mock('state/user/hooks')
|
||||
|
||||
// helpers to set mock expectations
|
||||
const expectRouterMock = (state: TradeState) => {
|
||||
mocked(useRoutingAPITrade).mockReturnValue({ state, trade: undefined })
|
||||
}
|
||||
|
||||
const expectClientSideMock = (state: TradeState) => {
|
||||
mocked(useClientSideV3Trade).mockReturnValue({ state, trade: undefined })
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
// ignore debounced value
|
||||
mocked(useDebounce).mockImplementation((value) => value)
|
||||
|
||||
mocked(useIsWindowVisible).mockReturnValue(true)
|
||||
mocked(useAutoRouterSupported).mockReturnValue(true)
|
||||
mocked(useRouterPreference).mockReturnValue([RouterPreference.CLIENT, () => undefined])
|
||||
})
|
||||
|
||||
describe('#useBestV3Trade ExactIn', () => {
|
||||
it('does not compute routing api trade when routing API is not supported', async () => {
|
||||
mocked(useAutoRouterSupported).mockReturnValue(false)
|
||||
expectRouterMock(TradeState.INVALID)
|
||||
expectClientSideMock(TradeState.VALID)
|
||||
|
||||
const { result } = renderHook(() => useBestTrade(TradeType.EXACT_INPUT, USDCAmount, DAI))
|
||||
|
||||
expect(useRoutingAPITrade).toHaveBeenCalledWith(
|
||||
TradeType.EXACT_INPUT,
|
||||
USDCAmount,
|
||||
DAI,
|
||||
RouterPreference.CLIENT,
|
||||
true, // skipFetch
|
||||
undefined
|
||||
)
|
||||
expect(useClientSideV3Trade).toHaveBeenCalledWith(TradeType.EXACT_INPUT, USDCAmount, DAI)
|
||||
expect(result.current).toEqual({ state: TradeState.VALID, trade: undefined })
|
||||
})
|
||||
|
||||
it('does not compute routing api trade when window is not focused', async () => {
|
||||
mocked(useIsWindowVisible).mockReturnValue(false)
|
||||
expectRouterMock(TradeState.NO_ROUTE_FOUND)
|
||||
expectClientSideMock(TradeState.VALID)
|
||||
|
||||
const { result } = renderHook(() => useBestTrade(TradeType.EXACT_INPUT, USDCAmount, DAI))
|
||||
|
||||
expect(useRoutingAPITrade).toHaveBeenCalledWith(
|
||||
TradeType.EXACT_INPUT,
|
||||
USDCAmount,
|
||||
DAI,
|
||||
RouterPreference.CLIENT,
|
||||
true, // skipFetch
|
||||
undefined
|
||||
)
|
||||
expect(result.current).toEqual({ state: TradeState.NO_ROUTE_FOUND, trade: undefined })
|
||||
})
|
||||
|
||||
describe('when routing api is in non-error state', () => {
|
||||
it('does not compute client side v3 trade if routing api is LOADING', () => {
|
||||
expectRouterMock(TradeState.LOADING)
|
||||
|
||||
const { result } = renderHook(() => useBestTrade(TradeType.EXACT_INPUT, USDCAmount, DAI))
|
||||
|
||||
expect(useClientSideV3Trade).toHaveBeenCalledWith(TradeType.EXACT_INPUT, undefined, undefined)
|
||||
expect(result.current).toEqual({ state: TradeState.LOADING, trade: undefined })
|
||||
})
|
||||
|
||||
it('does not compute client side v3 trade if routing api is VALID', () => {
|
||||
expectRouterMock(TradeState.VALID)
|
||||
|
||||
const { result } = renderHook(() => useBestTrade(TradeType.EXACT_INPUT, USDCAmount, DAI))
|
||||
|
||||
expect(useClientSideV3Trade).toHaveBeenCalledWith(TradeType.EXACT_INPUT, undefined, undefined)
|
||||
expect(result.current).toEqual({ state: TradeState.VALID, trade: undefined })
|
||||
})
|
||||
})
|
||||
|
||||
describe('when routing api is in error state', () => {
|
||||
it('does not compute client side v3 trade if routing api is INVALID', () => {
|
||||
expectRouterMock(TradeState.INVALID)
|
||||
expectClientSideMock(TradeState.VALID)
|
||||
|
||||
renderHook(() => useBestTrade(TradeType.EXACT_INPUT, USDCAmount, DAI))
|
||||
|
||||
expect(useClientSideV3Trade).toHaveBeenCalledWith(TradeType.EXACT_INPUT, undefined, undefined)
|
||||
})
|
||||
|
||||
it('computes client side v3 trade if routing api is NO_ROUTE_FOUND', () => {
|
||||
expectRouterMock(TradeState.NO_ROUTE_FOUND)
|
||||
expectClientSideMock(TradeState.VALID)
|
||||
|
||||
const { result } = renderHook(() => useBestTrade(TradeType.EXACT_INPUT, USDCAmount, DAI))
|
||||
|
||||
expect(useClientSideV3Trade).toHaveBeenCalledWith(TradeType.EXACT_INPUT, USDCAmount, DAI)
|
||||
expect(result.current).toEqual({ state: TradeState.VALID, trade: undefined })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('#useBestV3Trade ExactOut', () => {
|
||||
it('does not compute routing api trade when routing API is not supported', () => {
|
||||
mocked(useAutoRouterSupported).mockReturnValue(false)
|
||||
expectRouterMock(TradeState.INVALID)
|
||||
expectClientSideMock(TradeState.VALID)
|
||||
|
||||
const { result } = renderHook(() => useBestTrade(TradeType.EXACT_OUTPUT, DAIAmount, USDC_MAINNET))
|
||||
|
||||
expect(useRoutingAPITrade).toHaveBeenCalledWith(
|
||||
TradeType.EXACT_OUTPUT,
|
||||
DAIAmount,
|
||||
USDC_MAINNET,
|
||||
RouterPreference.CLIENT,
|
||||
true, // skipFetch
|
||||
undefined
|
||||
)
|
||||
expect(useClientSideV3Trade).toHaveBeenCalledWith(TradeType.EXACT_OUTPUT, DAIAmount, USDC_MAINNET)
|
||||
expect(result.current).toEqual({ state: TradeState.VALID, trade: undefined })
|
||||
})
|
||||
|
||||
it('does not compute routing api trade when window is not focused', () => {
|
||||
mocked(useIsWindowVisible).mockReturnValue(false)
|
||||
expectRouterMock(TradeState.NO_ROUTE_FOUND)
|
||||
expectClientSideMock(TradeState.VALID)
|
||||
|
||||
const { result } = renderHook(() => useBestTrade(TradeType.EXACT_OUTPUT, DAIAmount, USDC_MAINNET))
|
||||
|
||||
expect(useRoutingAPITrade).toHaveBeenCalledWith(
|
||||
TradeType.EXACT_OUTPUT,
|
||||
DAIAmount,
|
||||
USDC_MAINNET,
|
||||
RouterPreference.CLIENT,
|
||||
true, // skipFetch
|
||||
undefined
|
||||
)
|
||||
expect(result.current).toEqual({ state: TradeState.NO_ROUTE_FOUND, trade: undefined })
|
||||
})
|
||||
describe('when routing api is in non-error state', () => {
|
||||
it('does not compute client side v3 trade if routing api is LOADING', () => {
|
||||
expectRouterMock(TradeState.LOADING)
|
||||
|
||||
const { result } = renderHook(() => useBestTrade(TradeType.EXACT_OUTPUT, DAIAmount, USDC_MAINNET))
|
||||
|
||||
expect(useClientSideV3Trade).toHaveBeenCalledWith(TradeType.EXACT_OUTPUT, undefined, undefined)
|
||||
expect(result.current).toEqual({ state: TradeState.LOADING, trade: undefined })
|
||||
})
|
||||
|
||||
it('does not compute client side v3 trade if routing api is VALID', () => {
|
||||
expectRouterMock(TradeState.VALID)
|
||||
|
||||
const { result } = renderHook(() => useBestTrade(TradeType.EXACT_OUTPUT, DAIAmount, USDC_MAINNET))
|
||||
|
||||
expect(useClientSideV3Trade).toHaveBeenCalledWith(TradeType.EXACT_OUTPUT, undefined, undefined)
|
||||
expect(result.current).toEqual({ state: TradeState.VALID, trade: undefined })
|
||||
})
|
||||
})
|
||||
|
||||
describe('when routing api is in error state', () => {
|
||||
it('computes client side v3 trade if routing api is INVALID', () => {
|
||||
expectRouterMock(TradeState.INVALID)
|
||||
expectClientSideMock(TradeState.VALID)
|
||||
|
||||
renderHook(() => useBestTrade(TradeType.EXACT_OUTPUT, DAIAmount, USDC_MAINNET))
|
||||
|
||||
expect(useClientSideV3Trade).toHaveBeenCalledWith(TradeType.EXACT_OUTPUT, undefined, undefined)
|
||||
})
|
||||
|
||||
it('computes client side v3 trade if routing api is NO_ROUTE_FOUND', () => {
|
||||
expectRouterMock(TradeState.NO_ROUTE_FOUND)
|
||||
expectClientSideMock(TradeState.VALID)
|
||||
|
||||
const { result } = renderHook(() => useBestTrade(TradeType.EXACT_OUTPUT, DAIAmount, USDC_MAINNET))
|
||||
|
||||
expect(useClientSideV3Trade).toHaveBeenCalledWith(TradeType.EXACT_OUTPUT, DAIAmount, USDC_MAINNET)
|
||||
expect(result.current).toEqual({ state: TradeState.VALID, trade: undefined })
|
||||
})
|
||||
})
|
||||
})
|
@ -1,155 +0,0 @@
|
||||
import { ChainId, Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
|
||||
import { Route, SwapQuoter } from '@uniswap/v3-sdk'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import JSBI from 'jsbi'
|
||||
import { useSingleContractWithCallData } from 'lib/hooks/multicall'
|
||||
import { useMemo } from 'react'
|
||||
import { ClassicTrade, InterfaceTrade, QuoteMethod, TradeState } from 'state/routing/types'
|
||||
|
||||
import { isCelo } from '../constants/tokens'
|
||||
import { useAllV3Routes } from './useAllV3Routes'
|
||||
import { useQuoter } from './useContract'
|
||||
|
||||
const QUOTE_GAS_OVERRIDES: { [chainId: number]: number } = {
|
||||
[ChainId.ARBITRUM_ONE]: 25_000_000,
|
||||
[ChainId.ARBITRUM_GOERLI]: 25_000_000,
|
||||
[ChainId.CELO]: 50_000_000,
|
||||
[ChainId.CELO_ALFAJORES]: 50_000_000,
|
||||
[ChainId.POLYGON]: 40_000_000,
|
||||
[ChainId.POLYGON_MUMBAI]: 40_000_000,
|
||||
[ChainId.BNB]: 50_000_000,
|
||||
[ChainId.AVALANCHE]: 50_000_000,
|
||||
}
|
||||
|
||||
const DEFAULT_GAS_QUOTE = 2_000_000
|
||||
|
||||
// TODO (UniswapX or in general): Deprecate this?
|
||||
/**
|
||||
* Returns the best v3 trade for a desired swap
|
||||
* @param tradeType whether the swap is an exact in/out
|
||||
* @param amountSpecified the exact amount to swap in/out
|
||||
* @param otherCurrency the desired output/payment currency
|
||||
*/
|
||||
export function useClientSideV3Trade<TTradeType extends TradeType>(
|
||||
tradeType: TTradeType,
|
||||
amountSpecified?: CurrencyAmount<Currency>,
|
||||
otherCurrency?: Currency
|
||||
): { state: TradeState; trade?: InterfaceTrade } {
|
||||
const [currencyIn, currencyOut] =
|
||||
tradeType === TradeType.EXACT_INPUT
|
||||
? [amountSpecified?.currency, otherCurrency]
|
||||
: [otherCurrency, amountSpecified?.currency]
|
||||
const { routes, loading: routesLoading } = useAllV3Routes(currencyIn, currencyOut)
|
||||
|
||||
const { chainId } = useWeb3React()
|
||||
// Chains deployed using the deploy-v3 script only deploy QuoterV2.
|
||||
const useQuoterV2 = useMemo(() => Boolean(chainId && isCelo(chainId)), [chainId])
|
||||
const quoter = useQuoter(useQuoterV2)
|
||||
const callData = useMemo(
|
||||
() =>
|
||||
amountSpecified
|
||||
? routes.map(
|
||||
(route) => SwapQuoter.quoteCallParameters(route, amountSpecified, tradeType, { useQuoterV2 }).calldata
|
||||
)
|
||||
: [],
|
||||
[amountSpecified, routes, tradeType, useQuoterV2]
|
||||
)
|
||||
|
||||
const quotesResults = useSingleContractWithCallData(quoter, callData, {
|
||||
gasRequired: chainId ? QUOTE_GAS_OVERRIDES[chainId] ?? DEFAULT_GAS_QUOTE : undefined,
|
||||
})
|
||||
|
||||
const currenciesAreTheSame = useMemo(
|
||||
() => currencyIn && currencyOut && (currencyIn.equals(currencyOut) || currencyIn.wrapped.equals(currencyOut)),
|
||||
[currencyIn, currencyOut]
|
||||
)
|
||||
|
||||
return useMemo(() => {
|
||||
if (
|
||||
!amountSpecified ||
|
||||
!currencyIn ||
|
||||
!currencyOut ||
|
||||
quotesResults.some(({ valid }) => !valid) ||
|
||||
currenciesAreTheSame
|
||||
) {
|
||||
return {
|
||||
state: TradeState.INVALID,
|
||||
trade: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
if (routesLoading || quotesResults.some(({ loading }) => loading)) {
|
||||
return {
|
||||
state: TradeState.LOADING,
|
||||
trade: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
const { bestRoute, amountIn, amountOut } = quotesResults.reduce(
|
||||
(
|
||||
currentBest: {
|
||||
bestRoute: Route<Currency, Currency> | null
|
||||
amountIn: CurrencyAmount<Currency> | null
|
||||
amountOut: CurrencyAmount<Currency> | null
|
||||
},
|
||||
{ result },
|
||||
i
|
||||
) => {
|
||||
if (!result) return currentBest
|
||||
|
||||
// overwrite the current best if it's not defined or if this route is better
|
||||
if (tradeType === TradeType.EXACT_INPUT) {
|
||||
const amountOut = CurrencyAmount.fromRawAmount(currencyOut, result.amountOut.toString())
|
||||
if (currentBest.amountOut === null || JSBI.lessThan(currentBest.amountOut.quotient, amountOut.quotient)) {
|
||||
return {
|
||||
bestRoute: routes[i],
|
||||
amountIn: amountSpecified,
|
||||
amountOut,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const amountIn = CurrencyAmount.fromRawAmount(currencyIn, result.amountIn.toString())
|
||||
if (currentBest.amountIn === null || JSBI.greaterThan(currentBest.amountIn.quotient, amountIn.quotient)) {
|
||||
return {
|
||||
bestRoute: routes[i],
|
||||
amountIn,
|
||||
amountOut: amountSpecified,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return currentBest
|
||||
},
|
||||
{
|
||||
bestRoute: null,
|
||||
amountIn: null,
|
||||
amountOut: null,
|
||||
}
|
||||
)
|
||||
|
||||
if (!bestRoute || !amountIn || !amountOut) {
|
||||
return {
|
||||
state: TradeState.NO_ROUTE_FOUND,
|
||||
trade: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
state: TradeState.VALID,
|
||||
trade: new ClassicTrade({
|
||||
v2Routes: [],
|
||||
v3Routes: [
|
||||
{
|
||||
routev3: bestRoute,
|
||||
inputAmount: amountIn,
|
||||
outputAmount: amountOut,
|
||||
},
|
||||
],
|
||||
tradeType,
|
||||
quoteMethod: QuoteMethod.CLIENT_SIDE,
|
||||
// When using SOR, we don't have gas values from routing-api, so we can't calculate approve gas info
|
||||
approveInfo: { needsApprove: false },
|
||||
}),
|
||||
}
|
||||
}, [amountSpecified, currenciesAreTheSame, currencyIn, currencyOut, quotesResults, routes, routesLoading, tradeType])
|
||||
}
|
@ -5,15 +5,12 @@ import {
|
||||
ENS_REGISTRAR_ADDRESSES,
|
||||
MULTICALL_ADDRESSES,
|
||||
NONFUNGIBLE_POSITION_MANAGER_ADDRESSES,
|
||||
QUOTER_ADDRESSES,
|
||||
TICK_LENS_ADDRESSES,
|
||||
V2_ROUTER_ADDRESS,
|
||||
V3_MIGRATOR_ADDRESSES,
|
||||
} from '@uniswap/sdk-core'
|
||||
import QuoterV2Json from '@uniswap/swap-router-contracts/artifacts/contracts/lens/QuoterV2.sol/QuoterV2.json'
|
||||
import IUniswapV2PairJson from '@uniswap/v2-core/build/IUniswapV2Pair.json'
|
||||
import IUniswapV2Router02Json from '@uniswap/v2-periphery/build/IUniswapV2Router02.json'
|
||||
import QuoterJson from '@uniswap/v3-periphery/artifacts/contracts/lens/Quoter.sol/Quoter.json'
|
||||
import TickLensJson from '@uniswap/v3-periphery/artifacts/contracts/lens/TickLens.sol/TickLens.json'
|
||||
import UniswapInterfaceMulticallJson from '@uniswap/v3-periphery/artifacts/contracts/lens/UniswapInterfaceMulticall.sol/UniswapInterfaceMulticall.json'
|
||||
import NonfungiblePositionManagerJson from '@uniswap/v3-periphery/artifacts/contracts/NonfungiblePositionManager.sol/NonfungiblePositionManager.json'
|
||||
@ -32,14 +29,12 @@ import WETH_ABI from 'abis/weth.json'
|
||||
import { RPC_PROVIDERS } from 'constants/providers'
|
||||
import { WRAPPED_NATIVE_CURRENCY } from 'constants/tokens'
|
||||
import { useMemo } from 'react'
|
||||
import { NonfungiblePositionManager, Quoter, QuoterV2, TickLens, UniswapInterfaceMulticall } from 'types/v3'
|
||||
import { NonfungiblePositionManager, TickLens, UniswapInterfaceMulticall } from 'types/v3'
|
||||
import { V3Migrator } from 'types/v3/V3Migrator'
|
||||
import { getContract } from 'utils'
|
||||
|
||||
const { abi: IUniswapV2PairABI } = IUniswapV2PairJson
|
||||
const { abi: IUniswapV2Router02ABI } = IUniswapV2Router02Json
|
||||
const { abi: QuoterABI } = QuoterJson
|
||||
const { abi: QuoterV2ABI } = QuoterV2Json
|
||||
const { abi: TickLensABI } = TickLensJson
|
||||
const { abi: MulticallABI } = UniswapInterfaceMulticallJson
|
||||
const { abi: NFTPositionManagerABI } = NonfungiblePositionManagerJson
|
||||
@ -157,10 +152,6 @@ export function useV3NFTPositionManagerContract(withSignerIfPossible?: boolean):
|
||||
)
|
||||
}
|
||||
|
||||
export function useQuoter(useQuoterV2: boolean) {
|
||||
return useContract<Quoter | QuoterV2>(QUOTER_ADDRESSES, useQuoterV2 ? QuoterV2ABI : QuoterABI)
|
||||
}
|
||||
|
||||
export function useTickLens(): TickLens | null {
|
||||
const { chainId } = useWeb3React()
|
||||
const address = chainId ? TICK_LENS_ADDRESSES[chainId] : undefined
|
||||
|
72
src/hooks/useDebouncedTrade.test.ts
Normal file
72
src/hooks/useDebouncedTrade.test.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import { renderHook } from '@testing-library/react'
|
||||
import { CurrencyAmount, TradeType } from '@uniswap/sdk-core'
|
||||
import { DAI, USDC_MAINNET } from 'constants/tokens'
|
||||
import { RouterPreference, TradeState } from 'state/routing/types'
|
||||
import { useRouterPreference } from 'state/user/hooks'
|
||||
import { mocked } from 'test-utils/mocked'
|
||||
|
||||
import { useRoutingAPITrade } from '../state/routing/useRoutingAPITrade'
|
||||
import useAutoRouterSupported from './useAutoRouterSupported'
|
||||
import useDebounce from './useDebounce'
|
||||
import { useDebouncedTrade } from './useDebouncedTrade'
|
||||
import useIsWindowVisible from './useIsWindowVisible'
|
||||
|
||||
const USDCAmount = CurrencyAmount.fromRawAmount(USDC_MAINNET, '10000')
|
||||
const DAIAmount = CurrencyAmount.fromRawAmount(DAI, '10000')
|
||||
|
||||
jest.mock('./useAutoRouterSupported')
|
||||
jest.mock('./useDebounce')
|
||||
jest.mock('./useIsWindowVisible')
|
||||
jest.mock('state/routing/useRoutingAPITrade')
|
||||
jest.mock('state/user/hooks')
|
||||
|
||||
// helpers to set mock expectations
|
||||
const expectRouterMock = (state: TradeState) => {
|
||||
mocked(useRoutingAPITrade).mockReturnValue({ state, trade: undefined })
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
// ignore debounced value
|
||||
mocked(useDebounce).mockImplementation((value) => value)
|
||||
|
||||
mocked(useIsWindowVisible).mockReturnValue(true)
|
||||
mocked(useAutoRouterSupported).mockReturnValue(true)
|
||||
mocked(useRouterPreference).mockReturnValue([RouterPreference.CLIENT, () => undefined])
|
||||
})
|
||||
|
||||
describe('#useBestV3Trade ExactIn', () => {
|
||||
it('does not compute routing api trade when window is not focused', async () => {
|
||||
mocked(useIsWindowVisible).mockReturnValue(false)
|
||||
expectRouterMock(TradeState.NO_ROUTE_FOUND)
|
||||
|
||||
const { result } = renderHook(() => useDebouncedTrade(TradeType.EXACT_INPUT, USDCAmount, DAI))
|
||||
|
||||
expect(useRoutingAPITrade).toHaveBeenCalledWith(
|
||||
TradeType.EXACT_INPUT,
|
||||
USDCAmount,
|
||||
DAI,
|
||||
RouterPreference.CLIENT,
|
||||
true, // skipFetch
|
||||
undefined
|
||||
)
|
||||
expect(result.current).toEqual({ state: TradeState.NO_ROUTE_FOUND, trade: undefined })
|
||||
})
|
||||
})
|
||||
|
||||
describe('#useDebouncedTrade ExactOut', () => {
|
||||
it('does not compute routing api trade when window is not focused', () => {
|
||||
mocked(useIsWindowVisible).mockReturnValue(false)
|
||||
expectRouterMock(TradeState.NO_ROUTE_FOUND)
|
||||
|
||||
const { result } = renderHook(() => useDebouncedTrade(TradeType.EXACT_OUTPUT, DAIAmount, USDC_MAINNET))
|
||||
expect(useRoutingAPITrade).toHaveBeenCalledWith(
|
||||
TradeType.EXACT_OUTPUT,
|
||||
DAIAmount,
|
||||
USDC_MAINNET,
|
||||
RouterPreference.CLIENT,
|
||||
true, // skipFetch
|
||||
undefined
|
||||
)
|
||||
expect(result.current).toEqual({ state: TradeState.NO_ROUTE_FOUND, trade: undefined })
|
||||
})
|
||||
})
|
@ -8,7 +8,6 @@ import { useRoutingAPITrade } from 'state/routing/useRoutingAPITrade'
|
||||
import { useRouterPreference } from 'state/user/hooks'
|
||||
|
||||
import useAutoRouterSupported from './useAutoRouterSupported'
|
||||
import { useClientSideV3Trade } from './useClientSideV3Trade'
|
||||
import useDebounce from './useDebounce'
|
||||
import useIsWindowVisible from './useIsWindowVisible'
|
||||
|
||||
@ -18,7 +17,7 @@ const DEBOUNCE_TIME = 350
|
||||
// Temporary until we remove the feature flag.
|
||||
const DEBOUNCE_TIME_INCREASED = 650
|
||||
|
||||
export function useBestTrade(
|
||||
export function useDebouncedTrade(
|
||||
tradeType: TradeType,
|
||||
amountSpecified?: CurrencyAmount<Currency>,
|
||||
otherCurrency?: Currency,
|
||||
@ -29,7 +28,7 @@ export function useBestTrade(
|
||||
trade?: InterfaceTrade
|
||||
}
|
||||
|
||||
export function useBestTrade(
|
||||
export function useDebouncedTrade(
|
||||
tradeType: TradeType,
|
||||
amountSpecified?: CurrencyAmount<Currency>,
|
||||
otherCurrency?: Currency,
|
||||
@ -40,12 +39,15 @@ export function useBestTrade(
|
||||
trade?: ClassicTrade
|
||||
}
|
||||
/**
|
||||
* Returns the best v2+v3 trade for a desired swap.
|
||||
* Returns the debounced v2+v3 trade for a desired swap.
|
||||
* @param tradeType whether the swap is an exact in/out
|
||||
* @param amountSpecified the exact amount to swap in/out
|
||||
* @param otherCurrency the desired output/payment currency
|
||||
* @param routerPreferenceOverride force useRoutingAPITrade to use a specific RouterPreference
|
||||
* @param account the connected address
|
||||
*
|
||||
*/
|
||||
export function useBestTrade(
|
||||
export function useDebouncedTrade(
|
||||
tradeType: TradeType,
|
||||
amountSpecified?: CurrencyAmount<Currency>,
|
||||
otherCurrency?: Currency,
|
||||
@ -90,21 +92,12 @@ export function useBestTrade(
|
||||
const inDebounce =
|
||||
(!debouncedAmount && Boolean(amountSpecified)) || (!debouncedOtherCurrency && Boolean(otherCurrency))
|
||||
const isLoading = routingAPITrade.state === TradeState.LOADING || inDebounce
|
||||
const useFallback = (!autoRouterSupported || routingAPITrade.state === TradeState.NO_ROUTE_FOUND) && shouldGetTrade
|
||||
|
||||
// only use client side router if routing api trade failed or is not supported
|
||||
const bestV3Trade = useClientSideV3Trade(
|
||||
tradeType,
|
||||
useFallback ? debouncedAmount : undefined,
|
||||
useFallback ? debouncedOtherCurrency : undefined
|
||||
)
|
||||
|
||||
// only return gas estimate from api if routing api trade is used
|
||||
return useMemo(
|
||||
() => ({
|
||||
...(useFallback ? bestV3Trade : routingAPITrade),
|
||||
...routingAPITrade,
|
||||
...(isLoading ? { state: TradeState.LOADING } : {}),
|
||||
}),
|
||||
[bestV3Trade, isLoading, routingAPITrade, useFallback]
|
||||
[isLoading, routingAPITrade]
|
||||
)
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
import { ChainId, Currency, Token } from '@uniswap/sdk-core'
|
||||
import { FeeAmount, Pool } from '@uniswap/v3-sdk'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { useAllCurrencyCombinations } from './useAllCurrencyCombinations'
|
||||
import { PoolState, usePools } from './usePools'
|
||||
|
||||
/**
|
||||
* Returns all the existing pools that should be considered for swapping between an input currency and an output currency
|
||||
* @param currencyIn the input currency
|
||||
* @param currencyOut the output currency
|
||||
*/
|
||||
export function useV3SwapPools(
|
||||
currencyIn?: Currency,
|
||||
currencyOut?: Currency
|
||||
): {
|
||||
pools: Pool[]
|
||||
loading: boolean
|
||||
} {
|
||||
const { chainId } = useWeb3React()
|
||||
|
||||
const allCurrencyCombinations = useAllCurrencyCombinations(currencyIn, currencyOut)
|
||||
|
||||
const allCurrencyCombinationsWithAllFees: [Token, Token, FeeAmount][] = useMemo(
|
||||
() =>
|
||||
allCurrencyCombinations.reduce<[Token, Token, FeeAmount][]>((list, [tokenA, tokenB]) => {
|
||||
return chainId === ChainId.MAINNET
|
||||
? list.concat([
|
||||
[tokenA, tokenB, FeeAmount.LOW],
|
||||
[tokenA, tokenB, FeeAmount.MEDIUM],
|
||||
[tokenA, tokenB, FeeAmount.HIGH],
|
||||
])
|
||||
: list.concat([
|
||||
[tokenA, tokenB, FeeAmount.LOWEST],
|
||||
[tokenA, tokenB, FeeAmount.LOW],
|
||||
[tokenA, tokenB, FeeAmount.MEDIUM],
|
||||
[tokenA, tokenB, FeeAmount.HIGH],
|
||||
])
|
||||
}, []),
|
||||
[allCurrencyCombinations, chainId]
|
||||
)
|
||||
|
||||
const pools = usePools(allCurrencyCombinationsWithAllFees)
|
||||
|
||||
return useMemo(() => {
|
||||
return {
|
||||
pools: pools
|
||||
.filter((tuple): tuple is [PoolState.EXISTS, Pool] => {
|
||||
return tuple[0] === PoolState.EXISTS && tuple[1] !== null
|
||||
})
|
||||
.map(([, pool]) => pool),
|
||||
loading: pools.some(([state]) => state === PoolState.LOADING),
|
||||
}
|
||||
}, [pools])
|
||||
}
|
@ -35,13 +35,6 @@ export function useSingleContractMultipleData(
|
||||
return multicall.hooks.useSingleContractMultipleData(chainId, latestBlock, ...args)
|
||||
}
|
||||
|
||||
export function useSingleContractWithCallData(
|
||||
...args: SkipFirstTwoParams<typeof multicall.hooks.useSingleContractWithCallData>
|
||||
) {
|
||||
const { chainId, latestBlock } = useCallContext()
|
||||
return multicall.hooks.useSingleContractWithCallData(chainId, latestBlock, ...args)
|
||||
}
|
||||
|
||||
function useCallContext() {
|
||||
const { chainId } = useWeb3React()
|
||||
const latestBlock = useBlockNumber()
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Currency, CurrencyAmount, NativeCurrency, Percent, Token, TradeType } from '@uniswap/sdk-core'
|
||||
import useAutoSlippageTolerance from 'hooks/useAutoSlippageTolerance'
|
||||
import { useBestTrade } from 'hooks/useBestTrade'
|
||||
import { useDebouncedTrade } from 'hooks/useDebouncedTrade'
|
||||
import { useMemo } from 'react'
|
||||
import { ClassicTrade, RouterPreference, TradeState } from 'state/routing/types'
|
||||
import { isClassicTrade } from 'state/routing/utils'
|
||||
@ -14,7 +14,7 @@ export default function useDerivedPayWithAnyTokenSwapInfo(
|
||||
maximumAmountIn?: CurrencyAmount<Token>
|
||||
allowedSlippage: Percent
|
||||
} {
|
||||
const { state, trade } = useBestTrade(
|
||||
const { state, trade } = useDebouncedTrade(
|
||||
TradeType.EXACT_OUTPUT,
|
||||
parsedOutputAmount,
|
||||
inputCurrency ?? undefined,
|
||||
|
@ -2,7 +2,7 @@ import { Trans } from '@lingui/macro'
|
||||
import { ChainId, Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
|
||||
import { useWeb3React } from '@web3-react/core'
|
||||
import useAutoSlippageTolerance from 'hooks/useAutoSlippageTolerance'
|
||||
import { useBestTrade } from 'hooks/useBestTrade'
|
||||
import { useDebouncedTrade } from 'hooks/useDebouncedTrade'
|
||||
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
|
||||
import { ParsedQs } from 'qs'
|
||||
import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
@ -115,7 +115,7 @@ export function useDerivedSwapInfo(state: SwapState, chainId: ChainId | undefine
|
||||
[inputCurrency, isExactIn, outputCurrency, typedValue]
|
||||
)
|
||||
|
||||
let trade = useBestTrade(
|
||||
let trade = useDebouncedTrade(
|
||||
isExactIn ? TradeType.EXACT_INPUT : TradeType.EXACT_OUTPUT,
|
||||
parsedAmount,
|
||||
(isExactIn ? outputCurrency : inputCurrency) ?? undefined,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { CurrencyAmount, Percent, Price } from '@uniswap/sdk-core'
|
||||
import { renBTC, USDC_MAINNET } from 'constants/tokens'
|
||||
import { USDC_MAINNET, WBTC } from 'constants/tokens'
|
||||
|
||||
import {
|
||||
currencyAmountToPreciseFloat,
|
||||
@ -217,19 +217,19 @@ describe('currencyAmountToPreciseFloat', () => {
|
||||
|
||||
describe('priceToPreciseFloat', () => {
|
||||
it('small number', () => {
|
||||
const price = new Price(renBTC, USDC_MAINNET, 1234, 1)
|
||||
const price = new Price(WBTC, USDC_MAINNET, 1234, 1)
|
||||
expect(priceToPreciseFloat(price)).toEqual(0.0810373)
|
||||
})
|
||||
it('tiny number', () => {
|
||||
const price = new Price(renBTC, USDC_MAINNET, 12345600, 1)
|
||||
const price = new Price(WBTC, USDC_MAINNET, 12345600, 1)
|
||||
expect(priceToPreciseFloat(price)).toEqual(0.00000810005)
|
||||
})
|
||||
it('lots of decimals', () => {
|
||||
const price = new Price(renBTC, USDC_MAINNET, 123, 7)
|
||||
const price = new Price(WBTC, USDC_MAINNET, 123, 7)
|
||||
expect(priceToPreciseFloat(price)).toEqual(5.691056911)
|
||||
})
|
||||
it('integer', () => {
|
||||
const price = new Price(renBTC, USDC_MAINNET, 1, 7)
|
||||
const price = new Price(WBTC, USDC_MAINNET, 1, 7)
|
||||
expect(priceToPreciseFloat(price)).toEqual(700)
|
||||
})
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user