Commit 585d67c4 authored by Vignesh Mohankumar's avatar Vignesh Mohankumar Committed by GitHub

refactor: always enable permit2 (#6068)

* refactor: always enable permit2

* rm from modal

* one more

* rm

* more

* more

* more

* rm useswapcallback

* rm useapprovecallback

* unused hooks

* unused hooks

* rm

* lint
parent 521b9b8e
...@@ -2,7 +2,6 @@ import { BaseVariant, FeatureFlag, featureFlagSettings, useUpdateFlag } from 'fe ...@@ -2,7 +2,6 @@ import { BaseVariant, FeatureFlag, featureFlagSettings, useUpdateFlag } from 'fe
import { GqlRoutingVariant, useGqlRoutingFlag } from 'featureFlags/flags/gqlRouting' import { GqlRoutingVariant, useGqlRoutingFlag } from 'featureFlags/flags/gqlRouting'
import { NftGraphqlVariant, useNftGraphqlFlag } from 'featureFlags/flags/nftlGraphql' import { NftGraphqlVariant, useNftGraphqlFlag } from 'featureFlags/flags/nftlGraphql'
import { PayWithAnyTokenVariant, usePayWithAnyTokenFlag } from 'featureFlags/flags/payWithAnyToken' import { PayWithAnyTokenVariant, usePayWithAnyTokenFlag } from 'featureFlags/flags/payWithAnyToken'
import { Permit2Variant, usePermit2Flag } from 'featureFlags/flags/permit2'
import { SwapWidgetVariant, useSwapWidgetFlag } from 'featureFlags/flags/swapWidget' import { SwapWidgetVariant, useSwapWidgetFlag } from 'featureFlags/flags/swapWidget'
import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc' import { TraceJsonRpcVariant, useTraceJsonRpcFlag } from 'featureFlags/flags/traceJsonRpc'
import { useAtomValue, useUpdateAtom } from 'jotai/utils' import { useAtomValue, useUpdateAtom } from 'jotai/utils'
...@@ -206,12 +205,6 @@ export default function FeatureFlagModal() { ...@@ -206,12 +205,6 @@ export default function FeatureFlagModal() {
<X size={24} /> <X size={24} />
</CloseButton> </CloseButton>
</Header> </Header>
<FeatureFlagOption
variant={Permit2Variant}
value={usePermit2Flag()}
featureFlag={FeatureFlag.permit2}
label="Permit 2 / Universal Router"
/>
<FeatureFlagOption <FeatureFlagOption
variant={PayWithAnyTokenVariant} variant={PayWithAnyTokenVariant}
value={usePayWithAnyTokenFlag()} value={usePayWithAnyTokenFlag()}
......
...@@ -16,7 +16,6 @@ import { ...@@ -16,7 +16,6 @@ import {
SwapWidgetSkeleton, SwapWidgetSkeleton,
} from '@uniswap/widgets' } from '@uniswap/widgets'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { usePermit2Enabled } from 'featureFlags/flags/permit2'
import { useActiveLocale } from 'hooks/useActiveLocale' import { useActiveLocale } from 'hooks/useActiveLocale'
import { import {
formatPercentInBasisPointsNumber, formatPercentInBasisPointsNumber,
...@@ -154,8 +153,6 @@ export default function Widget({ ...@@ -154,8 +153,6 @@ export default function Widget({
[initialQuoteDate, trace] [initialQuoteDate, trace]
) )
const permit2Enabled = usePermit2Enabled()
if (!(inputs.value.INPUT || inputs.value.OUTPUT)) { if (!(inputs.value.INPUT || inputs.value.OUTPUT)) {
return <WidgetSkeleton /> return <WidgetSkeleton />
} }
...@@ -166,7 +163,7 @@ export default function Widget({ ...@@ -166,7 +163,7 @@ export default function Widget({
<SwapWidget <SwapWidget
hideConnectionUI hideConnectionUI
brandedFooter={false} brandedFooter={false}
permit2={permit2Enabled} permit2
routerUrl={WIDGET_ROUTER_URL} routerUrl={WIDGET_ROUTER_URL}
locale={locale} locale={locale}
theme={theme} theme={theme}
......
...@@ -15,7 +15,6 @@ export const V2_ROUTER_ADDRESS: AddressMap = constructSameAddressMap('0x7a250d56 ...@@ -15,7 +15,6 @@ 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_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'
...@@ -24,7 +23,6 @@ const CELO_TICK_LENS_ADDRESSES = '0x5f115D9113F88e0a0Db1b5033D90D4a9690AcD3D' ...@@ -24,7 +23,6 @@ const CELO_TICK_LENS_ADDRESSES = '0x5f115D9113F88e0a0Db1b5033D90D4a9690AcD3D'
// arbitrum goerli v3 addresses // arbitrum goerli v3 addresses
const ARBITRUM_GOERLI_V3_CORE_FACTORY_ADDRESSES = '0x4893376342d5D7b3e31d4184c08b265e5aB2A3f6' const ARBITRUM_GOERLI_V3_CORE_FACTORY_ADDRESSES = '0x4893376342d5D7b3e31d4184c08b265e5aB2A3f6'
const ARBITRUM_GOERLI_ROUTER_ADDRESS = '0xab7664500b19a7a2362Ab26081e6DfB971B6F1B0'
const ARBITRUM_GOERLI_V3_MIGRATOR_ADDRESSES = '0xA815919D2584Ac3F76ea9CB62E6Fd40a43BCe0C3' const ARBITRUM_GOERLI_V3_MIGRATOR_ADDRESSES = '0xA815919D2584Ac3F76ea9CB62E6Fd40a43BCe0C3'
const ARBITRUM_GOERLI_MULTICALL_ADDRESS = '0x8260CB40247290317a4c062F3542622367F206Ee' const ARBITRUM_GOERLI_MULTICALL_ADDRESS = '0x8260CB40247290317a4c062F3542622367F206Ee'
const ARBITRUM_GOERLI_QUOTER_ADDRESSES = '0x1dd92b83591781D0C6d98d07391eea4b9a6008FA' const ARBITRUM_GOERLI_QUOTER_ADDRESSES = '0x1dd92b83591781D0C6d98d07391eea4b9a6008FA'
...@@ -69,19 +67,6 @@ export const MULTICALL_ADDRESS: AddressMap = { ...@@ -69,19 +67,6 @@ export const MULTICALL_ADDRESS: AddressMap = {
[SupportedChainId.ARBITRUM_GOERLI]: ARBITRUM_GOERLI_MULTICALL_ADDRESS, [SupportedChainId.ARBITRUM_GOERLI]: ARBITRUM_GOERLI_MULTICALL_ADDRESS,
} }
export const SWAP_ROUTER_ADDRESSES: AddressMap = {
...constructSameAddressMap('0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45', [
SupportedChainId.OPTIMISM,
SupportedChainId.OPTIMISM_GOERLI,
SupportedChainId.ARBITRUM_ONE,
SupportedChainId.POLYGON,
SupportedChainId.POLYGON_MUMBAI,
]),
[SupportedChainId.CELO]: CELO_ROUTER_ADDRESS,
[SupportedChainId.CELO_ALFAJORES]: CELO_ROUTER_ADDRESS,
[SupportedChainId.ARBITRUM_GOERLI]: ARBITRUM_GOERLI_ROUTER_ADDRESS,
}
/** /**
* The oldest V0 governance address * The oldest V0 governance address
*/ */
......
import { UNIVERSAL_ROUTER_ADDRESS } from '@uniswap/universal-router-sdk'
import { useWeb3React } from '@web3-react/core'
import { BaseVariant, FeatureFlag, useBaseFlag } from '../index'
export function usePermit2Flag(): BaseVariant {
return useBaseFlag(FeatureFlag.permit2, BaseVariant.Enabled)
}
export function usePermit2Enabled(): boolean {
const flagEnabled = usePermit2Flag() === BaseVariant.Enabled
const { chainId } = useWeb3React()
try {
// Detect if the Universal Router is not yet deployed to chainId.
// This is necessary so that we can fallback correctly on chains without a Universal Router deployment.
// It will be removed once Universal Router is deployed on all supported chains.
chainId && UNIVERSAL_ROUTER_ADDRESS(chainId)
return flagEnabled
} catch {
return false
}
}
export { BaseVariant as Permit2Variant }
import { Trade } from '@uniswap/router-sdk' import { Currency, CurrencyAmount } from '@uniswap/sdk-core'
import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
import useSwapApproval 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'
...@@ -28,11 +26,3 @@ export function useApproveCallback( ...@@ -28,11 +26,3 @@ export function useApproveCallback(
const [approval, getApproval] = useApproval(amountToApprove, spender, useHasPendingApproval) const [approval, getApproval] = useApproval(amountToApprove, spender, useHasPendingApproval)
return [approval, useGetAndTrackApproval(getApproval)] return [approval, useGetAndTrackApproval(getApproval)]
} }
export function useApproveCallbackFromTrade(
trade: Trade<Currency, Currency, TradeType> | undefined,
allowedSlippage: Percent
): [ApprovalState, () => Promise<void>] {
const [approval, getApproval] = useSwapApproval(trade, allowedSlippage, useHasPendingApproval)
return [approval, useGetAndTrackApproval(getApproval)]
}
import { BigNumber } from '@ethersproject/bignumber' import { BigNumber } from '@ethersproject/bignumber'
import { splitSignature } from '@ethersproject/bytes' import { splitSignature } from '@ethersproject/bytes'
import { Trade } from '@uniswap/router-sdk' import { Currency, CurrencyAmount } from '@uniswap/sdk-core'
import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import { SupportedChainId } from 'constants/chains' import { SupportedChainId } from 'constants/chains'
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 } 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'
...@@ -44,7 +42,7 @@ const PERMITTABLE_TOKENS: { ...@@ -44,7 +42,7 @@ const PERMITTABLE_TOKENS: {
}, },
} }
export enum UseERC20PermitState { enum UseERC20PermitState {
// returned for any reason, e.g. it is an argent wallet, or the currency does not support it // returned for any reason, e.g. it is an argent wallet, or the currency does not support it
NOT_APPLICABLE, NOT_APPLICABLE,
LOADING, LOADING,
...@@ -73,7 +71,7 @@ interface AllowedSignatureData extends BaseSignatureData { ...@@ -73,7 +71,7 @@ interface AllowedSignatureData extends BaseSignatureData {
allowed: true allowed: true
} }
export type SignatureData = StandardSignatureData | AllowedSignatureData type SignatureData = StandardSignatureData | AllowedSignatureData
const EIP712_DOMAIN_TYPE = [ const EIP712_DOMAIN_TYPE = [
{ name: 'name', type: 'string' }, { name: 'name', type: 'string' },
...@@ -247,18 +245,3 @@ export function useERC20Permit( ...@@ -247,18 +245,3 @@ export function useERC20Permit(
signatureData, signatureData,
]) ])
} }
export function useERC20PermitFromTrade(
trade: Trade<Currency, Currency, TradeType> | undefined,
allowedSlippage: Percent,
transactionDeadline: BigNumber | undefined
) {
const { chainId } = useWeb3React()
const swapRouterAddress = chainId ? SWAP_ROUTER_ADDRESSES[chainId] : undefined
const amountToApprove = useMemo(
() => (trade ? trade.maximumAmountIn(allowedSlippage) : undefined),
[trade, allowedSlippage]
)
return useERC20Permit(amountToApprove, swapRouterAddress, transactionDeadline, null)
}
import { BigNumber } from '@ethersproject/bignumber'
import { SwapRouter, Trade } from '@uniswap/router-sdk'
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
import { FeeOptions } from '@uniswap/v3-sdk'
import { useWeb3React } from '@web3-react/core'
import { SWAP_ROUTER_ADDRESSES } from 'constants/addresses'
import { useMemo } from 'react'
import approveAmountCalldata from 'utils/approveAmountCalldata'
import { useArgentWalletContract } from './useArgentWalletContract'
import useENS from './useENS'
import { SignatureData } from './useERC20Permit'
interface SwapCall {
address: string
calldata: string
value: string
}
/**
* Returns the swap calls that can be used to make the trade
* @param trade trade to execute
* @param allowedSlippage user allowed slippage
* @param recipientAddressOrName the ENS name or address of the recipient of the swap output
* @param signatureData the signature data of the permit of the input token amount, if available
*/
export function useSwapCallArguments(
trade: Trade<Currency, Currency, TradeType> | undefined,
allowedSlippage: Percent,
recipientAddressOrName: string | null | undefined,
signatureData: SignatureData | null | undefined,
deadline: BigNumber | undefined,
feeOptions: FeeOptions | undefined
): SwapCall[] {
const { account, chainId, provider } = useWeb3React()
const { address: recipientAddress } = useENS(recipientAddressOrName)
const recipient = recipientAddressOrName === null ? account : recipientAddress
const argentWalletContract = useArgentWalletContract()
return useMemo(() => {
if (!trade || !recipient || !provider || !account || !chainId || !deadline) return []
const swapRouterAddress = chainId ? SWAP_ROUTER_ADDRESSES[chainId] : undefined
if (!swapRouterAddress) return []
const { value, calldata } = SwapRouter.swapCallParameters(trade, {
fee: feeOptions,
recipient,
slippageTolerance: allowedSlippage,
...(signatureData
? {
inputTokenPermit:
'allowed' in signatureData
? {
expiry: signatureData.deadline,
nonce: signatureData.nonce,
s: signatureData.s,
r: signatureData.r,
v: signatureData.v as any,
}
: {
deadline: signatureData.deadline,
amount: signatureData.amount,
s: signatureData.s,
r: signatureData.r,
v: signatureData.v as any,
},
}
: {}),
deadlineOrPreviousBlockhash: deadline.toString(),
})
if (argentWalletContract && trade.inputAmount.currency.isToken) {
return [
{
address: argentWalletContract.address,
calldata: argentWalletContract.interface.encodeFunctionData('wc_multiCall', [
[
approveAmountCalldata(trade.maximumAmountIn(allowedSlippage), swapRouterAddress),
{
to: swapRouterAddress,
value,
data: calldata,
},
],
]),
value: '0x0',
},
]
}
return [
{
address: swapRouterAddress,
calldata,
value,
},
]
}, [
account,
allowedSlippage,
argentWalletContract,
chainId,
deadline,
feeOptions,
provider,
recipient,
signatureData,
trade,
])
}
import { Trade } from '@uniswap/router-sdk' import { Trade } from '@uniswap/router-sdk'
import { Currency, Percent, TradeType } from '@uniswap/sdk-core' import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { usePermit2Enabled } from 'featureFlags/flags/permit2'
import { PermitSignature } from 'hooks/usePermitAllowance' import { PermitSignature } from 'hooks/usePermitAllowance'
import { SwapCallbackState, useSwapCallback as useLibSwapCallBack } from 'lib/hooks/swap/useSwapCallback' import { useMemo } from 'react'
import { ReactNode, useMemo } from 'react'
import { useTransactionAdder } from '../state/transactions/hooks' import { useTransactionAdder } from '../state/transactions/hooks'
import { TransactionType } from '../state/transactions/types' import { TransactionType } from '../state/transactions/types'
import { currencyId } from '../utils/currencyId' import { currencyId } from '../utils/currencyId'
import useENS from './useENS'
import { SignatureData } from './useERC20Permit'
import useTransactionDeadline from './useTransactionDeadline' import useTransactionDeadline from './useTransactionDeadline'
import { useUniversalRouterSwapCallback } from './useUniversalRouter' import { useUniversalRouterSwapCallback } from './useUniversalRouter'
...@@ -19,37 +14,18 @@ import { useUniversalRouterSwapCallback } from './useUniversalRouter' ...@@ -19,37 +14,18 @@ import { useUniversalRouterSwapCallback } from './useUniversalRouter'
export function useSwapCallback( export function useSwapCallback(
trade: Trade<Currency, Currency, TradeType> | 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
signatureData: SignatureData | undefined | null,
permitSignature: PermitSignature | undefined permitSignature: PermitSignature | undefined
): { state: SwapCallbackState; callback: null | (() => Promise<string>); error: ReactNode | null } { ): { callback: null | (() => Promise<string>) } {
const { account } = useWeb3React()
const deadline = useTransactionDeadline() const deadline = useTransactionDeadline()
const addTransaction = useTransactionAdder() const addTransaction = useTransactionAdder()
const { address: recipientAddress } = useENS(recipientAddressOrName) const universalRouterSwapCallback = useUniversalRouterSwapCallback(trade, {
const recipient = recipientAddressOrName === null ? account : recipientAddress
const permit2Enabled = usePermit2Enabled()
const {
state,
callback: libCallback,
error,
} = useLibSwapCallBack({
trade: permit2Enabled ? undefined : trade,
allowedSlippage,
recipientAddressOrName: recipient,
signatureData,
deadline,
})
const universalRouterSwapCallback = useUniversalRouterSwapCallback(permit2Enabled ? trade : undefined, {
slippageTolerance: allowedSlippage, slippageTolerance: allowedSlippage,
deadline, deadline,
permit: permitSignature, permit: permitSignature,
}) })
const swapCallback = permit2Enabled ? universalRouterSwapCallback : libCallback const swapCallback = universalRouterSwapCallback
const callback = useMemo(() => { const callback = useMemo(() => {
if (!trade || !swapCallback) return null if (!trade || !swapCallback) return null
...@@ -82,8 +58,6 @@ export function useSwapCallback( ...@@ -82,8 +58,6 @@ export function useSwapCallback(
}, [addTransaction, allowedSlippage, swapCallback, trade]) }, [addTransaction, allowedSlippage, swapCallback, trade])
return { return {
state,
callback, callback,
error,
} }
} }
import { BigNumber } from '@ethersproject/bignumber'
import type { JsonRpcProvider, TransactionResponse } from '@ethersproject/providers'
// eslint-disable-next-line no-restricted-imports
import { t, Trans } from '@lingui/macro'
import { sendAnalyticsEvent } from '@uniswap/analytics'
import { SwapEventName } from '@uniswap/analytics-events'
import { Trade } from '@uniswap/router-sdk'
import { Currency, TradeType } from '@uniswap/sdk-core'
import { formatSwapSignedAnalyticsEventProperties } from 'lib/utils/analytics'
import { useMemo } from 'react'
import { calculateGasMargin } from 'utils/calculateGasMargin'
import isZero from 'utils/isZero'
import { swapErrorToUserReadableMessage } from 'utils/swapErrorToUserReadableMessage'
interface SwapCall {
address: string
calldata: string
value: string
}
interface SwapCallEstimate {
call: SwapCall
}
interface SuccessfulCall extends SwapCallEstimate {
call: SwapCall
gasEstimate: BigNumber
}
interface FailedCall extends SwapCallEstimate {
call: SwapCall
error: Error
}
class InvalidSwapError extends Error {}
// returns a function that will execute a swap, if the parameters are all valid
export default function useSendSwapTransaction(
account: string | null | undefined,
chainId: number | undefined,
provider: JsonRpcProvider | undefined,
trade: Trade<Currency, Currency, TradeType> | undefined, // trade to execute, required
swapCalls: SwapCall[]
): { callback: null | (() => Promise<TransactionResponse>) } {
return useMemo(() => {
if (!trade || !provider || !account || !chainId) {
return { callback: null }
}
return {
callback: async function onSwap(): Promise<TransactionResponse> {
const estimatedCalls: SwapCallEstimate[] = await Promise.all(
swapCalls.map((call) => {
const { address, calldata, value } = call
const tx =
!value || isZero(value)
? { from: account, to: address, data: calldata }
: {
from: account,
to: address,
data: calldata,
value,
}
return provider
.estimateGas(tx)
.then((gasEstimate) => {
return {
call,
gasEstimate,
}
})
.catch((gasError) => {
console.debug('Gas estimate failed, trying eth_call to extract error', call)
return provider
.call(tx)
.then((result) => {
console.debug('Unexpected successful call after failed estimate gas', call, gasError, result)
return { call, error: <Trans>Unexpected issue with estimating the gas. Please try again.</Trans> }
})
.catch((callError) => {
console.debug('Call threw error', call, callError)
return { call, error: swapErrorToUserReadableMessage(callError) }
})
})
})
)
// a successful estimation is a bignumber gas estimate and the next call is also a bignumber gas estimate
let bestCallOption: SuccessfulCall | SwapCallEstimate | undefined = estimatedCalls.find(
(el, ix, list): el is SuccessfulCall =>
'gasEstimate' in el && (ix === list.length - 1 || 'gasEstimate' in list[ix + 1])
)
// check if any calls errored with a recognizable error
if (!bestCallOption) {
const errorCalls = estimatedCalls.filter((call): call is FailedCall => 'error' in call)
if (errorCalls.length > 0) throw errorCalls[errorCalls.length - 1].error
const firstNoErrorCall = estimatedCalls.find<SwapCallEstimate>(
(call): call is SwapCallEstimate => !('error' in call)
)
if (!firstNoErrorCall) throw new Error(t`Unexpected error. Could not estimate gas for the swap.`)
bestCallOption = firstNoErrorCall
}
const {
call: { address, calldata, value },
} = bestCallOption
return provider
.getSigner()
.sendTransaction({
from: account,
to: address,
data: calldata,
// let the wallet try if we can't estimate the gas
...('gasEstimate' in bestCallOption ? { gasLimit: calculateGasMargin(bestCallOption.gasEstimate) } : {}),
...(value && !isZero(value) ? { value } : {}),
})
.then((response) => {
sendAnalyticsEvent(
SwapEventName.SWAP_SIGNED,
formatSwapSignedAnalyticsEventProperties({ trade, txHash: response.hash })
)
if (calldata !== response.data) {
sendAnalyticsEvent(SwapEventName.SWAP_MODIFIED_IN_WALLET, { txHash: response.hash })
throw new InvalidSwapError(
t`Your swap was modified through your wallet. If this was a mistake, please cancel immediately or risk losing your funds.`
)
}
return response
})
.catch((error) => {
// if the user rejected the tx, pass this along
if (error?.code === 4001) {
throw new Error(t`Transaction rejected`)
} else {
// otherwise, the error was unexpected and we need to convey that
console.error(`Swap failed`, error, address, calldata, value)
if (error instanceof InvalidSwapError) {
throw error
} else {
throw new Error(t`Swap failed: ${swapErrorToUserReadableMessage(error)}`)
}
}
})
},
}
}, [account, chainId, provider, swapCalls, trade])
}
import { Trade } from '@uniswap/router-sdk'
import { Currency, CurrencyAmount, Percent, Token, TradeType } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import { SWAP_ROUTER_ADDRESSES } from 'constants/addresses'
import { useMemo } from 'react'
import { useApproval } from '../useApproval'
// wraps useApproveCallback in the context of a swap
export default function useSwapApproval(
trade: Trade<Currency, Currency, TradeType> | undefined,
allowedSlippage: Percent,
useIsPendingApproval: (token?: Token, spender?: string) => boolean,
amount?: CurrencyAmount<Currency> // defaults to trade.maximumAmountIn(allowedSlippage)
) {
const { chainId } = useWeb3React()
const amountToApprove = useMemo(
() => amount || (trade && trade.inputAmount.currency.isToken ? trade.maximumAmountIn(allowedSlippage) : undefined),
[amount, trade, allowedSlippage]
)
const spender = chainId ? SWAP_ROUTER_ADDRESSES[chainId] : undefined
return useApproval(amountToApprove, spender, useIsPendingApproval)
}
// eslint-disable-next-line no-restricted-imports
import { BigNumber } from '@ethersproject/bignumber'
import type { TransactionResponse } from '@ethersproject/providers'
import { Trans } from '@lingui/macro'
import { Trade } from '@uniswap/router-sdk'
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
import { FeeOptions } from '@uniswap/v3-sdk'
import { useWeb3React } from '@web3-react/core'
import useENS from 'hooks/useENS'
import { SignatureData } from 'hooks/useERC20Permit'
import { useSwapCallArguments } from 'hooks/useSwapCallArguments'
import { ReactNode, useMemo } from 'react'
import useSendSwapTransaction from './useSendSwapTransaction'
export enum SwapCallbackState {
INVALID,
LOADING,
VALID,
}
interface UseSwapCallbackReturns {
state: SwapCallbackState
callback?: () => Promise<TransactionResponse>
error?: ReactNode
}
interface UseSwapCallbackArgs {
trade: Trade<Currency, Currency, TradeType> | undefined // trade to execute, required
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
signatureData: SignatureData | null | undefined
deadline: BigNumber | undefined
feeOptions?: FeeOptions
}
// 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
export function useSwapCallback({
trade,
allowedSlippage,
recipientAddressOrName,
signatureData,
deadline,
feeOptions,
}: UseSwapCallbackArgs): UseSwapCallbackReturns {
const { account, chainId, provider } = useWeb3React()
const swapCalls = useSwapCallArguments(
trade,
allowedSlippage,
recipientAddressOrName,
signatureData,
deadline,
feeOptions
)
const { callback } = useSendSwapTransaction(account, chainId, provider, trade, swapCalls)
const { address: recipientAddress } = useENS(recipientAddressOrName)
const recipient = recipientAddressOrName === null ? account : recipientAddress
return useMemo(() => {
if (!trade || !provider || !account || !chainId || !callback) {
return { state: SwapCallbackState.INVALID, error: <Trans>Missing dependencies</Trans> }
}
if (!recipient) {
if (recipientAddressOrName !== null) {
return { state: SwapCallbackState.INVALID, error: <Trans>Invalid recipient</Trans> }
} else {
return { state: SwapCallbackState.LOADING }
}
}
return {
state: SwapCallbackState.VALID,
callback: async () => callback(),
}
}, [trade, provider, account, chainId, callback, recipient, recipientAddressOrName])
}
This diff is collapsed.
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