Commit fe6324f8 authored by Vignesh Mohankumar's avatar Vignesh Mohankumar Committed by GitHub

feat: remove v2, v3 swap router (#4372)

* remove v3 router

* rm v2

* unused

* remove anytrade

* unused

* rm shared

* remove optimized trade

* celo fix
parent 4a70eb59
...@@ -13,7 +13,7 @@ export const V2_ROUTER_ADDRESS: AddressMap = constructSameAddressMap('0x7a250d56 ...@@ -13,7 +13,7 @@ export const V2_ROUTER_ADDRESS: AddressMap = constructSameAddressMap('0x7a250d56
// celo v3 addresses // celo v3 addresses
const CELO_V3_CORE_FACTORY_ADDRESSES = '0xAfE208a311B21f13EF87E33A90049fC17A7acDEc' const CELO_V3_CORE_FACTORY_ADDRESSES = '0xAfE208a311B21f13EF87E33A90049fC17A7acDEc'
const CELO_V3_ROUTER_ADDRESS = '0x5615CDAb10dc425a742d643d949a7F474C01abc4' const CELO_ROUTER_ADDRESS = '0x5615CDAb10dc425a742d643d949a7F474C01abc4'
const CELO_V3_MIGRATOR_ADDRESSES = '0x3cFd4d48EDfDCC53D3f173F596f621064614C582' const CELO_V3_MIGRATOR_ADDRESSES = '0x3cFd4d48EDfDCC53D3f173F596f621064614C582'
const CELO_MULTICALL_ADDRESS = '0x633987602DE5C4F337e3DbF265303A1080324204' const CELO_MULTICALL_ADDRESS = '0x633987602DE5C4F337e3DbF265303A1080324204'
const CELO_QUOTER_ADDRESSES = '0x82825d0554fA07f7FC52Ab63c961F330fdEFa8E8' const CELO_QUOTER_ADDRESSES = '0x82825d0554fA07f7FC52Ab63c961F330fdEFa8E8'
...@@ -34,19 +34,6 @@ export const V3_CORE_FACTORY_ADDRESSES: AddressMap = { ...@@ -34,19 +34,6 @@ export const V3_CORE_FACTORY_ADDRESSES: AddressMap = {
[SupportedChainId.CELO_ALFAJORES]: CELO_V3_CORE_FACTORY_ADDRESSES, [SupportedChainId.CELO_ALFAJORES]: CELO_V3_CORE_FACTORY_ADDRESSES,
} }
export const V3_ROUTER_ADDRESS: AddressMap = {
...constructSameAddressMap('0xE592427A0AEce92De3Edee1F18E0157C05861564', [
SupportedChainId.OPTIMISM,
SupportedChainId.OPTIMISTIC_KOVAN,
SupportedChainId.ARBITRUM_ONE,
SupportedChainId.ARBITRUM_RINKEBY,
SupportedChainId.POLYGON,
SupportedChainId.POLYGON_MUMBAI,
]),
[SupportedChainId.CELO]: CELO_V3_ROUTER_ADDRESS,
[SupportedChainId.CELO_ALFAJORES]: CELO_V3_ROUTER_ADDRESS,
}
export const V3_MIGRATOR_ADDRESSES: AddressMap = { export const V3_MIGRATOR_ADDRESSES: AddressMap = {
...constructSameAddressMap('0xA5644E29708357803b5A882D272c41cC0dF92B34', [ ...constructSameAddressMap('0xA5644E29708357803b5A882D272c41cC0dF92B34', [
SupportedChainId.ARBITRUM_ONE, SupportedChainId.ARBITRUM_ONE,
...@@ -80,8 +67,8 @@ export const SWAP_ROUTER_ADDRESSES: AddressMap = { ...@@ -80,8 +67,8 @@ export const SWAP_ROUTER_ADDRESSES: AddressMap = {
SupportedChainId.POLYGON, SupportedChainId.POLYGON,
SupportedChainId.POLYGON_MUMBAI, SupportedChainId.POLYGON_MUMBAI,
]), ]),
[SupportedChainId.CELO]: CELO_V3_ROUTER_ADDRESS, [SupportedChainId.CELO]: CELO_ROUTER_ADDRESS,
[SupportedChainId.CELO_ALFAJORES]: CELO_V3_ROUTER_ADDRESS, [SupportedChainId.CELO_ALFAJORES]: CELO_ROUTER_ADDRESS,
} }
/** /**
......
import { Trade } from '@uniswap/router-sdk' import { Trade } from '@uniswap/router-sdk'
import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
import { Trade as V2Trade } from '@uniswap/v2-sdk' import useSwapApproval from 'lib/hooks/swap/useSwapApproval'
import { Trade as V3Trade } from '@uniswap/v3-sdk'
import useSwapApproval, { useSwapApprovalOptimizedTrade } from 'lib/hooks/swap/useSwapApproval'
import { ApprovalState, useApproval } from 'lib/hooks/useApproval' import { ApprovalState, useApproval } from 'lib/hooks/useApproval'
import { useCallback } from 'react' import { useCallback } from 'react'
...@@ -31,19 +29,8 @@ export function useApproveCallback( ...@@ -31,19 +29,8 @@ export function useApproveCallback(
return [approval, useGetAndTrackApproval(getApproval)] return [approval, useGetAndTrackApproval(getApproval)]
} }
export function useApprovalOptimizedTrade(
trade: Trade<Currency, Currency, TradeType> | undefined,
allowedSlippage: Percent
) {
return useSwapApprovalOptimizedTrade(trade, allowedSlippage, useHasPendingApproval)
}
export function useApproveCallbackFromTrade( export function useApproveCallbackFromTrade(
trade: trade: Trade<Currency, Currency, TradeType> | undefined,
| V2Trade<Currency, Currency, TradeType>
| V3Trade<Currency, Currency, TradeType>
| Trade<Currency, Currency, TradeType>
| undefined,
allowedSlippage: Percent allowedSlippage: Percent
): [ApprovalState, () => Promise<void>] { ): [ApprovalState, () => Promise<void>] {
const [approval, getApproval] = useSwapApproval(trade, allowedSlippage, useHasPendingApproval) const [approval, getApproval] = useSwapApproval(trade, allowedSlippage, useHasPendingApproval)
......
...@@ -2,14 +2,12 @@ import { BigNumber } from '@ethersproject/bignumber' ...@@ -2,14 +2,12 @@ import { BigNumber } from '@ethersproject/bignumber'
import { splitSignature } from '@ethersproject/bytes' import { splitSignature } from '@ethersproject/bytes'
import { Trade } from '@uniswap/router-sdk' import { Trade } from '@uniswap/router-sdk'
import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
import { Trade as V2Trade } from '@uniswap/v2-sdk'
import { Trade as V3Trade } from '@uniswap/v3-sdk'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import JSBI from 'jsbi' import JSBI from 'jsbi'
import { useSingleCallResult } from 'lib/hooks/multicall' import { useSingleCallResult } from 'lib/hooks/multicall'
import { useMemo, useState } from 'react' import { useMemo, useState } from 'react'
import { SWAP_ROUTER_ADDRESSES, V3_ROUTER_ADDRESS } from '../constants/addresses' import { SWAP_ROUTER_ADDRESSES } from '../constants/addresses'
import { DAI, UNI, USDC_MAINNET } from '../constants/tokens' import { DAI, UNI, USDC_MAINNET } from '../constants/tokens'
import { useEIP2612Contract } from './useContract' import { useEIP2612Contract } from './useContract'
import useIsArgentWallet from './useIsArgentWallet' import useIsArgentWallet from './useIsArgentWallet'
...@@ -260,23 +258,12 @@ export function useERC20Permit( ...@@ -260,23 +258,12 @@ export function useERC20Permit(
} }
export function useERC20PermitFromTrade( export function useERC20PermitFromTrade(
trade: trade: Trade<Currency, Currency, TradeType> | undefined,
| V2Trade<Currency, Currency, TradeType>
| V3Trade<Currency, Currency, TradeType>
| Trade<Currency, Currency, TradeType>
| undefined,
allowedSlippage: Percent, allowedSlippage: Percent,
transactionDeadline: BigNumber | undefined transactionDeadline: BigNumber | undefined
) { ) {
const { chainId } = useWeb3React() const { chainId } = useWeb3React()
const swapRouterAddress = chainId const swapRouterAddress = chainId ? SWAP_ROUTER_ADDRESSES[chainId] : undefined
? // v2 router does not support
trade instanceof V2Trade
? undefined
: trade instanceof V3Trade
? V3_ROUTER_ADDRESS[chainId]
: SWAP_ROUTER_ADDRESSES[chainId]
: undefined
const amountToApprove = useMemo( const amountToApprove = useMemo(
() => (trade ? trade.maximumAmountIn(allowedSlippage) : undefined), () => (trade ? trade.maximumAmountIn(allowedSlippage) : undefined),
[trade, allowedSlippage] [trade, allowedSlippage]
......
import { BigNumber } from '@ethersproject/bignumber' import { BigNumber } from '@ethersproject/bignumber'
import { SwapRouter, Trade } from '@uniswap/router-sdk' import { SwapRouter, Trade } from '@uniswap/router-sdk'
import { Currency, Percent, TradeType } from '@uniswap/sdk-core' import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
import { Router as V2SwapRouter, Trade as V2Trade } from '@uniswap/v2-sdk' import { FeeOptions } from '@uniswap/v3-sdk'
import { FeeOptions, SwapRouter as V3SwapRouter, Trade as V3Trade } from '@uniswap/v3-sdk'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { SWAP_ROUTER_ADDRESSES, V3_ROUTER_ADDRESS } from 'constants/addresses' import { SWAP_ROUTER_ADDRESSES } from 'constants/addresses'
import { useMemo } from 'react' import { useMemo } from 'react'
import approveAmountCalldata from 'utils/approveAmountCalldata' import approveAmountCalldata from 'utils/approveAmountCalldata'
import { useArgentWalletContract } from './useArgentWalletContract' import { useArgentWalletContract } from './useArgentWalletContract'
import { useV2RouterContract } from './useContract'
import useENS from './useENS' import useENS from './useENS'
import { SignatureData } from './useERC20Permit' import { SignatureData } from './useERC20Permit'
export type AnyTrade =
| V2Trade<Currency, Currency, TradeType>
| V3Trade<Currency, Currency, TradeType>
| Trade<Currency, Currency, TradeType>
interface SwapCall { interface SwapCall {
address: string address: string
calldata: string calldata: string
...@@ -32,7 +25,7 @@ interface SwapCall { ...@@ -32,7 +25,7 @@ interface SwapCall {
* @param signatureData the signature data of the permit of the input token amount, if available * @param signatureData the signature data of the permit of the input token amount, if available
*/ */
export function useSwapCallArguments( export function useSwapCallArguments(
trade: AnyTrade | undefined, trade: Trade<Currency, Currency, TradeType> | undefined,
allowedSlippage: Percent, allowedSlippage: Percent,
recipientAddressOrName: string | null | undefined, recipientAddressOrName: string | null | undefined,
signatureData: SignatureData | null | undefined, signatureData: SignatureData | null | undefined,
...@@ -43,62 +36,15 @@ export function useSwapCallArguments( ...@@ -43,62 +36,15 @@ export function useSwapCallArguments(
const { address: recipientAddress } = useENS(recipientAddressOrName) const { address: recipientAddress } = useENS(recipientAddressOrName)
const recipient = recipientAddressOrName === null ? account : recipientAddress const recipient = recipientAddressOrName === null ? account : recipientAddress
const routerContract = useV2RouterContract()
const argentWalletContract = useArgentWalletContract() const argentWalletContract = useArgentWalletContract()
return useMemo(() => { return useMemo(() => {
if (!trade || !recipient || !provider || !account || !chainId || !deadline) return [] if (!trade || !recipient || !provider || !account || !chainId || !deadline) return []
if (trade instanceof V2Trade) { const swapRouterAddress = chainId ? SWAP_ROUTER_ADDRESSES[chainId] : undefined
if (!routerContract) return [] if (!swapRouterAddress) return []
const swapMethods = []
swapMethods.push(
V2SwapRouter.swapCallParameters(trade, {
feeOnTransfer: false,
allowedSlippage,
recipient,
deadline: deadline.toNumber(),
})
)
if (trade.tradeType === TradeType.EXACT_INPUT) { const { value, calldata } = SwapRouter.swapCallParameters(trade, {
swapMethods.push(
V2SwapRouter.swapCallParameters(trade, {
feeOnTransfer: true,
allowedSlippage,
recipient,
deadline: deadline.toNumber(),
})
)
}
return swapMethods.map(({ methodName, args, value }) => {
if (argentWalletContract && trade.inputAmount.currency.isToken) {
return {
address: argentWalletContract.address,
calldata: argentWalletContract.interface.encodeFunctionData('wc_multiCall', [
[
approveAmountCalldata(trade.maximumAmountIn(allowedSlippage), routerContract.address),
{
to: routerContract.address,
value,
data: routerContract.interface.encodeFunctionData(methodName, args),
},
],
]),
value: '0x0',
}
} else {
return {
address: routerContract.address,
calldata: routerContract.interface.encodeFunctionData(methodName, args),
value,
}
}
})
} else {
// swap options shared by v3 and v2+v3 swap routers
const sharedSwapOptions = {
fee: feeOptions, fee: feeOptions,
recipient, recipient,
slippageTolerance: allowedSlippage, slippageTolerance: allowedSlippage,
...@@ -122,23 +68,7 @@ export function useSwapCallArguments( ...@@ -122,23 +68,7 @@ export function useSwapCallArguments(
}, },
} }
: {}), : {}),
}
const swapRouterAddress = chainId
? trade instanceof V3Trade
? V3_ROUTER_ADDRESS[chainId]
: SWAP_ROUTER_ADDRESSES[chainId]
: undefined
if (!swapRouterAddress) return []
const { value, calldata } =
trade instanceof V3Trade
? V3SwapRouter.swapCallParameters(trade, {
...sharedSwapOptions,
deadline: deadline.toString(),
})
: SwapRouter.swapCallParameters(trade, {
...sharedSwapOptions,
deadlineOrPreviousBlockhash: deadline.toString(), deadlineOrPreviousBlockhash: deadline.toString(),
}) })
...@@ -167,7 +97,6 @@ export function useSwapCallArguments( ...@@ -167,7 +97,6 @@ export function useSwapCallArguments(
value, value,
}, },
] ]
}
}, [ }, [
account, account,
allowedSlippage, allowedSlippage,
...@@ -177,7 +106,6 @@ export function useSwapCallArguments( ...@@ -177,7 +106,6 @@ export function useSwapCallArguments(
feeOptions, feeOptions,
provider, provider,
recipient, recipient,
routerContract,
signatureData, signatureData,
trade, trade,
]) ])
......
// eslint-disable-next-line no-restricted-imports // eslint-disable-next-line no-restricted-imports
import { Percent, TradeType } from '@uniswap/sdk-core' import { Trade } from '@uniswap/router-sdk'
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { SwapCallbackState, useSwapCallback as useLibSwapCallBack } from 'lib/hooks/swap/useSwapCallback' import { SwapCallbackState, useSwapCallback as useLibSwapCallBack } from 'lib/hooks/swap/useSwapCallback'
import { ReactNode, useMemo } from 'react' import { ReactNode, useMemo } from 'react'
...@@ -9,13 +10,12 @@ import { TransactionType } from '../state/transactions/types' ...@@ -9,13 +10,12 @@ import { TransactionType } from '../state/transactions/types'
import { currencyId } from '../utils/currencyId' import { currencyId } from '../utils/currencyId'
import useENS from './useENS' import useENS from './useENS'
import { SignatureData } from './useERC20Permit' import { SignatureData } from './useERC20Permit'
import { AnyTrade } from './useSwapCallArguments'
import useTransactionDeadline from './useTransactionDeadline' import useTransactionDeadline from './useTransactionDeadline'
// returns a function that will execute a swap, if the parameters are all valid // returns a function that will execute a swap, if the parameters are all valid
// and the user has approved the slippage adjusted input amount for the trade // and the user has approved the slippage adjusted input amount for the trade
export function useSwapCallback( export function useSwapCallback(
trade: AnyTrade | undefined, // trade to execute, required trade: Trade<Currency, Currency, TradeType> | undefined, // trade to execute, required
allowedSlippage: Percent, // in bips allowedSlippage: Percent, // in bips
recipientAddressOrName: string | null, // the ENS name or address of the recipient of the trade, or null if swap should be returned to sender recipientAddressOrName: string | null, // the ENS name or address of the recipient of the trade, or null if swap should be returned to sender
signatureData: SignatureData | undefined | null signatureData: SignatureData | undefined | null
......
...@@ -4,18 +4,11 @@ import { JsonRpcProvider, TransactionResponse } from '@ethersproject/providers' ...@@ -4,18 +4,11 @@ import { JsonRpcProvider, TransactionResponse } from '@ethersproject/providers'
import { t, Trans } from '@lingui/macro' import { t, Trans } from '@lingui/macro'
import { Trade } from '@uniswap/router-sdk' import { Trade } from '@uniswap/router-sdk'
import { Currency, TradeType } from '@uniswap/sdk-core' import { Currency, TradeType } from '@uniswap/sdk-core'
import { Trade as V2Trade } from '@uniswap/v2-sdk'
import { Trade as V3Trade } from '@uniswap/v3-sdk'
import { useMemo } from 'react' import { useMemo } from 'react'
import { calculateGasMargin } from 'utils/calculateGasMargin' import { calculateGasMargin } from 'utils/calculateGasMargin'
import isZero from 'utils/isZero' import isZero from 'utils/isZero'
import { swapErrorToUserReadableMessage } from 'utils/swapErrorToUserReadableMessage' import { swapErrorToUserReadableMessage } from 'utils/swapErrorToUserReadableMessage'
type AnyTrade =
| V2Trade<Currency, Currency, TradeType>
| V3Trade<Currency, Currency, TradeType>
| Trade<Currency, Currency, TradeType>
interface SwapCall { interface SwapCall {
address: string address: string
calldata: string calldata: string
...@@ -41,7 +34,7 @@ export default function useSendSwapTransaction( ...@@ -41,7 +34,7 @@ export default function useSendSwapTransaction(
account: string | null | undefined, account: string | null | undefined,
chainId: number | undefined, chainId: number | undefined,
provider: JsonRpcProvider | undefined, provider: JsonRpcProvider | undefined,
trade: AnyTrade | undefined, // trade to execute, required trade: Trade<Currency, Currency, TradeType> | undefined, // trade to execute, required
swapCalls: SwapCall[] swapCalls: SwapCall[]
): { callback: null | (() => Promise<TransactionResponse>) } { ): { callback: null | (() => Promise<TransactionResponse>) } {
return useMemo(() => { return useMemo(() => {
......
import { Protocol, Trade } from '@uniswap/router-sdk' import { Trade } from '@uniswap/router-sdk'
import { Currency, CurrencyAmount, Percent, Token, TradeType } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Percent, Token, TradeType } from '@uniswap/sdk-core'
import { Pair, Route as V2Route, Trade as V2Trade } from '@uniswap/v2-sdk'
import { Pool, Route as V3Route, Trade as V3Trade } from '@uniswap/v3-sdk'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { SWAP_ROUTER_ADDRESSES, V2_ROUTER_ADDRESS, V3_ROUTER_ADDRESS } from 'constants/addresses' import { SWAP_ROUTER_ADDRESSES } from 'constants/addresses'
import { useMemo } from 'react' import { useMemo } from 'react'
import { getTxOptimizedSwapRouter, SwapRouterVersion } from 'utils/getTxOptimizedSwapRouter'
import { ApprovalState, useApproval, useApprovalStateForSpender } from '../useApproval' import { useApproval } from '../useApproval'
export { ApprovalState } from '../useApproval' export { ApprovalState } from '../useApproval'
/** Returns approval state for all known swap routers */
function useSwapApprovalStates(
trade: Trade<Currency, Currency, TradeType> | undefined,
allowedSlippage: Percent,
useIsPendingApproval: (token?: Token, spender?: string) => boolean
): { v2: ApprovalState; v3: ApprovalState; v2V3: ApprovalState } {
const { chainId } = useWeb3React()
const amountToApprove = useMemo(
() => (trade && trade.inputAmount.currency.isToken ? trade.maximumAmountIn(allowedSlippage) : undefined),
[trade, allowedSlippage]
)
const v2RouterAddress = chainId ? V2_ROUTER_ADDRESS[chainId] : undefined
const v3RouterAddress = chainId ? V3_ROUTER_ADDRESS[chainId] : undefined
const swapRouterAddress = chainId ? SWAP_ROUTER_ADDRESSES[chainId] : undefined
const v2 = useApprovalStateForSpender(amountToApprove, v2RouterAddress, useIsPendingApproval)
const v3 = useApprovalStateForSpender(amountToApprove, v3RouterAddress, useIsPendingApproval)
const v2V3 = useApprovalStateForSpender(amountToApprove, swapRouterAddress, useIsPendingApproval)
return useMemo(() => ({ v2, v3, v2V3 }), [v2, v2V3, v3])
}
export function useSwapRouterAddress(
trade:
| V2Trade<Currency, Currency, TradeType>
| V3Trade<Currency, Currency, TradeType>
| Trade<Currency, Currency, TradeType>
| undefined
) {
const { chainId } = useWeb3React()
return useMemo(
() =>
chainId
? trade instanceof V2Trade
? V2_ROUTER_ADDRESS[chainId]
: trade instanceof V3Trade
? V3_ROUTER_ADDRESS[chainId]
: SWAP_ROUTER_ADDRESSES[chainId]
: undefined,
[chainId, trade]
)
}
// wraps useApproveCallback in the context of a swap // wraps useApproveCallback in the context of a swap
export default function useSwapApproval( export default function useSwapApproval(
trade: trade: Trade<Currency, Currency, TradeType> | undefined,
| V2Trade<Currency, Currency, TradeType>
| V3Trade<Currency, Currency, TradeType>
| Trade<Currency, Currency, TradeType>
| undefined,
allowedSlippage: Percent, allowedSlippage: Percent,
useIsPendingApproval: (token?: Token, spender?: string) => boolean, useIsPendingApproval: (token?: Token, spender?: string) => boolean,
amount?: CurrencyAmount<Currency> // defaults to trade.maximumAmountIn(allowedSlippage) amount?: CurrencyAmount<Currency> // defaults to trade.maximumAmountIn(allowedSlippage)
) { ) {
const { chainId } = useWeb3React()
const amountToApprove = useMemo( const amountToApprove = useMemo(
() => amount || (trade && trade.inputAmount.currency.isToken ? trade.maximumAmountIn(allowedSlippage) : undefined), () => amount || (trade && trade.inputAmount.currency.isToken ? trade.maximumAmountIn(allowedSlippage) : undefined),
[amount, trade, allowedSlippage] [amount, trade, allowedSlippage]
) )
const spender = useSwapRouterAddress(trade) const spender = chainId ? SWAP_ROUTER_ADDRESSES[chainId] : undefined
return useApproval(amountToApprove, spender, useIsPendingApproval) return useApproval(amountToApprove, spender, useIsPendingApproval)
} }
export function useSwapApprovalOptimizedTrade(
trade: Trade<Currency, Currency, TradeType> | undefined,
allowedSlippage: Percent,
useIsPendingApproval: (token?: Token, spender?: string) => boolean
):
| V2Trade<Currency, Currency, TradeType>
| V3Trade<Currency, Currency, TradeType>
| Trade<Currency, Currency, TradeType>
| undefined {
const onlyV2Routes = trade?.routes.every((route) => route.protocol === Protocol.V2)
const onlyV3Routes = trade?.routes.every((route) => route.protocol === Protocol.V3)
const tradeHasSplits = (trade?.routes.length ?? 0) > 1
const approvalStates = useSwapApprovalStates(trade, allowedSlippage, useIsPendingApproval)
const optimizedSwapRouter = useMemo(
() => getTxOptimizedSwapRouter({ onlyV2Routes, onlyV3Routes, tradeHasSplits, approvalStates }),
[approvalStates, tradeHasSplits, onlyV2Routes, onlyV3Routes]
)
return useMemo(() => {
if (!trade) return undefined
try {
switch (optimizedSwapRouter) {
case SwapRouterVersion.V2V3:
return trade
case SwapRouterVersion.V2:
const pairs = trade.swaps[0].route.pools.filter((pool) => pool instanceof Pair) as Pair[]
const v2Route = new V2Route(pairs, trade.inputAmount.currency, trade.outputAmount.currency)
return new V2Trade(v2Route, trade.inputAmount, trade.tradeType)
case SwapRouterVersion.V3:
return V3Trade.createUncheckedTradeWithMultipleRoutes({
routes: trade.swaps.map(({ route, inputAmount, outputAmount }) => ({
route: new V3Route(
route.pools.filter((p): p is Pool => p instanceof Pool),
inputAmount.currency,
outputAmount.currency
),
inputAmount,
outputAmount,
})),
tradeType: trade.tradeType,
})
default:
return undefined
}
} catch (e) {
// TODO(#2989): remove try-catch
console.debug(e)
return undefined
}
}, [trade, optimizedSwapRouter])
}
...@@ -2,12 +2,13 @@ ...@@ -2,12 +2,13 @@
import { BigNumber } from '@ethersproject/bignumber' import { BigNumber } from '@ethersproject/bignumber'
import { TransactionResponse } from '@ethersproject/providers' import { TransactionResponse } from '@ethersproject/providers'
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Percent } from '@uniswap/sdk-core' import { Trade } from '@uniswap/router-sdk'
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
import { FeeOptions } from '@uniswap/v3-sdk' import { FeeOptions } from '@uniswap/v3-sdk'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import useENS from 'hooks/useENS' import useENS from 'hooks/useENS'
import { SignatureData } from 'hooks/useERC20Permit' import { SignatureData } from 'hooks/useERC20Permit'
import { AnyTrade, useSwapCallArguments } from 'hooks/useSwapCallArguments' import { useSwapCallArguments } from 'hooks/useSwapCallArguments'
import { ReactNode, useMemo } from 'react' import { ReactNode, useMemo } from 'react'
import useSendSwapTransaction from './useSendSwapTransaction' import useSendSwapTransaction from './useSendSwapTransaction'
...@@ -24,7 +25,7 @@ interface UseSwapCallbackReturns { ...@@ -24,7 +25,7 @@ interface UseSwapCallbackReturns {
error?: ReactNode error?: ReactNode
} }
interface UseSwapCallbackArgs { interface UseSwapCallbackArgs {
trade: AnyTrade | undefined // trade to execute, required trade: Trade<Currency, Currency, TradeType> | undefined // trade to execute, required
allowedSlippage: Percent // in bips allowedSlippage: Percent // in bips
recipientAddressOrName: string | null | undefined // the ENS name or address of the recipient of the trade, or null if swap should be returned to sender recipientAddressOrName: string | null | undefined // the ENS name or address of the recipient of the trade, or null if swap should be returned to sender
signatureData: SignatureData | null | undefined signatureData: SignatureData | null | undefined
......
...@@ -17,7 +17,7 @@ export enum ApprovalState { ...@@ -17,7 +17,7 @@ export enum ApprovalState {
APPROVED = 'APPROVED', APPROVED = 'APPROVED',
} }
export function useApprovalStateForSpender( function useApprovalStateForSpender(
amountToApprove: CurrencyAmount<Currency> | undefined, amountToApprove: CurrencyAmount<Currency> | undefined,
spender: string | undefined, spender: string | undefined,
useIsPendingApproval: (token?: Token, spender?: string) => boolean useIsPendingApproval: (token?: Token, spender?: string) => boolean
......
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Trade } from '@uniswap/router-sdk' import { Trade } from '@uniswap/router-sdk'
import { Currency, CurrencyAmount, Percent, Token, TradeType } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Percent, Token, TradeType } from '@uniswap/sdk-core'
import { Trade as V2Trade } from '@uniswap/v2-sdk'
import { Trade as V3Trade } from '@uniswap/v3-sdk'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { sendAnalyticsEvent } from 'components/AmplitudeAnalytics' import { sendAnalyticsEvent } from 'components/AmplitudeAnalytics'
import { ElementName, Event, EventName, PageName, SectionName } from 'components/AmplitudeAnalytics/constants' import { ElementName, Event, EventName, PageName, SectionName } from 'components/AmplitudeAnalytics/constants'
...@@ -52,7 +50,7 @@ import { SwitchLocaleLink } from '../../components/SwitchLocaleLink' ...@@ -52,7 +50,7 @@ import { SwitchLocaleLink } from '../../components/SwitchLocaleLink'
import TokenWarningModal from '../../components/TokenWarningModal' import TokenWarningModal from '../../components/TokenWarningModal'
import { TOKEN_SHORTHANDS } from '../../constants/tokens' import { TOKEN_SHORTHANDS } from '../../constants/tokens'
import { useAllTokens, useCurrency } from '../../hooks/Tokens' import { useAllTokens, useCurrency } from '../../hooks/Tokens'
import { ApprovalState, useApprovalOptimizedTrade, useApproveCallbackFromTrade } from '../../hooks/useApproveCallback' import { ApprovalState, useApproveCallbackFromTrade } from '../../hooks/useApproveCallback'
import useENSAddress from '../../hooks/useENSAddress' import useENSAddress from '../../hooks/useENSAddress'
import { useERC20PermitFromTrade, UseERC20PermitState } from '../../hooks/useERC20Permit' import { useERC20PermitFromTrade, UseERC20PermitState } from '../../hooks/useERC20Permit'
import useIsArgentWallet from '../../hooks/useIsArgentWallet' import useIsArgentWallet from '../../hooks/useIsArgentWallet'
...@@ -153,6 +151,8 @@ const formatSwapQuoteReceivedEventProperties = ( ...@@ -153,6 +151,8 @@ const formatSwapQuoteReceivedEventProperties = (
} }
} }
const TRADE_STRING = 'SwapRouter'
export default function Swap() { export default function Swap() {
const navigate = useNavigate() const navigate = useNavigate()
const redesignFlag = useRedesignFlag() const redesignFlag = useRedesignFlag()
...@@ -305,22 +305,14 @@ export default function Swap() { ...@@ -305,22 +305,14 @@ export default function Swap() {
currencies[Field.INPUT] && currencies[Field.OUTPUT] && parsedAmounts[independentField]?.greaterThan(JSBI.BigInt(0)) currencies[Field.INPUT] && currencies[Field.OUTPUT] && parsedAmounts[independentField]?.greaterThan(JSBI.BigInt(0))
) )
const approvalOptimizedTrade = useApprovalOptimizedTrade(trade, allowedSlippage)
const approvalOptimizedTradeString =
approvalOptimizedTrade instanceof V2Trade
? 'V2SwapRouter'
: approvalOptimizedTrade instanceof V3Trade
? 'V3SwapRouter'
: 'SwapRouter'
// check whether the user has approved the router on the input token // check whether the user has approved the router on the input token
const [approvalState, approveCallback] = useApproveCallbackFromTrade(approvalOptimizedTrade, allowedSlippage) const [approvalState, approveCallback] = useApproveCallbackFromTrade(trade, allowedSlippage)
const transactionDeadline = useTransactionDeadline() const transactionDeadline = useTransactionDeadline()
const { const {
state: signatureState, state: signatureState,
signatureData, signatureData,
gatherPermitSignature, gatherPermitSignature,
} = useERC20PermitFromTrade(approvalOptimizedTrade, allowedSlippage, transactionDeadline) } = useERC20PermitFromTrade(trade, allowedSlippage, transactionDeadline)
const handleApprove = useCallback(async () => { const handleApprove = useCallback(async () => {
if (signatureState === UseERC20PermitState.NOT_SIGNED && gatherPermitSignature) { if (signatureState === UseERC20PermitState.NOT_SIGNED && gatherPermitSignature) {
...@@ -338,16 +330,10 @@ export default function Swap() { ...@@ -338,16 +330,10 @@ export default function Swap() {
sendEvent({ sendEvent({
category: 'Swap', category: 'Swap',
action: 'Approve', action: 'Approve',
label: [approvalOptimizedTradeString, approvalOptimizedTrade?.inputAmount?.currency.symbol].join('/'), label: [TRADE_STRING, trade?.inputAmount?.currency.symbol].join('/'),
}) })
} }
}, [ }, [signatureState, gatherPermitSignature, approveCallback, trade?.inputAmount?.currency.symbol])
signatureState,
gatherPermitSignature,
approveCallback,
approvalOptimizedTradeString,
approvalOptimizedTrade?.inputAmount?.currency.symbol,
])
// check if user has gone through approval process, used to show two step buttons, reset on token change // check if user has gone through approval process, used to show two step buttons, reset on token change
const [approvalSubmitted, setApprovalSubmitted] = useState<boolean>(false) const [approvalSubmitted, setApprovalSubmitted] = useState<boolean>(false)
...@@ -367,7 +353,7 @@ export default function Swap() { ...@@ -367,7 +353,7 @@ export default function Swap() {
// the callback to execute the swap // the callback to execute the swap
const { callback: swapCallback, error: swapCallbackError } = useSwapCallback( const { callback: swapCallback, error: swapCallbackError } = useSwapCallback(
approvalOptimizedTrade, trade,
allowedSlippage, allowedSlippage,
recipient, recipient,
signatureData signatureData
...@@ -397,12 +383,9 @@ export default function Swap() { ...@@ -397,12 +383,9 @@ export default function Swap() {
: (recipientAddress ?? recipient) === account : (recipientAddress ?? recipient) === account
? 'Swap w/o Send + recipient' ? 'Swap w/o Send + recipient'
: 'Swap w/ Send', : 'Swap w/ Send',
label: [ label: [TRADE_STRING, trade?.inputAmount?.currency?.symbol, trade?.outputAmount?.currency?.symbol, 'MH'].join(
approvalOptimizedTradeString, '/'
approvalOptimizedTrade?.inputAmount?.currency?.symbol, ),
approvalOptimizedTrade?.outputAmount?.currency?.symbol,
'MH',
].join('/'),
}) })
}) })
.catch((error) => { .catch((error) => {
...@@ -422,9 +405,8 @@ export default function Swap() { ...@@ -422,9 +405,8 @@ export default function Swap() {
recipient, recipient,
recipientAddress, recipientAddress,
account, account,
approvalOptimizedTradeString, trade?.inputAmount?.currency?.symbol,
approvalOptimizedTrade?.inputAmount?.currency?.symbol, trade?.outputAmount?.currency?.symbol,
approvalOptimizedTrade?.outputAmount?.currency?.symbol,
]) ])
// errors // errors
......
import { ApprovalState } from 'lib/hooks/useApproval'
import { getTxOptimizedSwapRouter, SwapRouterVersion } from './getTxOptimizedSwapRouter'
const getApprovalState = (approved: SwapRouterVersion[]) => ({
v2: approved.includes(SwapRouterVersion.V2) ? ApprovalState.APPROVED : ApprovalState.NOT_APPROVED,
v3: approved.includes(SwapRouterVersion.V3) ? ApprovalState.APPROVED : ApprovalState.NOT_APPROVED,
v2V3: approved.includes(SwapRouterVersion.V2V3) ? ApprovalState.APPROVED : ApprovalState.NOT_APPROVED,
})
describe(getTxOptimizedSwapRouter, () => {
it('always selects v2v3 when approved', () => {
expect(
getTxOptimizedSwapRouter({
onlyV2Routes: true,
onlyV3Routes: false,
tradeHasSplits: false,
approvalStates: getApprovalState([SwapRouterVersion.V2V3]),
})
).toEqual(SwapRouterVersion.V2V3)
expect(
getTxOptimizedSwapRouter({
onlyV2Routes: false,
onlyV3Routes: true,
tradeHasSplits: false,
approvalStates: getApprovalState([SwapRouterVersion.V2V3]),
})
).toEqual(SwapRouterVersion.V2V3)
expect(
getTxOptimizedSwapRouter({
onlyV2Routes: false,
onlyV3Routes: true,
tradeHasSplits: false,
approvalStates: getApprovalState([SwapRouterVersion.V2, SwapRouterVersion.V3, SwapRouterVersion.V2V3]),
})
).toEqual(SwapRouterVersion.V2V3)
})
it('selects the right router when only v2 routes', () => {
const base = { onlyV3Routes: false }
// selects v2
expect(
getTxOptimizedSwapRouter({
...base,
onlyV2Routes: true,
tradeHasSplits: false,
approvalStates: getApprovalState([SwapRouterVersion.V2, SwapRouterVersion.V3]),
})
).toEqual(SwapRouterVersion.V2)
// selects v2V3
expect(
getTxOptimizedSwapRouter({
...base,
onlyV2Routes: true,
tradeHasSplits: true,
approvalStates: getApprovalState([SwapRouterVersion.V2]),
})
).toEqual(SwapRouterVersion.V2V3)
expect(
getTxOptimizedSwapRouter({
...base,
onlyV2Routes: true,
tradeHasSplits: true,
approvalStates: getApprovalState([SwapRouterVersion.V2, SwapRouterVersion.V2V3]),
})
).toEqual(SwapRouterVersion.V2V3)
})
it('selects the right router when only v3 routes', () => {
const base = { onlyV2Routes: false }
// select v3
expect(
getTxOptimizedSwapRouter({
...base,
onlyV3Routes: true,
tradeHasSplits: false,
approvalStates: getApprovalState([SwapRouterVersion.V2, SwapRouterVersion.V3]),
})
).toEqual(SwapRouterVersion.V3)
expect(
getTxOptimizedSwapRouter({
...base,
onlyV3Routes: true,
tradeHasSplits: true,
approvalStates: getApprovalState([SwapRouterVersion.V3]),
})
).toEqual(SwapRouterVersion.V3)
// selects v2V3
expect(
getTxOptimizedSwapRouter({
...base,
onlyV3Routes: true,
tradeHasSplits: true,
approvalStates: getApprovalState([SwapRouterVersion.V2, SwapRouterVersion.V2V3]),
})
).toEqual(SwapRouterVersion.V2V3)
})
})
import { ApprovalState } from 'lib/hooks/useApproval'
export enum SwapRouterVersion {
V2,
V3,
V2V3,
}
/**
* Returns the swap router that will result in the least amount of txs (less gas) for a given swap.
* Heuristic:
* - if trade contains a single v2-only trade & V2 SwapRouter is approved: use V2 SwapRouter
* - if trade contains only v3 & V3 SwapRouter is approved: use V3 SwapRouter
* - else: approve and use V2+V3 SwapRouter
*/
export function getTxOptimizedSwapRouter({
onlyV2Routes,
onlyV3Routes,
tradeHasSplits,
approvalStates,
}: {
onlyV2Routes: boolean | undefined
onlyV3Routes: boolean | undefined
tradeHasSplits: boolean | undefined
approvalStates: { v2: ApprovalState; v3: ApprovalState; v2V3: ApprovalState }
}): SwapRouterVersion | undefined {
if ([approvalStates.v2, approvalStates.v3, approvalStates.v2V3].includes(ApprovalState.PENDING)) return undefined
if (approvalStates.v2V3 === ApprovalState.APPROVED) return SwapRouterVersion.V2V3
if (approvalStates.v2 === ApprovalState.APPROVED && onlyV2Routes && !tradeHasSplits) return SwapRouterVersion.V2
if (approvalStates.v3 === ApprovalState.APPROVED && onlyV3Routes) return SwapRouterVersion.V3
return SwapRouterVersion.V2V3
}
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