diff --git a/apps/cowswap-frontend/src/modules/tradeSlippage/hooks/useShouldShowSlippageProminent.ts b/apps/cowswap-frontend/src/modules/tradeSlippage/hooks/useShouldShowSlippageProminent.ts new file mode 100644 index 0000000000..e82755cd8e --- /dev/null +++ b/apps/cowswap-frontend/src/modules/tradeSlippage/hooks/useShouldShowSlippageProminent.ts @@ -0,0 +1,65 @@ +import { useMemo } from 'react' + +import { ETH_FLOW_SLIPPAGE_WARNING_THRESHOLD } from '@cowprotocol/common-const' +import { percentToBps } from '@cowprotocol/common-utils' +import { useWalletInfo } from '@cowprotocol/wallet' + +import { useIsCurrentTradeBridging, useIsEoaEthFlow } from 'modules/trade' + +import { useIsSlippageModified } from './useIsSlippageModified' +import { useTradeSlippage } from './useTradeSlippage' + +/** + * Slippage warning threshold for regular ERC20 orders + * Show slippage prominently when > 2% + */ +const REGULAR_ORDER_SLIPPAGE_WARNING_BPS = 200 // 2% + +/** + * Hook to determine if slippage should be displayed prominently (outside the accordion) + * + * Slippage should be prominent when: + * 1. User has manually modified the slippage value, OR + * 2. Slippage exceeds warning thresholds (>2%) + * + * EXCEPT: Never show prominently for Bridge orders + * + * Note: When accordion is expanded, prominent slippage is hidden to avoid duplication + * + * @returns {boolean} true if slippage should be shown outside the accordion + */ +export function useShouldShowSlippageProminent(): boolean { + const { chainId } = useWalletInfo() + const slippage = useTradeSlippage() + const isSlippageModified = useIsSlippageModified() + const isEoaEthFlow = useIsEoaEthFlow() + const isCurrentTradeBridging = useIsCurrentTradeBridging() + + return useMemo(() => { + // Never show prominently for Bridge orders + if (isCurrentTradeBridging) { + return false + } + + const slippageBps = percentToBps(slippage) + + // Determine the warning threshold based on order type + let warningThresholdBps: number + + if (isEoaEthFlow) { + // For ETH-flow orders, use 2% threshold + warningThresholdBps = ETH_FLOW_SLIPPAGE_WARNING_THRESHOLD[chainId] + } else { + // For regular ERC20 orders, use 2% threshold + warningThresholdBps = REGULAR_ORDER_SLIPPAGE_WARNING_BPS + } + + // Show prominently when: + // 1. User manually modified slippage, OR + // 2. Slippage exceeds threshold (>2%) + const shouldShowDueToHighSlippage = slippageBps > warningThresholdBps + + return isSlippageModified || shouldShowDueToHighSlippage + }, [chainId, slippage, isSlippageModified, isEoaEthFlow, isCurrentTradeBridging]) +} + diff --git a/apps/cowswap-frontend/src/modules/tradeSlippage/index.tsx b/apps/cowswap-frontend/src/modules/tradeSlippage/index.tsx index 03a6fec617..15e02cec65 100644 --- a/apps/cowswap-frontend/src/modules/tradeSlippage/index.tsx +++ b/apps/cowswap-frontend/src/modules/tradeSlippage/index.tsx @@ -8,3 +8,4 @@ export * from './hooks/useSlippageConfig' export * from './utils/slippageBpsToPercent' export * from './hooks/useSlippageConfig' export * from './hooks/useIsDefaultSlippageApplied' +export * from './hooks/useShouldShowSlippageProminent' diff --git a/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/TradeRateDetails/index.tsx b/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/TradeRateDetails/index.tsx index c68e04a39a..9656c8844f 100644 --- a/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/TradeRateDetails/index.tsx +++ b/apps/cowswap-frontend/src/modules/tradeWidgetAddons/containers/TradeRateDetails/index.tsx @@ -13,7 +13,7 @@ import { useReceiveAmountInfo, } from 'modules/trade' import { useTradeQuote } from 'modules/tradeQuote' -import { useIsSlippageModified, useTradeSlippage } from 'modules/tradeSlippage' +import { useIsSlippageModified, useShouldShowSlippageProminent, useTradeSlippage } from 'modules/tradeSlippage' import { useUsdAmount } from 'modules/usdAmount' import { QuoteApiError } from 'api/cowProtocol/errors/QuoteError' @@ -43,6 +43,7 @@ export function TradeRateDetails({ const slippage = useTradeSlippage() const isSlippageModified = useIsSlippageModified() + const shouldShowSlippageProminent = useShouldShowSlippageProminent() // todo replace by useGetReceiveAmountInfo when we decide what to show as bridge total fee const receiveAmountInfo = useReceiveAmountInfo() const derivedTradeState = useDerivedTradeState() @@ -82,6 +83,15 @@ export function TradeRateDetails({ const totalCosts = getTotalCosts(receiveAmountInfo, bridgeQuoteAmounts?.bridgeFee) + // Slippage row component - can be shown outside or inside accordion + const slippageRow = slippage ? ( + + ) : null + // Default expanded content if accordionContent prop is not supplied const defaultExpandedContent = ( <> @@ -90,26 +100,28 @@ export function TradeRateDetails({ networkCostsSuffix={shouldPayGas ? : null} networkCostsTooltipSuffix={} /> - {slippage && ( - - )} + {/* Always show slippage inside accordion */} + {slippageRow} ) return ( - - {accordionContent || defaultExpandedContent} - + <> + + {accordionContent || defaultExpandedContent} + + + {/* Show slippage outside accordion when prominent and accordion is closed (to avoid duplication) */} + {shouldShowSlippageProminent && !isFeeDetailsOpen && ( +
{slippageRow}
+ )} + ) }