feat(widgets): support convenience fee in trades (#3219)
* feat(widgets): support convenience fee in trades * update call signature * pr feedback
This commit is contained in:
parent
921310ef52
commit
8064dd8ede
@ -2,7 +2,7 @@ import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { SwapRouter, Trade } from '@uniswap/router-sdk'
|
||||
import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
|
||||
import { Router as V2SwapRouter, Trade as V2Trade } from '@uniswap/v2-sdk'
|
||||
import { SwapRouter as V3SwapRouter, Trade as V3Trade } from '@uniswap/v3-sdk'
|
||||
import { FeeOptions, SwapRouter as V3SwapRouter, Trade as V3Trade } from '@uniswap/v3-sdk'
|
||||
import { SWAP_ROUTER_ADDRESSES, V3_ROUTER_ADDRESS } from 'constants/addresses'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useMemo } from 'react'
|
||||
@ -36,7 +36,8 @@ export function useSwapCallArguments(
|
||||
allowedSlippage: Percent,
|
||||
recipientAddressOrName: string | null | undefined,
|
||||
signatureData: SignatureData | null | undefined,
|
||||
deadline: BigNumber | undefined
|
||||
deadline: BigNumber | undefined,
|
||||
fee: FeeOptions | undefined
|
||||
): SwapCall[] {
|
||||
const { account, chainId, library } = useActiveWeb3React()
|
||||
|
||||
@ -98,6 +99,7 @@ export function useSwapCallArguments(
|
||||
} else {
|
||||
// swap options shared by v3 and v2+v3 swap routers
|
||||
const sharedSwapOptions = {
|
||||
fee,
|
||||
recipient,
|
||||
slippageTolerance: allowedSlippage,
|
||||
...(signatureData
|
||||
@ -167,15 +169,16 @@ export function useSwapCallArguments(
|
||||
]
|
||||
}
|
||||
}, [
|
||||
trade,
|
||||
recipient,
|
||||
library,
|
||||
account,
|
||||
chainId,
|
||||
deadline,
|
||||
routerContract,
|
||||
allowedSlippage,
|
||||
argentWalletContract,
|
||||
chainId,
|
||||
deadline,
|
||||
fee,
|
||||
library,
|
||||
recipient,
|
||||
routerContract,
|
||||
signatureData,
|
||||
trade,
|
||||
])
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ export function useSwapCallback(
|
||||
state,
|
||||
callback: libCallback,
|
||||
error,
|
||||
} = useLibSwapCallBack(trade, allowedSlippage, recipient, signatureData, deadline)
|
||||
} = useLibSwapCallBack({ trade, allowedSlippage, recipientAddressOrName: recipient, signatureData, deadline })
|
||||
|
||||
const callback = useMemo(() => {
|
||||
if (!libCallback || !trade) {
|
||||
|
@ -51,6 +51,7 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
|
||||
currencies: { [Field.INPUT]: inputCurrency },
|
||||
currencyBalances: { [Field.INPUT]: inputCurrencyBalance },
|
||||
currencyAmounts: { [Field.INPUT]: inputCurrencyAmount, [Field.OUTPUT]: outputCurrencyAmount },
|
||||
fee,
|
||||
} = useSwapInfo()
|
||||
|
||||
const independentField = useAtomValue(independentFieldAtom)
|
||||
@ -118,13 +119,14 @@ export default function SwapButton({ disabled }: SwapButtonProps) {
|
||||
const { signatureData } = useERC20PermitFromTrade(optimizedTrade, allowedSlippage, deadline)
|
||||
|
||||
// the callback to execute the swap
|
||||
const { callback: swapCallback } = useSwapCallback(
|
||||
optimizedTrade,
|
||||
const { callback: swapCallback } = useSwapCallback({
|
||||
trade: optimizedTrade,
|
||||
allowedSlippage,
|
||||
account ?? null,
|
||||
recipientAddressOrName: account ?? null,
|
||||
signatureData,
|
||||
deadline
|
||||
)
|
||||
deadline,
|
||||
fee,
|
||||
})
|
||||
|
||||
//@TODO(ianlapham): add a loading state, process errors
|
||||
const setDisplayTxHash = useUpdateAtom(displayTxHashAtom)
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { TokenInfo } from '@uniswap/token-lists'
|
||||
import { useAtom } from 'jotai'
|
||||
import useSwapDefaults from 'lib/hooks/swap/useSwapDefaults'
|
||||
import { SwapInfoUpdater } from 'lib/hooks/swap/useSwapInfo'
|
||||
import useSyncConvenienceFee from 'lib/hooks/swap/useSyncConvenienceFee'
|
||||
import useSyncSwapDefaults from 'lib/hooks/swap/useSyncSwapDefaults'
|
||||
import { usePendingTransactions } from 'lib/hooks/transactions'
|
||||
import useActiveWeb3React from 'lib/hooks/useActiveWeb3React'
|
||||
import useTokenList from 'lib/hooks/useTokenList'
|
||||
@ -47,7 +48,8 @@ export interface SwapProps {
|
||||
|
||||
export default function Swap(props: SwapProps) {
|
||||
useTokenList(props.tokenList)
|
||||
useSwapDefaults(props)
|
||||
useSyncSwapDefaults(props)
|
||||
useSyncConvenienceFee(props)
|
||||
|
||||
const { active, account } = useActiveWeb3React()
|
||||
const [boundary, setBoundary] = useState<HTMLDivElement | null>(null)
|
||||
|
@ -3,6 +3,7 @@ import { BigNumber } from '@ethersproject/bignumber'
|
||||
import { TransactionResponse } from '@ethersproject/providers'
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Percent } from '@uniswap/sdk-core'
|
||||
import { FeeOptions } from '@uniswap/v3-sdk'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import useENS from 'hooks/useENS'
|
||||
import { SignatureData } from 'hooks/useERC20Permit'
|
||||
@ -17,18 +18,33 @@ export enum SwapCallbackState {
|
||||
VALID,
|
||||
}
|
||||
|
||||
interface UseSwapCallbackReturns {
|
||||
state: SwapCallbackState
|
||||
callback: null | (() => Promise<TransactionResponse>)
|
||||
error: ReactNode | null
|
||||
}
|
||||
interface UseSwapCallbackArgs {
|
||||
trade: AnyTrade | 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
|
||||
fee?: 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: AnyTrade | 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
|
||||
): { state: SwapCallbackState; callback: null | (() => Promise<TransactionResponse>); error: ReactNode | null } {
|
||||
export function useSwapCallback({
|
||||
trade,
|
||||
allowedSlippage,
|
||||
recipientAddressOrName,
|
||||
signatureData,
|
||||
deadline,
|
||||
fee,
|
||||
}: UseSwapCallbackArgs): UseSwapCallbackReturns {
|
||||
const { account, chainId, library } = useActiveWeb3React()
|
||||
|
||||
const swapCalls = useSwapCallArguments(trade, allowedSlippage, recipientAddressOrName, signatureData, deadline)
|
||||
const swapCalls = useSwapCallArguments(trade, allowedSlippage, recipientAddressOrName, signatureData, deadline, fee)
|
||||
const { callback } = useSendSwapTransaction(account, chainId, library, trade, swapCalls)
|
||||
|
||||
const { address: recipientAddress } = useENS(recipientAddressOrName)
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { Trans } from '@lingui/macro'
|
||||
import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
|
||||
import { FeeOptions } from '@uniswap/v3-sdk'
|
||||
import useAutoSlippageTolerance from 'hooks/useAutoSlippageTolerance'
|
||||
import { atom } from 'jotai'
|
||||
import { useAtomValue, useUpdateAtom } from 'jotai/utils'
|
||||
import { useCurrencyBalances } from 'lib/hooks/useCurrencyBalance'
|
||||
import { maxSlippageAtom } from 'lib/state/settings'
|
||||
import { Field, swapAtom } from 'lib/state/swap'
|
||||
import { DEFAULT_FEE_OPTIONS, feeOptionsAtom, Field, swapAtom } from 'lib/state/swap'
|
||||
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
|
||||
import { ReactNode, useEffect, useMemo } from 'react'
|
||||
import { InterfaceTrade, TradeState } from 'state/routing/types'
|
||||
@ -23,6 +24,7 @@ interface SwapInfo {
|
||||
state: TradeState
|
||||
}
|
||||
allowedSlippage: Percent
|
||||
fee: FeeOptions
|
||||
}
|
||||
|
||||
const BAD_RECIPIENT_ADDRESSES: { [address: string]: true } = {
|
||||
@ -42,6 +44,8 @@ function useComputeSwapInfo(): SwapInfo {
|
||||
[Field.OUTPUT]: outputCurrency,
|
||||
} = useAtomValue(swapAtom)
|
||||
|
||||
const fee = useAtomValue(feeOptionsAtom)
|
||||
|
||||
const to = account
|
||||
|
||||
const relevantTokenBalances = useCurrencyBalances(
|
||||
@ -139,8 +143,9 @@ function useComputeSwapInfo(): SwapInfo {
|
||||
inputError,
|
||||
trade,
|
||||
allowedSlippage,
|
||||
fee,
|
||||
}),
|
||||
[currencies, currencyBalances, currencyAmounts, inputError, trade, allowedSlippage]
|
||||
[currencies, currencyBalances, currencyAmounts, inputError, trade, allowedSlippage, fee]
|
||||
)
|
||||
}
|
||||
|
||||
@ -150,6 +155,7 @@ const swapInfoAtom = atom<SwapInfo>({
|
||||
currencyAmounts: {},
|
||||
trade: { state: TradeState.INVALID },
|
||||
allowedSlippage: new Percent(0),
|
||||
fee: DEFAULT_FEE_OPTIONS,
|
||||
})
|
||||
|
||||
export function SwapInfoUpdater() {
|
||||
|
35
src/lib/hooks/swap/useSyncConvenienceFee.ts
Normal file
35
src/lib/hooks/swap/useSyncConvenienceFee.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { Percent } from '@uniswap/sdk-core'
|
||||
import useActiveWeb3React from 'hooks/useActiveWeb3React'
|
||||
import { useUpdateAtom } from 'jotai/utils'
|
||||
import { DEFAULT_FEE_OPTIONS, feeOptionsAtom } from 'lib/state/swap'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
interface FeeOptionsArgs {
|
||||
convenienceFee?: number
|
||||
convenienceFeeRecipient?: string | string | { [chainId: number]: string }
|
||||
}
|
||||
|
||||
export default function useSyncConvenienceFee({ convenienceFee, convenienceFeeRecipient }: FeeOptionsArgs) {
|
||||
const { chainId } = useActiveWeb3React()
|
||||
const updateFeeOptions = useUpdateAtom(feeOptionsAtom)
|
||||
|
||||
useEffect(() => {
|
||||
if (convenienceFee && convenienceFeeRecipient) {
|
||||
if (typeof convenienceFeeRecipient === 'string') {
|
||||
updateFeeOptions({
|
||||
fee: new Percent(convenienceFee, 10_000),
|
||||
recipient: convenienceFeeRecipient,
|
||||
})
|
||||
return
|
||||
}
|
||||
if (chainId && convenienceFeeRecipient[chainId]) {
|
||||
updateFeeOptions({
|
||||
fee: new Percent(convenienceFee, 10_000),
|
||||
recipient: convenienceFeeRecipient[chainId],
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
updateFeeOptions(DEFAULT_FEE_OPTIONS)
|
||||
}, [chainId, convenienceFee, convenienceFeeRecipient, updateFeeOptions])
|
||||
}
|
@ -31,7 +31,7 @@ interface UseSwapDefaultsArgs {
|
||||
defaultOutputAmount?: string
|
||||
}
|
||||
|
||||
export default function useSwapDefaults({
|
||||
export default function useSyncSwapDefaults({
|
||||
defaultInputAddress,
|
||||
defaultInputAmount,
|
||||
defaultOutputAddress,
|
@ -1,4 +1,5 @@
|
||||
import { Currency } from '@uniswap/sdk-core'
|
||||
import { Currency, Percent } from '@uniswap/sdk-core'
|
||||
import { FeeOptions } from '@uniswap/v3-sdk'
|
||||
import { SupportedChainId } from 'constants/chains'
|
||||
import { nativeOnChain } from 'constants/tokens'
|
||||
import { atom } from 'jotai'
|
||||
@ -27,3 +28,9 @@ export const independentFieldAtom = pickAtom(swapAtom, 'independentField')
|
||||
|
||||
// If set to a transaction hash, that transaction will display in a status dialog.
|
||||
export const displayTxHashAtom = atom<string | undefined>(undefined)
|
||||
|
||||
export const DEFAULT_FEE_OPTIONS = {
|
||||
fee: new Percent(0),
|
||||
recipient: '',
|
||||
}
|
||||
export const feeOptionsAtom = atom<FeeOptions>(DEFAULT_FEE_OPTIONS)
|
||||
|
Loading…
Reference in New Issue
Block a user