feat: use multicall for argent wallets in swap and v3 add liquidity (#1387)
* use argent wallet contract in swap callback * maybe working swap callback * chore(v3): trigger a breaking release BREAKING CHANGE: trigger a major release for the uniswap interface to indicate it now supports swapping and liquidity provision against uniswap protocol v3 * fix the value * improve the error coverage * retry more frequently, couple more error nits * the is argent call was being sketchy * get it working for add liquidity * `0x0` for v2 swaps too * small nits in position page * fix import * fix compiler error
This commit is contained in:
parent
99ad4ae44c
commit
562b402293
61
src/abis/argent-wallet-contract.json
Normal file
61
src/abis/argent-wallet-contract.json
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"internalType": "address",
|
||||||
|
"name": "to",
|
||||||
|
"type": "address"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "uint256",
|
||||||
|
"name": "value",
|
||||||
|
"type": "uint256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "bytes",
|
||||||
|
"name": "data",
|
||||||
|
"type": "bytes"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "_transactions",
|
||||||
|
"type": "tuple[]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "wc_multiCall",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bytes[]",
|
||||||
|
"name": "",
|
||||||
|
"type": "bytes[]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "nonpayable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bytes32",
|
||||||
|
"name": "_msgHash",
|
||||||
|
"type": "bytes32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"internalType": "bytes",
|
||||||
|
"name": "_signature",
|
||||||
|
"type": "bytes"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "isValidSignature",
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"internalType": "bytes4",
|
||||||
|
"name": "",
|
||||||
|
"type": "bytes4"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"stateMutability": "view",
|
||||||
|
"type": "function"
|
||||||
|
}
|
||||||
|
]
|
15
src/hooks/useArgentWalletContract.ts
Normal file
15
src/hooks/useArgentWalletContract.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { ArgentWalletContract } from '../abis/types'
|
||||||
|
import { useActiveWeb3React } from './web3'
|
||||||
|
import { useContract } from './useContract'
|
||||||
|
import useIsArgentWallet from './useIsArgentWallet'
|
||||||
|
import ArgentWalletContractABI from '../abis/argent-wallet-contract.json'
|
||||||
|
|
||||||
|
export function useArgentWalletContract(): ArgentWalletContract | null {
|
||||||
|
const { account } = useActiveWeb3React()
|
||||||
|
const isArgentWallet = useIsArgentWallet()
|
||||||
|
return useContract(
|
||||||
|
isArgentWallet ? account ?? undefined : undefined,
|
||||||
|
ArgentWalletContractABI,
|
||||||
|
true
|
||||||
|
) as ArgentWalletContract
|
||||||
|
}
|
@ -41,7 +41,7 @@ import { Quoter, UniswapV3Factory, UniswapV3Pool } from 'types/v3'
|
|||||||
import { NonfungiblePositionManager } from 'types/v3/NonfungiblePositionManager'
|
import { NonfungiblePositionManager } from 'types/v3/NonfungiblePositionManager'
|
||||||
import { V3Migrator } from 'types/v3/V3Migrator'
|
import { V3Migrator } from 'types/v3/V3Migrator'
|
||||||
import { getContract } from 'utils'
|
import { getContract } from 'utils'
|
||||||
import { ArgentWalletDetector, EnsPublicResolver, EnsRegistrar, Erc20, Multicall2, Weth } from '../abis/types'
|
import { Erc20, ArgentWalletDetector, EnsPublicResolver, EnsRegistrar, Multicall2, Weth } from '../abis/types'
|
||||||
import { UNI } from '../constants/tokens'
|
import { UNI } from '../constants/tokens'
|
||||||
import { useActiveWeb3React } from './web3'
|
import { useActiveWeb3React } from './web3'
|
||||||
|
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { useMemo } from 'react'
|
||||||
import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks'
|
import { NEVER_RELOAD, useSingleCallResult } from '../state/multicall/hooks'
|
||||||
import { useActiveWeb3React } from './web3'
|
import { useActiveWeb3React } from './web3'
|
||||||
import { useArgentWalletDetectorContract } from './useContract'
|
import { useArgentWalletDetectorContract } from './useContract'
|
||||||
@ -5,6 +6,7 @@ import { useArgentWalletDetectorContract } from './useContract'
|
|||||||
export default function useIsArgentWallet(): boolean {
|
export default function useIsArgentWallet(): boolean {
|
||||||
const { account } = useActiveWeb3React()
|
const { account } = useActiveWeb3React()
|
||||||
const argentWalletDetector = useArgentWalletDetectorContract()
|
const argentWalletDetector = useArgentWalletDetectorContract()
|
||||||
const call = useSingleCallResult(argentWalletDetector, 'isArgentWallet', [account ?? undefined], NEVER_RELOAD)
|
const inputs = useMemo(() => [account ?? undefined], [account])
|
||||||
|
const call = useSingleCallResult(argentWalletDetector, 'isArgentWallet', inputs, NEVER_RELOAD)
|
||||||
return call?.result?.[0] ?? false
|
return call?.result?.[0] ?? false
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,8 @@ export default function useSocksBalance(): JSBI | undefined {
|
|||||||
const { account } = useActiveWeb3React()
|
const { account } = useActiveWeb3React()
|
||||||
const socksContract = useSocksController()
|
const socksContract = useSocksController()
|
||||||
|
|
||||||
const { result } = useSingleCallResult(socksContract, 'balanceOf', [account ?? undefined], NEVER_RELOAD)
|
const inputs = useMemo(() => [account ?? undefined], [account])
|
||||||
|
const { result } = useSingleCallResult(socksContract, 'balanceOf', inputs, NEVER_RELOAD)
|
||||||
const data = result?.[0]
|
const data = result?.[0]
|
||||||
return data ? JSBI.BigInt(data.toString()) : undefined
|
return data ? JSBI.BigInt(data.toString()) : undefined
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,13 @@ import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
|||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { SWAP_ROUTER_ADDRESSES } from '../constants/addresses'
|
import { SWAP_ROUTER_ADDRESSES } from '../constants/addresses'
|
||||||
import { calculateGasMargin } from '../utils/calculateGasMargin'
|
import { calculateGasMargin } from '../utils/calculateGasMargin'
|
||||||
|
import approveAmountCalldata from '../utils/approveAmountCalldata'
|
||||||
import { getTradeVersion } from '../utils/getTradeVersion'
|
import { getTradeVersion } from '../utils/getTradeVersion'
|
||||||
import { useTransactionAdder } from '../state/transactions/hooks'
|
import { useTransactionAdder } from '../state/transactions/hooks'
|
||||||
import { isAddress, shortenAddress } from '../utils'
|
import { isAddress, shortenAddress } from '../utils'
|
||||||
import isZero from '../utils/isZero'
|
import isZero from '../utils/isZero'
|
||||||
import { useActiveWeb3React } from './web3'
|
import { useActiveWeb3React } from './web3'
|
||||||
|
import { useArgentWalletContract } from './useArgentWalletContract'
|
||||||
import { useV2RouterContract } from './useContract'
|
import { useV2RouterContract } from './useContract'
|
||||||
import { SignatureData } from './useERC20Permit'
|
import { SignatureData } from './useERC20Permit'
|
||||||
import useTransactionDeadline from './useTransactionDeadline'
|
import useTransactionDeadline from './useTransactionDeadline'
|
||||||
@ -61,6 +63,7 @@ function useSwapCallArguments(
|
|||||||
const recipient = recipientAddressOrName === null ? account : recipientAddress
|
const recipient = recipientAddressOrName === null ? account : recipientAddress
|
||||||
const deadline = useTransactionDeadline()
|
const deadline = useTransactionDeadline()
|
||||||
const routerContract = useV2RouterContract()
|
const routerContract = useV2RouterContract()
|
||||||
|
const argentWalletContract = useArgentWalletContract()
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
if (!trade || !recipient || !library || !account || !chainId || !deadline) return []
|
if (!trade || !recipient || !library || !account || !chainId || !deadline) return []
|
||||||
@ -68,6 +71,7 @@ function useSwapCallArguments(
|
|||||||
if (trade instanceof V2Trade) {
|
if (trade instanceof V2Trade) {
|
||||||
if (!routerContract) return []
|
if (!routerContract) return []
|
||||||
const swapMethods = []
|
const swapMethods = []
|
||||||
|
|
||||||
swapMethods.push(
|
swapMethods.push(
|
||||||
Router.swapCallParameters(trade, {
|
Router.swapCallParameters(trade, {
|
||||||
feeOnTransfer: false,
|
feeOnTransfer: false,
|
||||||
@ -87,11 +91,30 @@ function useSwapCallArguments(
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return swapMethods.map(({ methodName, args, value }) => ({
|
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: value,
|
||||||
|
data: routerContract.interface.encodeFunctionData(methodName, args),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
value: '0x0',
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
address: routerContract.address,
|
address: routerContract.address,
|
||||||
calldata: routerContract.interface.encodeFunctionData(methodName, args),
|
calldata: routerContract.interface.encodeFunctionData(methodName, args),
|
||||||
value,
|
value,
|
||||||
}))
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
// trade is V3Trade
|
// trade is V3Trade
|
||||||
const swapRouterAddress = chainId ? SWAP_ROUTER_ADDRESSES[chainId] : undefined
|
const swapRouterAddress = chainId ? SWAP_ROUTER_ADDRESSES[chainId] : undefined
|
||||||
@ -122,7 +145,24 @@ function useSwapCallArguments(
|
|||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
})
|
})
|
||||||
|
if (argentWalletContract && trade.inputAmount.currency.isToken) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
address: argentWalletContract.address,
|
||||||
|
calldata: argentWalletContract.interface.encodeFunctionData('wc_multiCall', [
|
||||||
|
[
|
||||||
|
approveAmountCalldata(trade.maximumAmountIn(allowedSlippage), swapRouterAddress),
|
||||||
|
{
|
||||||
|
to: swapRouterAddress,
|
||||||
|
value: value,
|
||||||
|
data: calldata,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]),
|
||||||
|
value: '0x0',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
address: swapRouterAddress,
|
address: swapRouterAddress,
|
||||||
@ -131,7 +171,18 @@ function useSwapCallArguments(
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}, [account, allowedSlippage, chainId, deadline, library, recipient, routerContract, signatureData, trade])
|
}, [
|
||||||
|
account,
|
||||||
|
allowedSlippage,
|
||||||
|
argentWalletContract,
|
||||||
|
chainId,
|
||||||
|
deadline,
|
||||||
|
library,
|
||||||
|
recipient,
|
||||||
|
routerContract,
|
||||||
|
signatureData,
|
||||||
|
trade,
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,6 +6,7 @@ import { AlertTriangle, AlertCircle } from 'react-feather'
|
|||||||
import ReactGA from 'react-ga'
|
import ReactGA from 'react-ga'
|
||||||
import { ZERO_PERCENT } from '../../constants/misc'
|
import { ZERO_PERCENT } from '../../constants/misc'
|
||||||
import { NONFUNGIBLE_POSITION_MANAGER_ADDRESSES } from '../../constants/addresses'
|
import { NONFUNGIBLE_POSITION_MANAGER_ADDRESSES } from '../../constants/addresses'
|
||||||
|
import { useArgentWalletContract } from '../../hooks/useArgentWalletContract'
|
||||||
import { useV3NFTPositionManagerContract } from '../../hooks/useContract'
|
import { useV3NFTPositionManagerContract } from '../../hooks/useContract'
|
||||||
import { RouteComponentProps } from 'react-router-dom'
|
import { RouteComponentProps } from 'react-router-dom'
|
||||||
import { Text } from 'rebass'
|
import { Text } from 'rebass'
|
||||||
@ -18,6 +19,7 @@ import CurrencyInputPanel from '../../components/CurrencyInputPanel'
|
|||||||
import { RowBetween, RowFixed } from '../../components/Row'
|
import { RowBetween, RowFixed } from '../../components/Row'
|
||||||
import { useIsSwapUnsupported } from '../../hooks/useIsSwapUnsupported'
|
import { useIsSwapUnsupported } from '../../hooks/useIsSwapUnsupported'
|
||||||
import { useUSDCValue } from '../../hooks/useUSDCPrice'
|
import { useUSDCValue } from '../../hooks/useUSDCPrice'
|
||||||
|
import approveAmountCalldata from '../../utils/approveAmountCalldata'
|
||||||
import { calculateGasMargin } from '../../utils/calculateGasMargin'
|
import { calculateGasMargin } from '../../utils/calculateGasMargin'
|
||||||
import Review from './Review'
|
import Review from './Review'
|
||||||
import { useActiveWeb3React } from '../../hooks/web3'
|
import { useActiveWeb3React } from '../../hooks/web3'
|
||||||
@ -170,13 +172,15 @@ export default function AddLiquidity({
|
|||||||
{}
|
{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const argentWalletContract = useArgentWalletContract()
|
||||||
|
|
||||||
// check whether the user has approved the router on the tokens
|
// check whether the user has approved the router on the tokens
|
||||||
const [approvalA, approveACallback] = useApproveCallback(
|
const [approvalA, approveACallback] = useApproveCallback(
|
||||||
parsedAmounts[Field.CURRENCY_A],
|
argentWalletContract ? undefined : parsedAmounts[Field.CURRENCY_A],
|
||||||
chainId ? NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId] : undefined
|
chainId ? NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId] : undefined
|
||||||
)
|
)
|
||||||
const [approvalB, approveBCallback] = useApproveCallback(
|
const [approvalB, approveBCallback] = useApproveCallback(
|
||||||
parsedAmounts[Field.CURRENCY_B],
|
argentWalletContract ? undefined : parsedAmounts[Field.CURRENCY_B],
|
||||||
chainId ? NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId] : undefined
|
chainId ? NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId] : undefined
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -208,12 +212,36 @@ export default function AddLiquidity({
|
|||||||
createPool: noLiquidity,
|
createPool: noLiquidity,
|
||||||
})
|
})
|
||||||
|
|
||||||
const txn = {
|
let txn: { to: string; data: string; value: string } = {
|
||||||
to: NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId],
|
to: NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId],
|
||||||
data: calldata,
|
data: calldata,
|
||||||
value,
|
value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (argentWalletContract) {
|
||||||
|
const amountA = parsedAmounts[Field.CURRENCY_A]
|
||||||
|
const amountB = parsedAmounts[Field.CURRENCY_B]
|
||||||
|
const batch = [
|
||||||
|
...(amountA && amountA.currency.isToken
|
||||||
|
? [approveAmountCalldata(amountA, NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId])]
|
||||||
|
: []),
|
||||||
|
...(amountB && amountB.currency.isToken
|
||||||
|
? [approveAmountCalldata(amountB, NONFUNGIBLE_POSITION_MANAGER_ADDRESSES[chainId])]
|
||||||
|
: []),
|
||||||
|
{
|
||||||
|
to: txn.to,
|
||||||
|
data: txn.data,
|
||||||
|
value: txn.value,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const data = argentWalletContract.interface.encodeFunctionData('wc_multiCall', [batch])
|
||||||
|
txn = {
|
||||||
|
to: argentWalletContract.address,
|
||||||
|
data,
|
||||||
|
value: '0x0',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setAttemptingTxn(true)
|
setAttemptingTxn(true)
|
||||||
|
|
||||||
library
|
library
|
||||||
@ -244,6 +272,7 @@ export default function AddLiquidity({
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
console.error('Failed to send transaction', error)
|
||||||
setAttemptingTxn(false)
|
setAttemptingTxn(false)
|
||||||
// we only care if the error is something _other_ than the user rejected the tx
|
// we only care if the error is something _other_ than the user rejected the tx
|
||||||
if (error?.code !== 4001) {
|
if (error?.code !== 4001) {
|
||||||
@ -351,8 +380,10 @@ export default function AddLiquidity({
|
|||||||
)
|
)
|
||||||
|
|
||||||
// we need an existence check on parsed amounts for single-asset deposits
|
// we need an existence check on parsed amounts for single-asset deposits
|
||||||
const showApprovalA = approvalA !== ApprovalState.APPROVED && !!parsedAmounts[Field.CURRENCY_A]
|
const showApprovalA =
|
||||||
const showApprovalB = approvalB !== ApprovalState.APPROVED && !!parsedAmounts[Field.CURRENCY_B]
|
!argentWalletContract && approvalA !== ApprovalState.APPROVED && !!parsedAmounts[Field.CURRENCY_A]
|
||||||
|
const showApprovalB =
|
||||||
|
!argentWalletContract && approvalB !== ApprovalState.APPROVED && !!parsedAmounts[Field.CURRENCY_B]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ScrollablePage>
|
<ScrollablePage>
|
||||||
@ -418,7 +449,7 @@ export default function AddLiquidity({
|
|||||||
id="add-liquidity-input-tokena"
|
id="add-liquidity-input-tokena"
|
||||||
showCommonBases
|
showCommonBases
|
||||||
/>
|
/>
|
||||||
<div style={{ width: '12px' }}></div>
|
<div style={{ width: '12px' }} />
|
||||||
|
|
||||||
<CurrencyDropdown
|
<CurrencyDropdown
|
||||||
value={formattedAmounts[Field.CURRENCY_B]}
|
value={formattedAmounts[Field.CURRENCY_B]}
|
||||||
@ -571,7 +602,7 @@ export default function AddLiquidity({
|
|||||||
<TYPE.body fontWeight={500} textAlign="center" fontSize={20}>
|
<TYPE.body fontWeight={500} textAlign="center" fontSize={20}>
|
||||||
<HoverInlineText
|
<HoverInlineText
|
||||||
maxCharacters={20}
|
maxCharacters={20}
|
||||||
text={invertPrice ? price.invert().toSignificant(5) : price.toSignificant(5)}
|
text={invertPrice ? price.invert().toSignificant(6) : price.toSignificant(6)}
|
||||||
/>{' '}
|
/>{' '}
|
||||||
</TYPE.body>
|
</TYPE.body>
|
||||||
<TYPE.main fontWeight={500} textAlign="center" fontSize={12}>
|
<TYPE.main fontWeight={500} textAlign="center" fontSize={12}>
|
||||||
@ -697,8 +728,8 @@ export default function AddLiquidity({
|
|||||||
}}
|
}}
|
||||||
disabled={
|
disabled={
|
||||||
!isValid ||
|
!isValid ||
|
||||||
(approvalA !== ApprovalState.APPROVED && !depositADisabled) ||
|
(!argentWalletContract && approvalA !== ApprovalState.APPROVED && !depositADisabled) ||
|
||||||
(approvalB !== ApprovalState.APPROVED && !depositBDisabled)
|
(!argentWalletContract && approvalB !== ApprovalState.APPROVED && !depositBDisabled)
|
||||||
}
|
}
|
||||||
error={!isValid && !!parsedAmounts[Field.CURRENCY_A] && !!parsedAmounts[Field.CURRENCY_B]}
|
error={!isValid && !!parsedAmounts[Field.CURRENCY_A] && !!parsedAmounts[Field.CURRENCY_B]}
|
||||||
>
|
>
|
||||||
|
@ -166,7 +166,7 @@ function CurrentPriceCard({
|
|||||||
<AutoColumn gap="8px" justify="center">
|
<AutoColumn gap="8px" justify="center">
|
||||||
<ExtentsText>{t('Current price')}</ExtentsText>
|
<ExtentsText>{t('Current price')}</ExtentsText>
|
||||||
<TYPE.mediumHeader textAlign="center">
|
<TYPE.mediumHeader textAlign="center">
|
||||||
{(inverted ? pool.token1Price : pool.token0Price).toSignificant(5)}{' '}
|
{(inverted ? pool.token1Price : pool.token0Price).toSignificant(6)}{' '}
|
||||||
</TYPE.mediumHeader>
|
</TYPE.mediumHeader>
|
||||||
<ExtentsText>{currencyQuote?.symbol + ' per ' + currencyBase?.symbol}</ExtentsText>
|
<ExtentsText>{currencyQuote?.symbol + ' per ' + currencyBase?.symbol}</ExtentsText>
|
||||||
</AutoColumn>
|
</AutoColumn>
|
||||||
|
@ -33,6 +33,7 @@ import { ApprovalState, useApproveCallbackFromTrade } from '../../hooks/useAppro
|
|||||||
import { V3TradeState } from '../../hooks/useBestV3Trade'
|
import { V3TradeState } from '../../hooks/useBestV3Trade'
|
||||||
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 { useIsSwapUnsupported } from '../../hooks/useIsSwapUnsupported'
|
import { useIsSwapUnsupported } from '../../hooks/useIsSwapUnsupported'
|
||||||
import { useSwapCallback } from '../../hooks/useSwapCallback'
|
import { useSwapCallback } from '../../hooks/useSwapCallback'
|
||||||
import useToggledVersion, { Version } from '../../hooks/useToggledVersion'
|
import useToggledVersion, { Version } from '../../hooks/useToggledVersion'
|
||||||
@ -302,9 +303,12 @@ export default function Swap({ history }: RouteComponentProps) {
|
|||||||
)
|
)
|
||||||
}, [priceImpact, trade])
|
}, [priceImpact, trade])
|
||||||
|
|
||||||
|
const isArgentWallet = useIsArgentWallet()
|
||||||
|
|
||||||
// show approve flow when: no error on inputs, not approved or pending, or approved in current session
|
// show approve flow when: no error on inputs, not approved or pending, or approved in current session
|
||||||
// never show if price impact is above threshold in non expert mode
|
// never show if price impact is above threshold in non expert mode
|
||||||
const showApproveFlow =
|
const showApproveFlow =
|
||||||
|
!isArgentWallet &&
|
||||||
!swapInputError &&
|
!swapInputError &&
|
||||||
(approvalState === ApprovalState.NOT_APPROVED ||
|
(approvalState === ApprovalState.NOT_APPROVED ||
|
||||||
approvalState === ApprovalState.PENDING ||
|
approvalState === ApprovalState.PENDING ||
|
||||||
|
32
src/utils/approveAmountCalldata.ts
Normal file
32
src/utils/approveAmountCalldata.ts
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { Interface } from '@ethersproject/abi'
|
||||||
|
import { Currency, CurrencyAmount } from '@uniswap/sdk-core'
|
||||||
|
import { toHex } from '@uniswap/v3-sdk'
|
||||||
|
import { Erc20Interface } from '../abis/types/Erc20'
|
||||||
|
|
||||||
|
const ERC20_INTERFACE = new Interface([
|
||||||
|
{
|
||||||
|
constant: false,
|
||||||
|
inputs: [
|
||||||
|
{ name: '_spender', type: 'address' },
|
||||||
|
{ name: '_value', type: 'uint256' },
|
||||||
|
],
|
||||||
|
name: 'approve',
|
||||||
|
outputs: [{ name: '', type: 'bool' }],
|
||||||
|
payable: false,
|
||||||
|
stateMutability: 'nonpayable',
|
||||||
|
type: 'function',
|
||||||
|
},
|
||||||
|
]) as Erc20Interface
|
||||||
|
|
||||||
|
export default function approveAmountCalldata(
|
||||||
|
amount: CurrencyAmount<Currency>,
|
||||||
|
spender: string
|
||||||
|
): { to: string; data: string; value: '0x0' } {
|
||||||
|
if (!amount.currency.isToken) throw new Error('Must call with an amount of token')
|
||||||
|
const approveData = ERC20_INTERFACE.encodeFunctionData('approve', [spender, toHex(amount.quotient)])
|
||||||
|
return {
|
||||||
|
to: amount.currency.address,
|
||||||
|
data: approveData,
|
||||||
|
value: '0x0',
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user