diff --git a/apps/web/src/components/AccessRisk/SwapRevampRiskDisplay.tsx b/apps/web/src/components/AccessRisk/SwapRevampRiskDisplay.tsx index 2ef361f6d977b..6138ba97e45a1 100644 --- a/apps/web/src/components/AccessRisk/SwapRevampRiskDisplay.tsx +++ b/apps/web/src/components/AccessRisk/SwapRevampRiskDisplay.tsx @@ -1,6 +1,6 @@ import { useTranslation } from '@pancakeswap/localization' import { ERC20Token } from '@pancakeswap/sdk' -import { Box, FlexGap, Link, RiskAlertIcon, Text } from '@pancakeswap/uikit' +import { Box, FlexGap, Link, RiskAlertIcon, Text, WarningIcon } from '@pancakeswap/uikit' import isUndefinedOrNull from '@pancakeswap/utils/isUndefinedOrNull' import { SwapUIV2 } from '@pancakeswap/widgets-internal' import { useEffect, useMemo, useState } from 'react' @@ -35,6 +35,8 @@ interface RiskDetailsPanelProps { token0RiskLevelDescription?: string token1?: ERC20Token token1RiskLevelDescription?: string + isPriceImpactTooHigh?: boolean + isSlippageTooHigh?: boolean } const useRiskCheckData = (token?: ERC20Token) => { @@ -111,6 +113,70 @@ export const RiskTitle: React.FC = ({ token }) => { return null } +export const PriceImpactTitle: React.FC = () => { + const { t } = useTranslation() + return ( + + + + + + {t('Price impact too high. Proceed with caution.')} + + + ) +} + +export const SlippageTitle: React.FC = () => { + const { t } = useTranslation() + return ( + + + + + + {t('Slippage settings too high. Proceed with caution.')} + + + ) +} + +const PriceImpactDetails: React.FC = () => { + const { t } = useTranslation() + return ( + + + + {t( + 'Final execution price may be differ from the market price due to trader size, available liquidity, and trading route. Please proceed with caution.', + )} + + + Learn More + + + + ) +} + +const SlippageDetails: React.FC = () => { + const { t } = useTranslation() + return ( + + + + {t( + 'You may only get the amount of “Minimum received” with a high slippage setting. Reset your slippage to avoid potential losses.', + )} + + + Learn More + + + + ) +} + export const RiskDetails: React.FC = ({ token }) => { const { t } = useTranslation() const { isDataLoading, riskLevel } = useRiskCheckData(token) @@ -139,9 +205,10 @@ export const RiskDetails: React.FC = ({ token }) => { export const useShouldRiskPanelDisplay = (token0?: ERC20Token, token1?: ERC20Token) => { const { isDataLoading: isDataLoading0, riskLevel: riskLevel0 } = useRiskCheckData(token0) const { isDataLoading: isDataLoading1, riskLevel: riskLevel1 } = useRiskCheckData(token1) + if (isDataLoading0 || isDataLoading1) { + return false + } return ( - isDataLoading0 || - isDataLoading1 || (riskLevel0 && riskLevel0 <= TOKEN_RISK.SIGNIFICANT && riskLevel0 >= TOKEN_RISK.HIGH) || (riskLevel1 && riskLevel1 <= TOKEN_RISK.SIGNIFICANT && riskLevel1 >= TOKEN_RISK.HIGH) ) @@ -152,26 +219,58 @@ export const RiskDetailsPanel: React.FC = ({ token1, token0RiskLevelDescription, token1RiskLevelDescription, + isPriceImpactTooHigh, + isSlippageTooHigh, }) => { const [isOpen, setIsOpen] = useState(false) + const isRiskToken0 = useShouldRiskPanelDisplay(token0) + const isRiskToken1 = useShouldRiskPanelDisplay(token1) + const isRiskMoreThanOne = useMemo(() => { + let count = 0 + if (isRiskToken0) { + count++ + console.log('isRiskToken0', isRiskToken0) + } + if (isRiskToken1) { + count++ + console.log('isRiskToken1', isRiskToken1) + } + if (isPriceImpactTooHigh) { + count++ + console.log('isPriceImpactTooHigh', isPriceImpactTooHigh) + } + if (isSlippageTooHigh) { + count++ + console.log('isSlippageTooHigh', isSlippageTooHigh) + } + return count > 1 + }, [isRiskToken0, isRiskToken1, isPriceImpactTooHigh, isSlippageTooHigh]) return ( - setIsOpen(!isOpen)} - title={ - - - - - } - content={ - - - - - } - /> + {isRiskMoreThanOne ? ( + 'risk more than one' + ) : ( + setIsOpen(!isOpen)} + title={ + + + + {isPriceImpactTooHigh && } + {isSlippageTooHigh && } + + } + content={ + + + + {isPriceImpactTooHigh && } + {isSlippageTooHigh && } + + } + /> + )} ) } diff --git a/apps/web/src/views/SwapSimplify/V4Swap/index.tsx b/apps/web/src/views/SwapSimplify/V4Swap/index.tsx index e68af827e33f2..414aee4f0e94c 100644 --- a/apps/web/src/views/SwapSimplify/V4Swap/index.tsx +++ b/apps/web/src/views/SwapSimplify/V4Swap/index.tsx @@ -1,4 +1,5 @@ import { SmartRouter } from '@pancakeswap/smart-router/evm' +import { useUserSlippage } from '@pancakeswap/utils/user' import { SwapUIV2 } from '@pancakeswap/widgets-internal' import { RiskDetailsPanel, useShouldRiskPanelDisplay } from 'components/AccessRisk/SwapRevampRiskDisplay' import { useCurrency } from 'hooks/Tokens' @@ -7,8 +8,11 @@ import { useMemo } from 'react' import { Field } from 'state/swap/actions' import { useSwapState } from 'state/swap/hooks' import { logger } from 'utils/datadog' +import { warningSeverity } from 'utils/exchange' +import { isXOrder } from 'views/Swap/utils' import { SwapType } from '../../Swap/types' import { useAllTypeBestTrade } from '../../Swap/V3Swap/hooks/useAllTypeBestTrade' +import { computeTradePriceBreakdown } from '../../Swap/V3Swap/utils/exchange' import { ButtonAndDetailsPanel } from './ButtonAndDetailsPanel' import { CommitButton } from './CommitButton' import { FormMain } from './FormMainV4' @@ -90,10 +94,20 @@ export function V4SwapForm() { () => (bestOrder?.trade ? SmartRouter.getExecutionPrice(bestOrder.trade) : undefined), [bestOrder?.trade], ) - const inputCurrency = useCurrency(inputCurrencyId) const outputCurrency = useCurrency(outputCurrencyId) + const { priceImpactWithoutFee } = useMemo( + () => computeTradePriceBreakdown(isXOrder(bestOrder) ? bestOrder?.ammTrade : bestOrder?.trade), + [bestOrder], + ) + const isPriceImpactTooHigh = useMemo(() => { + const warningLevel = warningSeverity(priceImpactWithoutFee) + return warningLevel >= 3 + }, [priceImpactWithoutFee]) + const [userSlippageTolerance] = useUserSlippage() + const isSlippageTooHigh = useMemo(() => userSlippageTolerance > 500, [userSlippageTolerance]) + const shouldRiskPanelDisplay = useShouldRiskPanelDisplay(inputCurrency?.wrapped, outputCurrency?.wrapped) return ( @@ -102,9 +116,6 @@ export function V4SwapForm() { - } inputAmount={bestOrder?.trade?.inputAmount} outputAmount={bestOrder?.trade?.outputAmount} swapCommitButton={ @@ -112,7 +123,14 @@ export function V4SwapForm() { } /> - {shouldRiskPanelDisplay && } + {(shouldRiskPanelDisplay || isPriceImpactTooHigh || isSlippageTooHigh) && ( + + )}