From 04ebd55af2064528cf80367e5b0615f945ba3bdb Mon Sep 17 00:00:00 2001 From: Martin Grabina Date: Tue, 18 Nov 2025 20:30:48 -0300 Subject: [PATCH 1/5] fix: correct liquidatable HF condition for warning --- .../Swap/warnings/postInputs/LowHealthFactorWarning.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/transactions/Swap/warnings/postInputs/LowHealthFactorWarning.tsx b/src/components/transactions/Swap/warnings/postInputs/LowHealthFactorWarning.tsx index 55bd9cae86..9e3d3f0044 100644 --- a/src/components/transactions/Swap/warnings/postInputs/LowHealthFactorWarning.tsx +++ b/src/components/transactions/Swap/warnings/postInputs/LowHealthFactorWarning.tsx @@ -56,7 +56,7 @@ export function LowHealthFactorWarning({ Low health factor after swap. Your position will carry a higher risk of liquidation. - {!state.actionsBlocked[ActionsBlockedReason.LOW_HEALTH_FACTOR] && ( + {!state.actionsBlocked[ActionsBlockedReason.IS_LIQUIDATABLE] && ( Date: Tue, 18 Nov 2025 22:16:57 -0300 Subject: [PATCH 2/5] fix: recheck balance guard on lower amount correctly --- .../transactions/Swap/errors/SwapErrors.tsx | 6 ++++-- .../errors/shared/InsufficientBalanceGuard.tsx | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/components/transactions/Swap/errors/SwapErrors.tsx b/src/components/transactions/Swap/errors/SwapErrors.tsx index f90f0478c6..bb7069c02f 100644 --- a/src/components/transactions/Swap/errors/SwapErrors.tsx +++ b/src/components/transactions/Swap/errors/SwapErrors.tsx @@ -3,7 +3,7 @@ import React, { Dispatch, useEffect } from 'react'; import { useModalContext } from '../../../../hooks/useModal'; import { TrackAnalyticsHandlers } from '../analytics/useTrackAnalytics'; import { SwapError, SwapParams, SwapState } from '../types'; -import { isProtocolSwapState } from '../types/state.types'; +import { ActionsBlockedReason, isProtocolSwapState } from '../types/state.types'; import { errorToConsole } from './shared/console.helpers'; import { FlashLoanDisabledBlockingGuard, @@ -66,7 +66,9 @@ export const SwapErrors = ({ } }, [state.error]); - if (hasInsufficientBalance(state)) { + const insufficientBalance = hasInsufficientBalance(state); + + if (insufficientBalance || state.actionsBlocked?.[ActionsBlockedReason.INSUFFICIENT_BALANCE]) { return ( Date: Tue, 18 Nov 2025 22:33:27 -0300 Subject: [PATCH 3/5] nit for quote refreshs --- src/components/transactions/Swap/hooks/useSwapQuote.ts | 2 -- src/components/transactions/Swap/inputs/SwapInputs.tsx | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/transactions/Swap/hooks/useSwapQuote.ts b/src/components/transactions/Swap/hooks/useSwapQuote.ts index bcc5bf66e2..c102f63a0a 100644 --- a/src/components/transactions/Swap/hooks/useSwapQuote.ts +++ b/src/components/transactions/Swap/hooks/useSwapQuote.ts @@ -433,9 +433,7 @@ const useMultiProviderSwapQuoteQuery = ({ !state.mainTxState.txHash && // Don't fetch quotes once transaction is sent !state.mainTxState.loading && // Don't fetch quotes while transaction is processing !approvalTxState?.loading && // Don't fetch quotes while approval is processing - !approvalTxState?.success && // Don't fetch quotes while approval is successful provider !== SwapProvider.NONE && - !state.quoteRefreshPaused && !state.isWrongNetwork ); })(), diff --git a/src/components/transactions/Swap/inputs/SwapInputs.tsx b/src/components/transactions/Swap/inputs/SwapInputs.tsx index b64f8d1f8d..5f855df1b0 100644 --- a/src/components/transactions/Swap/inputs/SwapInputs.tsx +++ b/src/components/transactions/Swap/inputs/SwapInputs.tsx @@ -88,6 +88,7 @@ export const SwapInputs = ({ quoteTimerPausedAccumMs: undefined, } : {}), + ...(state.orderType === OrderType.MARKET ? { quoteRefreshPaused: false } : {}), inputAmount: maxAmount, inputAmountUSD: computeUSD(maxAmount), isMaxSelected: true, @@ -103,6 +104,7 @@ export const SwapInputs = ({ quoteTimerPausedAccumMs: undefined, } : {}), + ...(state.orderType === OrderType.MARKET ? { quoteRefreshPaused: false } : {}), inputAmount: value, inputAmountUSD: computeUSD(value), isMaxSelected: value === state.forcedMaxValue, From c67e02114f247308a37406a49dbf2e6f512eb74a Mon Sep 17 00:00:00 2001 From: Martin Grabina Date: Tue, 18 Nov 2025 22:38:32 -0300 Subject: [PATCH 4/5] dont show flashloan amount on non flashloan flow --- .../transactions/Swap/details/CowCostsDetails.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/transactions/Swap/details/CowCostsDetails.tsx b/src/components/transactions/Swap/details/CowCostsDetails.tsx index 4b4e35c827..a04d52d784 100644 --- a/src/components/transactions/Swap/details/CowCostsDetails.tsx +++ b/src/components/transactions/Swap/details/CowCostsDetails.tsx @@ -37,6 +37,7 @@ export const CowCostsDetails = ({ state }: { state: SwapState }) => { .toNumber(); const flashloanFeeUsd = Number(flashloanFeeFormatted) * flashLoanFeeTokenPriceUnitUsd; const flashloanFeeToken = state.sellAmountToken; + const isFlashloanUsed = state.useFlashloan; if (!state.buyAmountToken || !state.sellAmountToken) return null; @@ -74,7 +75,8 @@ export const CowCostsDetails = ({ state }: { state: SwapState }) => { partnerFeeToken = state.buyAmountToken; } - const totalCostsInUsd = networkFeeUsd + partnerFeeUsd + (flashloanFeeUsd ?? 0); // + costs.slippageInUsd; + const totalCostsInUsd = + networkFeeUsd + partnerFeeUsd + (isFlashloanUsed ? flashloanFeeUsd ?? 0 : 0); // + costs.slippageInUsd; return ( { /> - {!!(flashloanFeeFormatted && flashloanFeeToken && flashloanFeeUsd) && ( + {!!(flashloanFeeFormatted && flashloanFeeToken && flashloanFeeUsd && isFlashloanUsed) && ( Date: Tue, 18 Nov 2025 22:44:49 -0300 Subject: [PATCH 5/5] for paraswap distinguish failed vs gas estimation issue --- .../CollateralSwapActionsViaParaswapAdapters.tsx | 6 +++--- .../Swap/actions/DebtSwap/DebtSwapActionsViaParaswap.tsx | 7 ++++--- .../RepayWithCollateralActionsViaParaswap.tsx | 6 +++--- .../Swap/actions/SwapActions/SwapActionsViaParaswap.tsx | 6 +++--- .../WithdrawAndSwapActionsViaParaswap.tsx | 5 +++-- .../transactions/Swap/analytics/state.helpers.ts | 9 +++++++++ .../transactions/Swap/analytics/useTrackAnalytics.ts | 7 +++++++ src/utils/events.ts | 3 +++ 8 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/components/transactions/Swap/actions/CollateralSwap/CollateralSwapActionsViaParaswapAdapters.tsx b/src/components/transactions/Swap/actions/CollateralSwap/CollateralSwapActionsViaParaswapAdapters.tsx index d532555929..958e435464 100644 --- a/src/components/transactions/Swap/actions/CollateralSwap/CollateralSwapActionsViaParaswapAdapters.tsx +++ b/src/components/transactions/Swap/actions/CollateralSwap/CollateralSwapActionsViaParaswapAdapters.tsx @@ -228,6 +228,7 @@ export const CollateralSwapActionsViaParaswapAdapters = ({ ], error: undefined, // Clear any existing errors }); + trackingHandlers.trackGasEstimationError(error); } else { // For other errors, handle normally setTxError(parsedError); @@ -239,14 +240,13 @@ export const CollateralSwapActionsViaParaswapAdapters = ({ actionBlocked: parsedError.actionBlocked, }, }); + const reason = error instanceof Error ? error.message : 'Swap failed'; + trackingHandlers.trackSwapFailed(reason); } setMainTxState({ loading: false, }); - - const reason = error instanceof Error ? error.message : 'Swap failed'; - trackingHandlers.trackSwapFailed(reason); } }; diff --git a/src/components/transactions/Swap/actions/DebtSwap/DebtSwapActionsViaParaswap.tsx b/src/components/transactions/Swap/actions/DebtSwap/DebtSwapActionsViaParaswap.tsx index 951fab2e26..6c60b968dc 100644 --- a/src/components/transactions/Swap/actions/DebtSwap/DebtSwapActionsViaParaswap.tsx +++ b/src/components/transactions/Swap/actions/DebtSwap/DebtSwapActionsViaParaswap.tsx @@ -212,21 +212,22 @@ export const DebtSwapActionsViaParaswap = ({ ], error: undefined, // Clear any existing errors }); + trackingHandlers.trackGasEstimationError(error); } else { // For other errors, handle normally setTxError(parsedError); setState({ actionsLoading: false, }); + + const reason = error instanceof Error ? error.message : 'Swap failed'; + trackingHandlers.trackSwapFailed(reason); } setMainTxState({ txHash: undefined, loading: false, }); - - const reason = error instanceof Error ? error.message : 'Swap failed'; - trackingHandlers.trackSwapFailed(reason); } }; diff --git a/src/components/transactions/Swap/actions/RepayWithCollateral/RepayWithCollateralActionsViaParaswap.tsx b/src/components/transactions/Swap/actions/RepayWithCollateral/RepayWithCollateralActionsViaParaswap.tsx index 3f0d8bce67..d8b6625dec 100644 --- a/src/components/transactions/Swap/actions/RepayWithCollateral/RepayWithCollateralActionsViaParaswap.tsx +++ b/src/components/transactions/Swap/actions/RepayWithCollateral/RepayWithCollateralActionsViaParaswap.tsx @@ -249,20 +249,20 @@ export const RepayWithCollateralActionsViaParaswap = ({ ], error: undefined, // Clear any existing errors }); + trackingHandlers.trackGasEstimationError(error); } else { // For other errors, handle normally setTxError(parsedError); setState({ actionsLoading: false, }); + const reason = error instanceof Error ? error.message : undefined; + trackingHandlers.trackSwapFailed(reason); } setMainTxState({ loading: false, }); - - const reason = error instanceof Error ? error.message : undefined; - trackingHandlers.trackSwapFailed(reason); } }; diff --git a/src/components/transactions/Swap/actions/SwapActions/SwapActionsViaParaswap.tsx b/src/components/transactions/Swap/actions/SwapActions/SwapActionsViaParaswap.tsx index f218f1f583..e8b9f258ee 100644 --- a/src/components/transactions/Swap/actions/SwapActions/SwapActionsViaParaswap.tsx +++ b/src/components/transactions/Swap/actions/SwapActions/SwapActionsViaParaswap.tsx @@ -187,21 +187,21 @@ export const SwapActionsViaParaswap = ({ ], error: undefined, // Clear any existing errors }); + trackingHandlers.trackGasEstimationError(error); } else { // For other errors, handle normally setTxError(parsedError); setState({ actionsLoading: false, }); + const reason = error instanceof Error ? error.message : 'Swap failed'; + trackingHandlers.trackSwapFailed(reason); } setMainTxState({ txHash: undefined, loading: false, }); - - const reason = error instanceof Error ? error.message : 'Swap failed'; - trackingHandlers.trackSwapFailed(reason); } } else { setTxError( diff --git a/src/components/transactions/Swap/actions/WithdrawAndSwap/WithdrawAndSwapActionsViaParaswap.tsx b/src/components/transactions/Swap/actions/WithdrawAndSwap/WithdrawAndSwapActionsViaParaswap.tsx index 04ace480a6..df69e53bad 100644 --- a/src/components/transactions/Swap/actions/WithdrawAndSwap/WithdrawAndSwapActionsViaParaswap.tsx +++ b/src/components/transactions/Swap/actions/WithdrawAndSwap/WithdrawAndSwapActionsViaParaswap.tsx @@ -169,20 +169,21 @@ export const WithdrawAndSwapActionsViaParaswap = ({ ], error: undefined, // Clear any existing errors }); + trackingHandlers.trackGasEstimationError(error); } else { // For other errors, handle normally setTxError(parsedError); setState({ actionsLoading: false, }); + const reason = error instanceof Error ? error.message : undefined; + trackingHandlers.trackSwapFailed(reason); } setMainTxState({ txHash: undefined, loading: false, }); - const reason = error instanceof Error ? error.message : undefined; - trackingHandlers.trackSwapFailed(reason); } }; diff --git a/src/components/transactions/Swap/analytics/state.helpers.ts b/src/components/transactions/Swap/analytics/state.helpers.ts index 1479685163..3558b8426c 100644 --- a/src/components/transactions/Swap/analytics/state.helpers.ts +++ b/src/components/transactions/Swap/analytics/state.helpers.ts @@ -135,3 +135,12 @@ export const swapUserDeniedToAnalyticsEventParams = (state: SwapState): TrackEve ...swapStateToAnalyticsEventParams(state), }; }; + +export const swapTrackGasEstimationErrorToAnalyticsEventParams = ( + state: SwapState +): TrackEventProperties => { + return { + ...swapStateToAnalyticsEventParams(state), + errorMessage: 'Gas estimation error', + }; +}; diff --git a/src/components/transactions/Swap/analytics/useTrackAnalytics.ts b/src/components/transactions/Swap/analytics/useTrackAnalytics.ts index 487b641180..a7531cccf8 100644 --- a/src/components/transactions/Swap/analytics/useTrackAnalytics.ts +++ b/src/components/transactions/Swap/analytics/useTrackAnalytics.ts @@ -7,6 +7,7 @@ import { swapInputChangeToAnalyticsEventParams, swapQuoteToAnalyticsEventParams, swapTrackApprovalToAnalyticsEventParams, + swapTrackGasEstimationErrorToAnalyticsEventParams, swapTrackSwapFailedToAnalyticsEventParams, swapTrackSwapFilledToAnalyticsEventParams, swapTrackSwapToAnalyticsEventParams, @@ -22,6 +23,7 @@ export type TrackAnalyticsHandlers = { trackSwap: () => void; trackSwapFilled: (executedSellAmount: string, executedBuyAmount: string) => void; trackSwapFailed: (reason?: string) => void; + trackGasEstimationError: (error: SwapError) => void; }; /* @@ -59,5 +61,10 @@ export const useHandleAnalytics = ({ state }: { state: SwapState }) => { ), trackSwapFailed: (reason?: string) => trackEvent(SWAP.SWAP_FAILED, swapTrackSwapFailedToAnalyticsEventParams(state, reason)), + trackGasEstimationError: () => + trackEvent( + SWAP.GAS_ESTIMATION_ERROR, + swapTrackGasEstimationErrorToAnalyticsEventParams(state) + ), }; }; diff --git a/src/utils/events.ts b/src/utils/events.ts index b3437ccf38..cde0e57724 100644 --- a/src/utils/events.ts +++ b/src/utils/events.ts @@ -58,6 +58,9 @@ export enum SWAP { /// The user denied a wallet request USER_DENIED = 'SWAP_USER_DENIED_WALLET_REQUEST', + + /// The user has encountered a gas estimation error + GAS_ESTIMATION_ERROR = 'SWAP_GAS_ESTIMATION_ERROR', } export const REWARDS = {