Skip to content

Commit

Permalink
refactor: permit 2 maintainability improvements (#325)
Browse files Browse the repository at this point in the history
* refactor: permit 2 maintainability improvements

* chore: nit on block time
  • Loading branch information
zzmp authored Dec 7, 2022
1 parent ec4cc3b commit a21b504
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 39 deletions.
6 changes: 3 additions & 3 deletions src/components/ActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export const Overlay = styled(Row)<{ hasAction: boolean }>`
export interface Action {
message: ReactNode
icon?: Icon
tooltip?: ReactNode
tooltipContent?: ReactNode
onClick?: () => void
children?: ReactNode
}
Expand Down Expand Up @@ -98,9 +98,9 @@ export default function ActionButton({
</StyledButton>
{action && (
<ActionRow gap={0.5}>
{action.tooltip ? (
{action.tooltipContent ? (
<Tooltip icon={LargeIcon} iconProps={{ color: 'currentColor', icon: action.icon || AlertTriangle }}>
{action.tooltip}
{action.tooltipContent}
</Tooltip>
) : (
<LargeIcon color="currentColor" icon={action.icon || AlertTriangle} />
Expand Down
21 changes: 5 additions & 16 deletions src/components/Swap/SwapActionButton/Permit2Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { PERMIT2_ADDRESS } from '@uniswap/permit2-sdk'
import ActionButton from 'components/ActionButton'
import EtherscanLink from 'components/EtherscanLink'
import { usePendingApproval } from 'hooks/transactions'
import { PermitState } from 'hooks/usePermit2'
import { Spinner } from 'icons'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { InterfaceTrade } from 'state/routing/types'
Expand All @@ -18,13 +17,11 @@ import { ExplorerDataType } from 'utils/getExplorerLink'
export default function PermitButton({
color,
trade,
state,
callback,
onSubmit,
}: {
color: keyof Colors
trade?: InterfaceTrade
state: PermitState
callback?: () => Promise<ApprovalTransactionInfo | void>
onSubmit: (submit?: () => Promise<ApprovalTransactionInfo | void>) => Promise<void>
}) {
Expand Down Expand Up @@ -52,15 +49,7 @@ export default function PermitButton({

const pendingApproval = usePendingApproval(currency?.isToken ? currency : undefined, PERMIT2_ADDRESS)

const actionProps = useMemo(() => {
switch (state) {
case PermitState.UNKNOWN:
case PermitState.PERMITTED:
return
case PermitState.APPROVAL_NEEDED:
case PermitState.PERMIT_NEEDED:
}

const action = useMemo(() => {
if (isPending) {
return {
icon: Spinner,
Expand All @@ -82,15 +71,15 @@ export default function PermitButton({
}
} else {
return {
tooltip: t`Permission is required for Uniswap to swap each token. This will expire after one month for your security.`,
message: `Approve use of ${currency?.symbol ?? 'token'}`,
tooltipContent: t`Permission is required for Uniswap to swap each token. This will expire after one month for your security.`,
message: t`Approve use of ${currency?.symbol ?? 'token'}`,
onClick,
}
}
}, [currency?.symbol, isFailed, isPending, onClick, pendingApproval, state])
}, [currency?.symbol, isFailed, isPending, onClick, pendingApproval])

return (
<ActionButton color={color} disabled={!actionProps?.onClick} action={actionProps}>
<ActionButton color={color} disabled={!action?.onClick} action={action}>
{isFailed ? t`Try again` : t`Approve`}
</ActionButton>
)
Expand Down
4 changes: 2 additions & 2 deletions src/components/Swap/SwapActionButton/SwapButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,13 @@ export default function SwapButton({
deadline,
feeOptions,
})
const universalRouterCallback = useUniversalRouterSwapCallback(permit2 ? trade : undefined, {
const universalRouterSwapCallback = useUniversalRouterSwapCallback(permit2 ? trade : undefined, {
slippageTolerance: slippage.allowed,
deadline,
permit: permit.signature,
feeOptions,
})
const swapCallback = permit2 ? universalRouterCallback : swapRouterCallback
const swapCallback = permit2 ? universalRouterSwapCallback : swapRouterCallback

const [open, setOpen] = useState(false)
// Close the review modal if there is no available trade.
Expand Down
2 changes: 2 additions & 0 deletions src/constants/chainInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import ms from 'ms.macro'

import { SupportedChainId, SupportedL1ChainId, SupportedL2ChainId } from './chains'

export const STANDARD_L1_BLOCK_TIME = ms`12s`

export enum NetworkType {
L1,
L2,
Expand Down
31 changes: 18 additions & 13 deletions src/hooks/usePermit2.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { PERMIT2_ADDRESS } from '@uniswap/permit2-sdk'
import { CurrencyAmount, Token } from '@uniswap/sdk-core'
import { useWeb3React } from '@web3-react/core'
import ms from 'ms.macro'
import { STANDARD_L1_BLOCK_TIME } from 'constants/chainInfo'
import { useCallback, useEffect, useMemo, useState } from 'react'

import { ApprovalTransactionInfo } from '..'
Expand All @@ -11,7 +11,6 @@ import { useTokenAllowance, useUpdateTokenAllowance } from './useTokenAllowance'

export enum PermitState {
UNKNOWN,
APPROVAL_NEEDED,
PERMIT_NEEDED,
PERMITTED,
}
Expand All @@ -27,12 +26,17 @@ export default function usePermit(amount?: CurrencyAmount<Token>, spender?: stri
const tokenAllowance = useTokenAllowance(amount?.currency, account, PERMIT2_ADDRESS)
const updateTokenAllowance = useUpdateTokenAllowance(amount, PERMIT2_ADDRESS)

const allowanceData = usePermitAllowance(amount?.currency, spender)
const [permitAllowance, setPermitAllowance] = useState(allowanceData?.amount)
useEffect(() => setPermitAllowance(allowanceData?.amount), [allowanceData?.amount])
const permitAllowance = usePermitAllowance(amount?.currency, spender)
const [permitAllowanceAmount, setPermitAllowanceAmount] = useState(permitAllowance?.amount)
useEffect(() => setPermitAllowanceAmount(permitAllowance?.amount), [permitAllowance?.amount])

const [signature, setSignature] = useState<PermitSignature>()
const updatePermitAllowance = useUpdatePermitAllowance(amount?.currency, spender, allowanceData?.nonce, setSignature)
const updatePermitAllowance = useUpdatePermitAllowance(
amount?.currency,
spender,
permitAllowance?.nonce,
setSignature
)

const updateTokenAndPermitAllowance = useCallback(async () => {
const info = await updateTokenAllowance()
Expand All @@ -43,35 +47,36 @@ export default function usePermit(amount?: CurrencyAmount<Token>, spender?: stri
// Trigger a re-render if either tokenAllowance or signature expire.
useInterval(
() => {
const now = Date.now() / 1000 - 12 // ensure it can still go into this block (assuming 12s block time)
// Calculate now such that the signature will still be valid for the next block.
const now = (Date.now() - STANDARD_L1_BLOCK_TIME) / 1000
if (signature && signature.sigDeadline < now) {
setSignature(undefined)
}
if (allowanceData && allowanceData.expiration < now) {
setPermitAllowance(undefined)
if (permitAllowance && permitAllowance.expiration < now) {
setPermitAllowanceAmount(undefined)
}
},
ms`12s`,
STANDARD_L1_BLOCK_TIME,
true
)

return useMemo(() => {
if (!amount || !tokenAllowance) {
return { state: PermitState.UNKNOWN }
} else if (tokenAllowance.greaterThan(amount) || tokenAllowance.equalTo(amount)) {
if (permitAllowance?.gte(amount.quotient.toString())) {
if (permitAllowanceAmount?.gte(amount.quotient.toString())) {
return { state: PermitState.PERMITTED }
} else if (signature?.details.token === amount.currency.address && signature?.spender === spender) {
return { state: PermitState.PERMITTED, signature }
} else {
return { state: PermitState.PERMIT_NEEDED, callback: updatePermitAllowance }
}
} else {
return { state: PermitState.APPROVAL_NEEDED, callback: updateTokenAndPermitAllowance }
return { state: PermitState.PERMIT_NEEDED, callback: updateTokenAndPermitAllowance }
}
}, [
amount,
permitAllowance,
permitAllowanceAmount,
signature,
spender,
tokenAllowance,
Expand Down
8 changes: 4 additions & 4 deletions src/hooks/usePermitAllowance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ export interface PermitSignature extends Permit {
}

export function useUpdatePermitAllowance(
token?: Token,
spender?: string,
nonce?: number,
onPermitSignature?: (signature: PermitSignature) => void
token: Token | undefined,
spender: string | undefined,
nonce: number | undefined,
onPermitSignature: (signature: PermitSignature) => void
) {
const { account, chainId, provider } = useWeb3React()

Expand Down
2 changes: 2 additions & 0 deletions src/hooks/useSyncFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ export function usePermit2() {
const permit2 = useAtomValue(flagsAtom).permit2 ?? false
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 permit2
} catch {
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/useTokenAllowance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function useTokenAllowance(token?: Token, owner?: string, spender?: strin
)
}

export function useUpdateTokenAllowance(amount?: CurrencyAmount<Token>, spender?: string) {
export function useUpdateTokenAllowance(amount: CurrencyAmount<Token> | undefined, spender: string) {
const contract = useTokenContract(amount?.currency.address)

return useCallback(async (): Promise<ApprovalTransactionInfo> => {
Expand Down

1 comment on commit a21b504

@vercel
Copy link

@vercel vercel bot commented on a21b504 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-git-main-uniswap.vercel.app
widgets-seven-tau.vercel.app
widgets-uniswap.vercel.app

Please sign in to comment.