Commit e35eefbe authored by Zach Pomerantz's avatar Zach Pomerantz Committed by GitHub

fix: only prompt for necessary approval/permit (#5575)

parent 049a7d1d
...@@ -19,7 +19,7 @@ export enum PermitState { ...@@ -19,7 +19,7 @@ export enum PermitState {
export interface Permit { export interface Permit {
state: PermitState state: PermitState
signature?: PermitSignature signature?: PermitSignature
callback?: () => Promise<{ callback?: (sPendingApproval: boolean) => Promise<{
response: ContractTransaction response: ContractTransaction
info: ApproveTransactionInfo info: ApproveTransactionInfo
} | void> } | void>
...@@ -29,10 +29,18 @@ export default function usePermit(amount?: CurrencyAmount<Token>, spender?: stri ...@@ -29,10 +29,18 @@ export default function usePermit(amount?: CurrencyAmount<Token>, spender?: stri
const { account } = useWeb3React() const { account } = useWeb3React()
const tokenAllowance = useTokenAllowance(amount?.currency, account, PERMIT2_ADDRESS) const tokenAllowance = useTokenAllowance(amount?.currency, account, PERMIT2_ADDRESS)
const updateTokenAllowance = useUpdateTokenAllowance(amount, PERMIT2_ADDRESS) const updateTokenAllowance = useUpdateTokenAllowance(amount, PERMIT2_ADDRESS)
const isAllowed = useMemo(
() => amount && (tokenAllowance?.greaterThan(amount) || tokenAllowance?.equalTo(amount)),
[amount, tokenAllowance]
)
const permitAllowance = usePermitAllowance(amount?.currency, spender) const permitAllowance = usePermitAllowance(amount?.currency, spender)
const [permitAllowanceAmount, setPermitAllowanceAmount] = useState(permitAllowance?.amount) const [permitAllowanceAmount, setPermitAllowanceAmount] = useState(permitAllowance?.amount)
useEffect(() => setPermitAllowanceAmount(permitAllowance?.amount), [permitAllowance?.amount]) useEffect(() => setPermitAllowanceAmount(permitAllowance?.amount), [permitAllowance?.amount])
const isPermitted = useMemo(
() => amount && permitAllowanceAmount?.gte(amount.quotient.toString()),
[amount, permitAllowanceAmount]
)
const [signature, setSignature] = useState<PermitSignature>() const [signature, setSignature] = useState<PermitSignature>()
const updatePermitAllowance = useUpdatePermitAllowance( const updatePermitAllowance = useUpdatePermitAllowance(
...@@ -41,12 +49,10 @@ export default function usePermit(amount?: CurrencyAmount<Token>, spender?: stri ...@@ -41,12 +49,10 @@ export default function usePermit(amount?: CurrencyAmount<Token>, spender?: stri
permitAllowance?.nonce, permitAllowance?.nonce,
setSignature setSignature
) )
const isSigned = useMemo(
const updateTokenAndPermitAllowance = useCallback(async () => { () => amount && signature?.details.token === amount?.currency.address && signature?.spender === spender,
const info = await updateTokenAllowance() [amount, signature?.details.token, signature?.spender, spender]
await updatePermitAllowance() )
return info
}, [updatePermitAllowance, updateTokenAllowance])
// Trigger a re-render if either tokenAllowance or signature expire. // Trigger a re-render if either tokenAllowance or signature expire.
useInterval( useInterval(
...@@ -64,27 +70,30 @@ export default function usePermit(amount?: CurrencyAmount<Token>, spender?: stri ...@@ -64,27 +70,30 @@ export default function usePermit(amount?: CurrencyAmount<Token>, spender?: stri
true true
) )
const callback = useCallback(
async (isPendingApproval: boolean) => {
let info
if (!isAllowed && !isPendingApproval) {
info = await updateTokenAllowance()
}
if (!isPermitted && !isSigned) {
await updatePermitAllowance()
}
return info
},
[isAllowed, isPermitted, isSigned, updatePermitAllowance, updateTokenAllowance]
)
return useMemo(() => { return useMemo(() => {
if (!amount || !tokenAllowance) { if (!amount || !tokenAllowance) {
return { state: PermitState.UNKNOWN } return { state: PermitState.UNKNOWN }
} else if (tokenAllowance.greaterThan(amount) || tokenAllowance.equalTo(amount)) { } else if (isAllowed) {
if (permitAllowanceAmount?.gte(amount.quotient.toString())) { if (isPermitted) {
return { state: PermitState.PERMITTED } return { state: PermitState.PERMITTED }
} else if (signature?.details.token === amount.currency.address && signature?.spender === spender) { } else if (isSigned) {
return { state: PermitState.PERMITTED, signature } return { state: PermitState.PERMITTED, signature }
} else {
return { state: PermitState.PERMIT_NEEDED, callback: updatePermitAllowance }
} }
} else {
return { state: PermitState.PERMIT_NEEDED, callback: updateTokenAndPermitAllowance }
} }
}, [ return { state: PermitState.PERMIT_NEEDED, callback }
amount, }, [amount, callback, isAllowed, isPermitted, isSigned, signature, tokenAllowance])
permitAllowanceAmount,
signature,
spender,
tokenAllowance,
updatePermitAllowance,
updateTokenAndPermitAllowance,
])
} }
...@@ -308,7 +308,7 @@ export default function Swap() { ...@@ -308,7 +308,7 @@ export default function Swap() {
const updatePermit = useCallback(async () => { const updatePermit = useCallback(async () => {
setIsPermitPending(true) setIsPermitPending(true)
try { try {
const approval = await permit.callback?.() const approval = await permit.callback?.(isApprovalPending)
if (approval) { if (approval) {
sendAnalyticsEvent(EventName.APPROVE_TOKEN_TXN_SUBMITTED, { sendAnalyticsEvent(EventName.APPROVE_TOKEN_TXN_SUBMITTED, {
chain_id: chainId, chain_id: chainId,
...@@ -326,7 +326,14 @@ export default function Swap() { ...@@ -326,7 +326,14 @@ export default function Swap() {
} finally { } finally {
setIsPermitPending(false) setIsPermitPending(false)
} }
}, [addTransaction, chainId, maximumAmountIn?.currency.address, maximumAmountIn?.currency.symbol, permit]) }, [
addTransaction,
chainId,
isApprovalPending,
maximumAmountIn?.currency.address,
maximumAmountIn?.currency.symbol,
permit,
])
// 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( const [approvalState, approveCallback] = useApproveCallbackFromTrade(
......
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