diff --git a/apps/cowswap-frontend/src/modules/permit/hooks/useCheckHasValidPendingPermit.ts b/apps/cowswap-frontend/src/modules/permit/hooks/useCheckHasValidPendingPermit.ts index 6197865e15..75144a1c9f 100644 --- a/apps/cowswap-frontend/src/modules/permit/hooks/useCheckHasValidPendingPermit.ts +++ b/apps/cowswap-frontend/src/modules/permit/hooks/useCheckHasValidPendingPermit.ts @@ -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 => { @@ -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] ) @@ -34,7 +45,8 @@ export function useCheckHasValidPendingPermit(): CheckHasValidPendingPermit { async function checkHasValidPendingPermit( order: ParsedOrder, provider: Web3Provider, - chainId: SupportedChainId + chainId: SupportedChainId, + permitInfo: PermitInfo ): Promise { const { fullAppData, partiallyFillable, executionData } = order const preHooks = getAppDataHooks(fullAppData)?.pre @@ -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 @@ -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) ) ) @@ -78,9 +92,10 @@ async function checkIsSingleCallDataAValidPermit( eip2162Utils: Eip2612PermitUtils, tokenAddress: string, tokenName: string, - callData: string + callData: string, + { version }: SupportedPermitInfo ): Promise { - const params = { chainId, tokenName, tokenAddress, callData } + const params = { chainId, tokenName: fixTokenName(tokenName), tokenAddress, callData, version } let recoverPermitOwnerPromise: Promise | undefined = undefined diff --git a/apps/cowswap-frontend/src/modules/permit/hooks/useGetPermitInfo.ts b/apps/cowswap-frontend/src/modules/permit/hooks/useGetPermitInfo.ts new file mode 100644 index 0000000000..f8c89dfe12 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/hooks/useGetPermitInfo.ts @@ -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] + ) +} diff --git a/apps/cowswap-frontend/src/modules/permit/utils/buildPermitCallData.ts b/apps/cowswap-frontend/src/modules/permit/utils/buildPermitCallData.ts index aba6099b8f..4ac03b1812 100644 --- a/apps/cowswap-frontend/src/modules/permit/utils/buildPermitCallData.ts +++ b/apps/cowswap-frontend/src/modules/permit/utils/buildPermitCallData.ts @@ -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 { - // 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 diff --git a/apps/cowswap-frontend/src/modules/permit/utils/fixTokenName.ts b/apps/cowswap-frontend/src/modules/permit/utils/fixTokenName.ts new file mode 100644 index 0000000000..3b16d300d4 --- /dev/null +++ b/apps/cowswap-frontend/src/modules/permit/utils/fixTokenName.ts @@ -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 +}