From 15671019225fb04d466ae82d020ea4496551b807 Mon Sep 17 00:00:00 2001 From: tenderdeve Date: Mon, 22 Jun 2026 19:45:32 +0530 Subject: [PATCH 1/5] fix(widget): fire ON_BEFORE_APPROVAL widget hook before permit signing For permittable tokens, CowSwap signs an EIP-2612 permit instead of performing an on-chain ERC-20 approval. The ON_BEFORE_APPROVAL widget hook, however, was only fired from the on-chain approval path (useApproveCurrency), so widget integrators that subscribed to onBeforeApproval never saw the event when the user was about to sign a permit. From the integrator's perspective the user authorized spending without their pre-approval handler ever running. Fire ON_BEFORE_APPROVAL in the swap and limit order trade flows right before requesting the permit signature, mirroring the payload shape used by useApproveCurrency (chainId, sellToken, sellAmount, walletAddress, spenderAddress). The hook is skipped when a cached permit is reused, matching the behaviour of the existing permit request UI step. If the integrator's hook returns false, the relevant flow aborts cleanly without dispatching a permit request: - swap flow returns false, just like a declined price impact; - limit order flow throws a new WidgetHookDeclineError which is swallowed by useHandleOrderPlacement and only dismisses the trade confirmation modal. Closes #7685 --- .../hooks/useHandleOrderPlacement.ts | 6 ++- .../limitOrders/services/tradeFlow/index.ts | 40 ++++++++++++++++--- .../src/modules/limitOrders/services/types.ts | 2 + .../tradeFlow/services/swapFlow/index.ts | 25 ++++++++++-- 4 files changed, 64 insertions(+), 9 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useHandleOrderPlacement.ts b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useHandleOrderPlacement.ts index f69f471e5d9..67960ca4825 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/hooks/useHandleOrderPlacement.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/hooks/useHandleOrderPlacement.ts @@ -17,7 +17,7 @@ import { useUpdateLimitOrdersRawState } from 'modules/limitOrders/hooks/useLimit import { useSafeBundleFlowContext } from 'modules/limitOrders/hooks/useSafeBundleFlowContext' import { safeBundleFlow } from 'modules/limitOrders/services/safeBundleFlow' import { tradeFlow } from 'modules/limitOrders/services/tradeFlow' -import { PriceImpactDeclineError, TradeFlowContext } from 'modules/limitOrders/services/types' +import { PriceImpactDeclineError, TradeFlowContext, WidgetHookDeclineError } from 'modules/limitOrders/services/types' import { LimitOrdersSettingsState } from 'modules/limitOrders/state/limitOrdersSettingsAtom' import { partiallyFillableOverrideAtom } from 'modules/limitOrders/state/partiallyFillableOverride' import { calculateLimitOrdersDeadline } from 'modules/limitOrders/utils/calculateLimitOrdersDeadline' @@ -202,6 +202,10 @@ export function useHandleOrderPlacement( }) .catch((error) => { if (error instanceof PriceImpactDeclineError) return + if (error instanceof WidgetHookDeclineError) { + tradeConfirmActions.onDismiss() + return + } if (error instanceof OperatorError) { tradeConfirmActions.onError(error.message || error.description) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/services/tradeFlow/index.ts b/apps/cowswap-frontend/src/modules/limitOrders/services/tradeFlow/index.ts index 4d09e81e00f..ff10d663f33 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/services/tradeFlow/index.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/services/tradeFlow/index.ts @@ -1,8 +1,16 @@ -import { captureError, ERROR_TYPES, normalizeError, reportPermitWithDefaultSigner } from '@cowprotocol/common-utils' -import { SigningScheme } from '@cowprotocol/cow-sdk' +import { + captureError, + COW_PROTOCOL_VAULT_RELAYER_ADDRESS, + currencyAmountToTokenAmount, + ERROR_TYPES, + normalizeError, + reportPermitWithDefaultSigner, +} from '@cowprotocol/common-utils' +import { SigningScheme, SupportedChainId } from '@cowprotocol/cow-sdk' import { Percent } from '@cowprotocol/currency' import { isSupportedPermitInfo } from '@cowprotocol/permit-utils' import { Command, UiOrderType } from '@cowprotocol/types' +import { WidgetHookEvents } from '@cowprotocol/widget-lib' import { tradingSdk } from 'tradingSdk/tradingSdk' import { sendTransaction } from 'wagmi/actions' @@ -11,8 +19,9 @@ import { PriceImpact } from 'legacy/hooks/usePriceImpact' import { partialOrderUpdate } from 'legacy/state/orders/utils' import { mapUnsignedOrderToOrder, wrapErrorInOperatorError } from 'legacy/utils/trade' +import { callWidgetHook } from 'modules/injectedWidget' import { LOW_RATE_THRESHOLD_PERCENT } from 'modules/limitOrders/const/trade' -import { PriceImpactDeclineError, TradeFlowContext } from 'modules/limitOrders/services/types' +import { PriceImpactDeclineError, TradeFlowContext, WidgetHookDeclineError } from 'modules/limitOrders/services/types' import { LimitOrdersSettingsState } from 'modules/limitOrders/state/limitOrdersSettingsAtom' import { calculateLimitOrdersDeadline } from 'modules/limitOrders/utils/calculateLimitOrdersDeadline' import { emitPostedOrderEvent } from 'modules/orders' @@ -27,7 +36,7 @@ import { getSwapErrorMessage } from 'common/utils/getSwapErrorMessage' import type { Hex } from 'viem' // TODO: Break down this large function into smaller functions -// eslint-disable-next-line max-lines-per-function +// eslint-disable-next-line max-lines-per-function, complexity export async function tradeFlow( params: TradeFlowContext, priceImpact: PriceImpact, @@ -73,7 +82,28 @@ export async function tradeFlow( try { logTradeFlow('LIMIT ORDER FLOW', 'STEP 2: handle permit') - if (isSupportedPermitInfo(permitInfo)) await beforePermit() + if (isSupportedPermitInfo(permitInfo)) { + const cachedPermit = await params.getCachedPermit(sellToken.address) + + if (!cachedPermit) { + const sellTokenAmount = currencyAmountToTokenAmount(inputAmount) + const isWidgetHookPassed = await callWidgetHook(WidgetHookEvents.ON_BEFORE_APPROVAL, { + chainId: sellTokenAmount.currency.chainId, + sellToken: { + ...sellTokenAmount.currency, + name: sellTokenAmount.currency.name || '', + symbol: sellTokenAmount.currency.symbol || '', + }, + sellAmount: (permitAmountToSign ?? 0n).toString(), + walletAddress: account, + spenderAddress: COW_PROTOCOL_VAULT_RELAYER_ADDRESS[chainId as SupportedChainId], + }) + + if (!isWidgetHookPassed) throw new WidgetHookDeclineError() + } + + await beforePermit() + } postOrderParams.appData = await handlePermit({ permitInfo, diff --git a/apps/cowswap-frontend/src/modules/limitOrders/services/types.ts b/apps/cowswap-frontend/src/modules/limitOrders/services/types.ts index 766a792f226..f28c7d1d808 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/services/types.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/services/types.ts @@ -36,3 +36,5 @@ export interface SafeBundleFlowContext extends TradeFlowContext { } export class PriceImpactDeclineError extends Error {} + +export class WidgetHookDeclineError extends Error {} diff --git a/apps/cowswap-frontend/src/modules/tradeFlow/services/swapFlow/index.ts b/apps/cowswap-frontend/src/modules/tradeFlow/services/swapFlow/index.ts index 4cbf2d3c015..4184d54f631 100644 --- a/apps/cowswap-frontend/src/modules/tradeFlow/services/swapFlow/index.ts +++ b/apps/cowswap-frontend/src/modules/tradeFlow/services/swapFlow/index.ts @@ -1,16 +1,19 @@ import { captureError, + COW_PROTOCOL_VAULT_RELAYER_ADDRESS, + currencyAmountToTokenAmount, delay, ERROR_TYPES, getCurrencyAddress, normalizeError, reportPermitWithDefaultSigner, } from '@cowprotocol/common-utils' -import { SigningScheme, SigningStepManager } from '@cowprotocol/cow-sdk' +import { SigningScheme, SigningStepManager, SupportedChainId } from '@cowprotocol/cow-sdk' import { Percent } from '@cowprotocol/currency' import { isSupportedPermitInfo } from '@cowprotocol/permit-utils' import { CoWShedEip1271SignatureInvalid } from '@cowprotocol/sdk-cow-shed' import { UiOrderType } from '@cowprotocol/types' +import { WidgetHookEvents } from '@cowprotocol/widget-lib' import { SigningSteps } from 'entities/trade' import ms from 'ms.macro' @@ -21,6 +24,7 @@ import { PriceImpact } from 'legacy/hooks/usePriceImpact' import { partialOrderUpdate } from 'legacy/state/orders/utils' import { mapUnsignedOrderToOrder, wrapErrorInOperatorError } from 'legacy/utils/trade' +import { callWidgetHook } from 'modules/injectedWidget' import { emitPostedOrderEvent } from 'modules/orders' import { callDataContainsPermitSigner, handlePermit } from 'modules/permit' import { addPendingOrderStep } from 'modules/trade/utils/addPendingOrderStep' @@ -86,13 +90,28 @@ export async function swapFlow( try { logTradeFlow('SWAP FLOW', 'STEP 2: handle permit') + const { appData, account, isSafeWallet, recipientAddressOrName, kind } = orderParams + if (shouldSignPermit) { + const sellTokenAmount = currencyAmountToTokenAmount(inputAmount) + const isWidgetHookPassed = await callWidgetHook(WidgetHookEvents.ON_BEFORE_APPROVAL, { + chainId: sellTokenAmount.currency.chainId, + sellToken: { + ...sellTokenAmount.currency, + name: sellTokenAmount.currency.name || '', + symbol: sellTokenAmount.currency.symbol || '', + }, + sellAmount: (permitAmountToSign ?? 0n).toString(), + walletAddress: account, + spenderAddress: COW_PROTOCOL_VAULT_RELAYER_ADDRESS[chainId as SupportedChainId], + }) + + if (!isWidgetHookPassed) return false + setSigningStep(isBridgingOrder ? '1/3' : '1/2', SigningSteps.PermitSigning) tradeConfirmActions.requestPermitSignature(tradeAmounts) } - const { appData, account, isSafeWallet, recipientAddressOrName, inputAmount, outputAmount, kind } = orderParams - orderParams.appData = await handlePermit({ appData, typedHooks, From f9d60508525c188ddbc43f41d560fdfe7adc283a Mon Sep 17 00:00:00 2001 From: tenderdeve Date: Tue, 23 Jun 2026 12:29:09 +0530 Subject: [PATCH 2/5] fix(widget): skip swap-error analytics for WidgetHookDeclineError Treat the widget-hook decline as an expected abort path rather than a generic swap error: re-throw before the catch block routes it through captureError and analytics, so declined ON_BEFORE_APPROVAL hooks no longer pollute error telemetry. Addresses @coderabbitai's feedback on #7697. --- .../src/modules/limitOrders/services/tradeFlow/index.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/cowswap-frontend/src/modules/limitOrders/services/tradeFlow/index.ts b/apps/cowswap-frontend/src/modules/limitOrders/services/tradeFlow/index.ts index ff10d663f33..30b909d76ff 100644 --- a/apps/cowswap-frontend/src/modules/limitOrders/services/tradeFlow/index.ts +++ b/apps/cowswap-frontend/src/modules/limitOrders/services/tradeFlow/index.ts @@ -226,6 +226,11 @@ export async function tradeFlow( } catch (err: unknown) { const error = normalizeError(err) + // Expected abort path: skip generic swap-error analytics so widget-hook declines don't pollute telemetry. + if (error instanceof WidgetHookDeclineError) { + throw error + } + logTradeFlow('LIMIT ORDER FLOW', 'STEP 9: ERROR: ', error) const swapErrorMessage = getSwapErrorMessage(error) From 97b1ab54c1a22f48a495662c419cdf3af7f896f9 Mon Sep 17 00:00:00 2001 From: tenderdeve Date: Tue, 23 Jun 2026 16:19:44 +0530 Subject: [PATCH 3/5] fix(widget): fire ON_BEFORE_APPROVAL hook before the trade approve tx The previous fix only wired ON_BEFORE_APPROVAL into the permit-signing paths (limit orders + swap permit flow). On the Swap page with a non-permittable token, the approval still goes through `useTradeApproveCallback` -> `approveCallback`, which never fired the hook. Result: the widget's onBeforeApproval listener never ran on the Swap page in that scenario. Call the hook in `useTradeApproveCallback` right before the ERC20 `approve` transaction. If the host widget declines, reset the approve progress modal and bail out without sending the tx, matching the behaviour of the other hook call sites. Addresses @elena-zh's review on #7697. --- .../useTradeApproveCallback.ts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.ts b/apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.ts index cd6fca881b0..cc81c5b3b26 100644 --- a/apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.ts +++ b/apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.ts @@ -3,10 +3,13 @@ import { useCallback } from 'react' import { useTradeSpenderAddress } from '@cowprotocol/balances-and-allowances' import { Currency, CurrencyAmount } from '@cowprotocol/currency' import { useIsSafeViaWc, useIsSafeWallet, useWalletInfo } from '@cowprotocol/wallet' +import { WidgetHookEvents } from '@cowprotocol/widget-lib' import { useSetOptimisticAllowance } from 'entities/optimisticAllowance/useSetOptimisticAllowance' import { usePublicClient } from 'wagmi' +import { callWidgetHook } from 'modules/injectedWidget' + import { processApprovalTransaction } from './approveUtils' import { useApprovalAnalytics } from './useApprovalAnalytics' import { useHandleApprovalError } from './useHandleApprovalError' @@ -64,6 +67,7 @@ interface ProcessTransactionConfirmationParams { }) => void } +// eslint-disable-next-line max-lines-per-function export function useTradeApproveCallback(currency: Currency | undefined): TradeApproveCallback { const symbol = currency?.symbol @@ -82,6 +86,7 @@ export function useTradeApproveCallback(currency: Currency | undefined): TradeAp const handleApprovalError = useHandleApprovalError(symbol) return useCallback( + // eslint-disable-next-line complexity async (amount, { useModals = true, waitForTxConfirmation } = DEFAULT_APPROVE_PARAMS) => { if (useModals) { const amountToApprove = currency ? CurrencyAmount.fromRawAmount(currency, amount.toString()) : undefined @@ -91,6 +96,27 @@ export function useTradeApproveCallback(currency: Currency | undefined): TradeAp approvalAnalytics('Send', symbol) try { + if (currency && account && spender) { + const isWidgetHookPassed = await callWidgetHook(WidgetHookEvents.ON_BEFORE_APPROVAL, { + chainId: currency.chainId, + sellToken: { + chainId: currency.chainId, + address: currency.isToken ? currency.address : '', + decimals: currency.decimals, + name: currency.name || '', + symbol: currency.symbol || '', + }, + sellAmount: amount.toString(), + walletAddress: account, + spenderAddress: spender, + }) + + if (!isWidgetHookPassed) { + resetApproveProgressModalState() + return undefined + } + } + const response = await approveCallback(amount) if (!response) { From 6653bb118709def2c7b45794352237cdd50e63e0 Mon Sep 17 00:00:00 2001 From: tenderdeve Date: Tue, 23 Jun 2026 17:48:32 +0530 Subject: [PATCH 4/5] fix(widget): fire ON_BEFORE_APPROVAL hook in advance permit signing On the Swap page, when the user clicks Approve for a permittable token, the trade form pre-signs an EIP-2612 permit via `useGeneratePermitInAdvanceToTrade`. That path skipped the `ON_BEFORE_APPROVAL` widget hook, so the host widget's `onBeforeApproval` listener never ran on Swap with permittable tokens (it worked on Limit Orders because the permit is signed inside the limit-order `tradeFlow`, which already calls the hook). Call the hook in `useGeneratePermitInAdvanceToTrade` right before `generatePermit`. If the host widget declines, bail out without signing, matching the behaviour of the other hook call sites. Also drop the speculative hook call I added to `useTradeApproveCallback` in 97b1ab54c: `useApproveCurrency` (the only path that consumes `useTradeApproveCallback` for the Swap form) already fires the hook, so the extra call would double-prompt. Addresses @elena-zh's follow-up review on #7697. --- .../useTradeApproveCallback.ts | 26 ----------------- .../useGeneratePermitInAdvanceToTrade.ts | 28 +++++++++++++++++-- 2 files changed, 26 insertions(+), 28 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.ts b/apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.ts index cc81c5b3b26..cd6fca881b0 100644 --- a/apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.ts +++ b/apps/cowswap-frontend/src/modules/erc20Approve/containers/TradeApproveModal/useTradeApproveCallback.ts @@ -3,13 +3,10 @@ import { useCallback } from 'react' import { useTradeSpenderAddress } from '@cowprotocol/balances-and-allowances' import { Currency, CurrencyAmount } from '@cowprotocol/currency' import { useIsSafeViaWc, useIsSafeWallet, useWalletInfo } from '@cowprotocol/wallet' -import { WidgetHookEvents } from '@cowprotocol/widget-lib' import { useSetOptimisticAllowance } from 'entities/optimisticAllowance/useSetOptimisticAllowance' import { usePublicClient } from 'wagmi' -import { callWidgetHook } from 'modules/injectedWidget' - import { processApprovalTransaction } from './approveUtils' import { useApprovalAnalytics } from './useApprovalAnalytics' import { useHandleApprovalError } from './useHandleApprovalError' @@ -67,7 +64,6 @@ interface ProcessTransactionConfirmationParams { }) => void } -// eslint-disable-next-line max-lines-per-function export function useTradeApproveCallback(currency: Currency | undefined): TradeApproveCallback { const symbol = currency?.symbol @@ -86,7 +82,6 @@ export function useTradeApproveCallback(currency: Currency | undefined): TradeAp const handleApprovalError = useHandleApprovalError(symbol) return useCallback( - // eslint-disable-next-line complexity async (amount, { useModals = true, waitForTxConfirmation } = DEFAULT_APPROVE_PARAMS) => { if (useModals) { const amountToApprove = currency ? CurrencyAmount.fromRawAmount(currency, amount.toString()) : undefined @@ -96,27 +91,6 @@ export function useTradeApproveCallback(currency: Currency | undefined): TradeAp approvalAnalytics('Send', symbol) try { - if (currency && account && spender) { - const isWidgetHookPassed = await callWidgetHook(WidgetHookEvents.ON_BEFORE_APPROVAL, { - chainId: currency.chainId, - sellToken: { - chainId: currency.chainId, - address: currency.isToken ? currency.address : '', - decimals: currency.decimals, - name: currency.name || '', - symbol: currency.symbol || '', - }, - sellAmount: amount.toString(), - walletAddress: account, - spenderAddress: spender, - }) - - if (!isWidgetHookPassed) { - resetApproveProgressModalState() - return undefined - } - } - const response = await approveCallback(amount) if (!response) { diff --git a/apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGeneratePermitInAdvanceToTrade.ts b/apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGeneratePermitInAdvanceToTrade.ts index 95bc25ddfa5..161c614e46a 100644 --- a/apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGeneratePermitInAdvanceToTrade.ts +++ b/apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGeneratePermitInAdvanceToTrade.ts @@ -1,9 +1,12 @@ import { useCallback } from 'react' -import { getWrappedToken, isRejectRequestProviderError } from '@cowprotocol/common-utils' +import { useTradeSpenderAddress } from '@cowprotocol/balances-and-allowances' +import { currencyAmountToTokenAmount, getWrappedToken, isRejectRequestProviderError } from '@cowprotocol/common-utils' import { Currency, CurrencyAmount } from '@cowprotocol/currency' import { useWalletInfo } from '@cowprotocol/wallet' +import { WidgetHookEvents } from '@cowprotocol/widget-lib' +import { callWidgetHook } from 'modules/injectedWidget' import { useGeneratePermitHook, usePermitInfo } from 'modules/permit' import { TradeType } from 'modules/trade' @@ -14,6 +17,7 @@ export function useGeneratePermitInAdvanceToTrade(amountToApprove: CurrencyAmoun const updateApproveProgressModalState = useUpdateApproveProgressModalState() const resetApproveProgressModalState = useResetApproveProgressModalState() const { account } = useWalletInfo() + const tradeSpenderAddress = useTradeSpenderAddress() const token = getWrappedToken(amountToApprove.currency) const permitInfo = usePermitInfo(token, TradeType.SWAP) @@ -21,6 +25,25 @@ export function useGeneratePermitInAdvanceToTrade(amountToApprove: CurrencyAmoun return useCallback(async () => { if (!account || !permitInfo) return false + const amountRaw = BigInt(amountToApprove.quotient.toString()) + + if (tradeSpenderAddress) { + const tokenAmount = currencyAmountToTokenAmount(amountToApprove) + const isWidgetHookPassed = await callWidgetHook(WidgetHookEvents.ON_BEFORE_APPROVAL, { + chainId: tokenAmount.currency.chainId, + sellToken: { + ...tokenAmount.currency, + name: tokenAmount.currency.name || '', + symbol: tokenAmount.currency.symbol || '', + }, + sellAmount: amountRaw.toString(), + walletAddress: account, + spenderAddress: tradeSpenderAddress, + }) + + if (!isWidgetHookPassed) return false + } + const preSignCallback = (): void => updateApproveProgressModalState({ currency: amountToApprove.currency, @@ -33,7 +56,7 @@ export function useGeneratePermitInAdvanceToTrade(amountToApprove: CurrencyAmoun inputToken: { name: token.name || '', address: token.address as `0x${string}` }, account, permitInfo, - amount: BigInt(amountToApprove.quotient.toString()), + amount: amountRaw, preSignCallback, postSignCallback: resetApproveProgressModalState, }) @@ -54,6 +77,7 @@ export function useGeneratePermitInAdvanceToTrade(amountToApprove: CurrencyAmoun resetApproveProgressModalState, token.address, token.name, + tradeSpenderAddress, updateApproveProgressModalState, ]) } From 7d49d28c42e44bfa94ba06fb059f5423ebc4eb59 Mon Sep 17 00:00:00 2001 From: tenderdeve Date: Tue, 23 Jun 2026 18:10:11 +0530 Subject: [PATCH 5/5] fix(widget): gate advance permit signing on tradeSpenderAddress If \`tradeSpenderAddress\` was unavailable, the previous version skipped the \`ON_BEFORE_APPROVAL\` widget hook but still called \`generatePermit\`, letting a permit be signed without the pre-approval gate. Treat a missing spender as a hard precondition (same as missing \`account\` / \`permitInfo\`) so the hook is always evaluated before any permit signature. Addresses @coderabbitai's review on #7697. --- .../useGeneratePermitInAdvanceToTrade.ts | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGeneratePermitInAdvanceToTrade.ts b/apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGeneratePermitInAdvanceToTrade.ts index 161c614e46a..54a0416874e 100644 --- a/apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGeneratePermitInAdvanceToTrade.ts +++ b/apps/cowswap-frontend/src/modules/erc20Approve/hooks/useGeneratePermitInAdvanceToTrade.ts @@ -23,26 +23,24 @@ export function useGeneratePermitInAdvanceToTrade(amountToApprove: CurrencyAmoun const permitInfo = usePermitInfo(token, TradeType.SWAP) return useCallback(async () => { - if (!account || !permitInfo) return false + if (!account || !permitInfo || !tradeSpenderAddress) return false const amountRaw = BigInt(amountToApprove.quotient.toString()) - if (tradeSpenderAddress) { - const tokenAmount = currencyAmountToTokenAmount(amountToApprove) - const isWidgetHookPassed = await callWidgetHook(WidgetHookEvents.ON_BEFORE_APPROVAL, { - chainId: tokenAmount.currency.chainId, - sellToken: { - ...tokenAmount.currency, - name: tokenAmount.currency.name || '', - symbol: tokenAmount.currency.symbol || '', - }, - sellAmount: amountRaw.toString(), - walletAddress: account, - spenderAddress: tradeSpenderAddress, - }) + const tokenAmount = currencyAmountToTokenAmount(amountToApprove) + const isWidgetHookPassed = await callWidgetHook(WidgetHookEvents.ON_BEFORE_APPROVAL, { + chainId: tokenAmount.currency.chainId, + sellToken: { + ...tokenAmount.currency, + name: tokenAmount.currency.name || '', + symbol: tokenAmount.currency.symbol || '', + }, + sellAmount: amountRaw.toString(), + walletAddress: account, + spenderAddress: tradeSpenderAddress, + }) - if (!isWidgetHookPassed) return false - } + if (!isWidgetHookPassed) return false const preSignCallback = (): void => updateApproveProgressModalState({