diff --git a/src/components/transactions/Swap/actions/DebtSwap/DebtSwapActionsViaCoW.tsx b/src/components/transactions/Swap/actions/DebtSwap/DebtSwapActionsViaCoW.tsx index 1487130d56..60eed532bb 100644 --- a/src/components/transactions/Swap/actions/DebtSwap/DebtSwapActionsViaCoW.tsx +++ b/src/components/transactions/Swap/actions/DebtSwap/DebtSwapActionsViaCoW.tsx @@ -81,8 +81,11 @@ export const DebtSwapActionsViaCoW = ({ [state.expiry] ); - // Pre-compute instance address + // Pre-compute instance address. + // Skip recalculation while approval is in progress or succeeded to prevent in-flight quote + // responses from changing the adapter address and invalidating the user's signature. useEffect(() => { + if (approvalTxState.loading || approvalTxState.success) return; calculateInstanceAddress({ user, validTo, @@ -113,6 +116,8 @@ export const DebtSwapActionsViaCoW = ({ state.orderType, state.chainId, APP_CODE_PER_SWAP_TYPE[state.swapType], + approvalTxState.loading, + approvalTxState.success, ]); const amountToApprove = useMemo(() => { diff --git a/src/components/transactions/Swap/actions/RepayWithCollateral/RepayWithCollateralActionsViaCoW.tsx b/src/components/transactions/Swap/actions/RepayWithCollateral/RepayWithCollateralActionsViaCoW.tsx index 336b16da98..ab3d0a9e4e 100644 --- a/src/components/transactions/Swap/actions/RepayWithCollateral/RepayWithCollateralActionsViaCoW.tsx +++ b/src/components/transactions/Swap/actions/RepayWithCollateral/RepayWithCollateralActionsViaCoW.tsx @@ -81,8 +81,11 @@ export const RepayWithCollateralActionsViaCoW = ({ [state.expiry] ); - // Pre-compute instance address + // Pre-compute instance address. + // Skip recalculation while approval is in progress or succeeded to prevent in-flight quote + // responses from changing the adapter address and invalidating the user's signature. useEffect(() => { + if (approvalTxState.loading || approvalTxState.success) return; calculateInstanceAddress({ user, validTo, @@ -113,6 +116,8 @@ export const RepayWithCollateralActionsViaCoW = ({ state.orderType, state.chainId, APP_CODE_PER_SWAP_TYPE[state.swapType], + approvalTxState.loading, + approvalTxState.success, ]); // Approval is aToken ERC20 Approval diff --git a/src/components/transactions/Swap/helpers/cow/adapters.helpers.ts b/src/components/transactions/Swap/helpers/cow/adapters.helpers.ts index afe3c35e8a..15cbe42284 100644 --- a/src/components/transactions/Swap/helpers/cow/adapters.helpers.ts +++ b/src/components/transactions/Swap/helpers/cow/adapters.helpers.ts @@ -58,7 +58,6 @@ export const calculateInstanceAddress = async ({ const { sellAmountWithMarginForDustProtection, buyAmountWithMarginForDustProtection, - buyAmount, sellToken, buyToken, quoteId, @@ -77,7 +76,6 @@ export const calculateInstanceAddress = async ({ state.orderType ), sellToken: state.sellAmountToken, - buyAmount: state.buyAmountBigInt, buyToken: state.buyAmountToken, quoteId: isCowProtocolRates(state.swapRate) ? state.swapRate?.quoteId : undefined, side: state.processedSide, @@ -100,7 +98,7 @@ export const calculateInstanceAddress = async ({ buyToken: buyToken.underlyingAddress, buyTokenDecimals: buyToken.decimals, sellAmount: sellAmountToSign.toString(), - buyAmount: buyAmount.toString(), + buyAmount: buyAmountWithMarginForDustProtection.toString(), kind: side === 'buy' ? OrderKind.BUY : OrderKind.SELL, quoteId, validTo, diff --git a/src/components/transactions/Swap/hooks/useSwapQuote.ts b/src/components/transactions/Swap/hooks/useSwapQuote.ts index 453f0a1671..962f59059b 100644 --- a/src/components/transactions/Swap/hooks/useSwapQuote.ts +++ b/src/components/transactions/Swap/hooks/useSwapQuote.ts @@ -227,8 +227,13 @@ export const useSwapQuote = ({ } }, [ratesError]); + // Apply incoming quote to state. Discard in-flight responses that arrive after + // the user has started the approval flow (quoteRefreshPaused) to prevent + // amount changes that would invalidate the adapter instance address / signature. useEffect(() => { if (swapQuote) { + if (state.quoteRefreshPaused) return; + const isAutoRefreshed = Boolean(state.quoteLastUpdatedAt); trackingHandlers?.trackSwapQuote(isAutoRefreshed, swapQuote);