Skip to content

Commit

Permalink
fix(permit): usdc limit orders warning (#3247)
Browse files Browse the repository at this point in the history
* feat: move USDC name hack to a utils fn fixTokenName

* fix: apply USDC token name fix to valid permit check as well

* feat: add useGetPermitInfo

* feat: use PermitInfo when checking for pending permit
  • Loading branch information
alfetopito authored Oct 18, 2023
1 parent 878afbb commit d958d0f
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ import { getAppDataHooks } from 'modules/appData'

import { ParsedOrder } from 'utils/orderUtils/parseOrder'

import { CheckHasValidPendingPermit } from '../types'
import { useGetPermitInfo } from './useGetPermitInfo'

import { CheckHasValidPendingPermit, PermitInfo, SupportedPermitInfo } from '../types'
import { fixTokenName } from '../utils/fixTokenName'
import { getPermitUtilsInstance } from '../utils/getPermitUtilsInstance'

export function useCheckHasValidPendingPermit(): CheckHasValidPendingPermit {
const { chainId } = useWalletInfo()
const { provider } = useWeb3React()
const getPermitInfo = useGetPermitInfo(chainId)

return useCallback(
async (order: ParsedOrder): Promise<boolean | undefined> => {
Expand All @@ -25,7 +29,14 @@ export function useCheckHasValidPendingPermit(): CheckHasValidPendingPermit {
return undefined
}

return checkHasValidPendingPermit(order, provider, chainId)
const permitInfo = getPermitInfo(order.inputToken.address)

if (permitInfo === undefined) {
// Missing permit info, we can't tell
return undefined
}

return checkHasValidPendingPermit(order, provider, chainId, permitInfo)
},
[chainId, provider]
)
Expand All @@ -34,7 +45,8 @@ export function useCheckHasValidPendingPermit(): CheckHasValidPendingPermit {
async function checkHasValidPendingPermit(
order: ParsedOrder,
provider: Web3Provider,
chainId: SupportedChainId
chainId: SupportedChainId,
permitInfo: PermitInfo
): Promise<boolean> {
const { fullAppData, partiallyFillable, executionData } = order
const preHooks = getAppDataHooks(fullAppData)?.pre
Expand All @@ -44,7 +56,9 @@ async function checkHasValidPendingPermit(
!preHooks ||
// Permit is only executed for partially fillable orders in the first execution
// Thus, if there is any amount executed, partiallyFillable permit is no longer valid
(partiallyFillable && executionData.filledAmount.gt('0'))
(partiallyFillable && executionData.filledAmount.gt('0')) ||
// Permit not supported, shouldn't even get this far
!permitInfo
) {
// These cases we know for sure permit isn't valid or there is no permit
return false
Expand All @@ -57,7 +71,7 @@ async function checkHasValidPendingPermit(

const checkedHooks = await Promise.all(
preHooks.map(({ callData }) =>
checkIsSingleCallDataAValidPermit(order, chainId, eip2162Utils, tokenAddress, tokenName, callData)
checkIsSingleCallDataAValidPermit(order, chainId, eip2162Utils, tokenAddress, tokenName, callData, permitInfo)
)
)

Expand All @@ -78,9 +92,10 @@ async function checkIsSingleCallDataAValidPermit(
eip2162Utils: Eip2612PermitUtils,
tokenAddress: string,
tokenName: string,
callData: string
callData: string,
{ version }: SupportedPermitInfo
): Promise<boolean | undefined> {
const params = { chainId, tokenName, tokenAddress, callData }
const params = { chainId, tokenName: fixTokenName(tokenName), tokenAddress, callData, version }

let recoverPermitOwnerPromise: Promise<string> | undefined = undefined

Expand Down
21 changes: 21 additions & 0 deletions apps/cowswap-frontend/src/modules/permit/hooks/useGetPermitInfo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { useAtomValue } from 'jotai'
import { useCallback } from 'react'

import { SupportedChainId } from '@cowprotocol/cow-sdk'

import { permittableTokensAtom } from '../state/permittableTokensAtom'
import { IsTokenPermittableResult } from '../types'

/**
* Returns a callback for getting PermitInfo for a given token
*
* Assumes permit info was already checked and cached.
*/
export function useGetPermitInfo(chainId: SupportedChainId): (tokenAddress: string) => IsTokenPermittableResult {
const permittableTokens = useAtomValue(permittableTokensAtom)

return useCallback(
(tokenAddress: string) => permittableTokens[chainId][tokenAddress.toLowerCase()],
[chainId, permittableTokens]
)
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
import { DAI_PERMIT_SELECTOR, EIP_2612_PERMIT_SELECTOR } from '@1inch/permit-signed-approvals-utils'

import { fixTokenName } from './fixTokenName'

import { BuildDaiLikePermitCallDataParams, BuildEip2162PermitCallDataParams } from '../types'

export async function buildEip2162PermitCallData({
eip2162Utils,
callDataParams,
}: BuildEip2162PermitCallDataParams): Promise<string> {
// TODO: this is ugly and I'm not happy with it either
// It'll probably go away when the tokens overhaul is implemented
// For now, this is a problem for favourite tokens cached locally with the hardcoded name for USDC token
// Using the wrong name breaks the signature.
const [permitParams, chainId, _tokenName, ...rest] = callDataParams
const tokenName = _tokenName === 'USD//C' ? 'USD Coin' : _tokenName
const [permitParams, chainId, tokenName, ...rest] = callDataParams

const callData = await eip2162Utils.buildPermitCallData(permitParams, chainId, tokenName, ...rest)
const callData = await eip2162Utils.buildPermitCallData(permitParams, chainId, fixTokenName(tokenName), ...rest)
// For some reason, the method above removes the permit selector prefix
// https://github.com/1inch/permit-signed-approvals-utils/blob/master/src/eip-2612-permit.utils.ts#L92
// Adding it back
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function fixTokenName(tokenName: string): string {
// TODO: this is ugly and I'm not happy with it either
// It'll probably go away when the tokens overhaul is implemented
// For now, this is a problem for favourite tokens cached locally with the hardcoded name for USDC token
// Using the wrong name breaks the signature.
return tokenName === 'USD//C' ? 'USD Coin' : tokenName
}

0 comments on commit d958d0f

Please sign in to comment.