Skip to content

Commit

Permalink
fix: only prompt for necessary approval/permit (#328)
Browse files Browse the repository at this point in the history
  • Loading branch information
zzmp authored Dec 7, 2022
1 parent a21b504 commit 2f0c5cf
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 32 deletions.
11 changes: 5 additions & 6 deletions src/components/Swap/SwapActionButton/Permit2Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ export default function PermitButton({
}: {
color: keyof Colors
trade?: InterfaceTrade
callback?: () => Promise<ApprovalTransactionInfo | void>
onSubmit: (submit?: () => Promise<ApprovalTransactionInfo | void>) => Promise<void>
callback?: (isPendingApproval: boolean) => Promise<ApprovalTransactionInfo | void>
onSubmit: (submit: () => Promise<ApprovalTransactionInfo | void>) => Promise<void>
}) {
const currency = trade?.inputAmount?.currency
const [isPending, setIsPending] = useState(false)
const [isFailed, setIsFailed] = useState(false)
const pendingApproval = usePendingApproval(currency?.isToken ? currency : undefined, PERMIT2_ADDRESS)
useEffect(() => {
// Reset pending/failed state if currency changes.
setIsPending(false)
Expand All @@ -37,17 +38,15 @@ export default function PermitButton({
const onClick = useCallback(async () => {
setIsPending(true)
try {
await onSubmit(callback)
await onSubmit(async () => await callback?.(Boolean(pendingApproval)))
setIsFailed(false)
} catch (e) {
console.error(e)
setIsFailed(true)
} finally {
setIsPending(false)
}
}, [callback, onSubmit])

const pendingApproval = usePendingApproval(currency?.isToken ? currency : undefined, PERMIT2_ADDRESS)
}, [callback, onSubmit, pendingApproval])

const action = useMemo(() => {
if (isPending) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/Swap/SwapActionButton/SwapButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export default function SwapButton({
}: {
color: keyof Colors
disabled: boolean
onSubmit: (submit?: () => Promise<ApprovalTransactionInfo | SwapTransactionInfo | void>) => Promise<void>
onSubmit: (submit: () => Promise<ApprovalTransactionInfo | SwapTransactionInfo | void>) => Promise<void>
}) {
const { account, chainId } = useWeb3React()
const {
Expand Down
4 changes: 2 additions & 2 deletions src/components/Swap/SwapActionButton/useOnSubmit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ export default function useOnSubmit() {
const [, setInputAmount] = useSwapAmount(Field.INPUT)

return useCallback(
async (submit?: () => Promise<TransactionInfo | void>): Promise<void> => {
const info = await submit?.()
async (submit: () => Promise<TransactionInfo | void>): Promise<void> => {
const info = await submit()
if (!info) return

addTransactionInfo(info)
Expand Down
55 changes: 32 additions & 23 deletions src/hooks/usePermit2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,25 @@ export enum PermitState {
export interface Permit {
state: PermitState
signature?: PermitSignature
callback?: () => Promise<ApprovalTransactionInfo | void>
callback?: (isPendingApproval: boolean) => Promise<ApprovalTransactionInfo | void>
}

export default function usePermit(amount?: CurrencyAmount<Token>, spender?: string): Permit {
const { account } = useWeb3React()
const tokenAllowance = useTokenAllowance(amount?.currency, account, 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 [permitAllowanceAmount, setPermitAllowanceAmount] = useState(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 updatePermitAllowance = useUpdatePermitAllowance(
Expand All @@ -37,12 +45,10 @@ export default function usePermit(amount?: CurrencyAmount<Token>, spender?: stri
permitAllowance?.nonce,
setSignature
)

const updateTokenAndPermitAllowance = useCallback(async () => {
const info = await updateTokenAllowance()
await updatePermitAllowance()
return info
}, [updatePermitAllowance, updateTokenAllowance])
const isSigned = useMemo(
() => amount && signature?.details.token === amount?.currency.address && signature?.spender === spender,
[amount, signature?.details.token, signature?.spender, spender]
)

// Trigger a re-render if either tokenAllowance or signature expire.
useInterval(
Expand All @@ -60,27 +66,30 @@ export default function usePermit(amount?: CurrencyAmount<Token>, spender?: stri
true
)

const callback = useCallback(
async (isPendingApproval: boolean) => {
let info: ApprovalTransactionInfo | undefined
if (!isAllowed && !isPendingApproval) {
info = await updateTokenAllowance()
}
if (!isPermitted && !isSigned) {
await updatePermitAllowance()
}
return info
},
[isAllowed, isPermitted, isSigned, updatePermitAllowance, updateTokenAllowance]
)

return useMemo(() => {
if (!amount || !tokenAllowance) {
return { state: PermitState.UNKNOWN }
} else if (tokenAllowance.greaterThan(amount) || tokenAllowance.equalTo(amount)) {
if (permitAllowanceAmount?.gte(amount.quotient.toString())) {
} else if (isAllowed) {
if (isPermitted) {
return { state: PermitState.PERMITTED }
} else if (signature?.details.token === amount.currency.address && signature?.spender === spender) {
} else if (isSigned) {
return { state: PermitState.PERMITTED, signature }
} else {
return { state: PermitState.PERMIT_NEEDED, callback: updatePermitAllowance }
}
} else {
return { state: PermitState.PERMIT_NEEDED, callback: updateTokenAndPermitAllowance }
}
}, [
amount,
permitAllowanceAmount,
signature,
spender,
tokenAllowance,
updatePermitAllowance,
updateTokenAndPermitAllowance,
])
return { state: PermitState.PERMIT_NEEDED, callback }
}, [amount, callback, isAllowed, isPermitted, isSigned, signature, tokenAllowance])
}

1 comment on commit 2f0c5cf

@vercel
Copy link

@vercel vercel bot commented on 2f0c5cf Dec 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

widgets – ./

widgets-uniswap.vercel.app
widgets-git-main-uniswap.vercel.app
widgets-seven-tau.vercel.app

Please sign in to comment.