diff --git a/src/lib/components/Swap/Output.tsx b/src/lib/components/Swap/Output.tsx index 13e9166bf2..a74e33cf2f 100644 --- a/src/lib/components/Swap/Output.tsx +++ b/src/lib/components/Swap/Output.tsx @@ -5,13 +5,12 @@ import { useAtomValue } from 'jotai/utils' import BrandedFooter from 'lib/components/BrandedFooter' import { useIsSwapFieldIndependent, useSwapAmount, useSwapCurrency, useSwapInfo } from 'lib/hooks/swap' import useCurrencyColor from 'lib/hooks/useCurrencyColor' -import useUSDCPriceImpact, { toHumanReadablePriceImpact } from 'lib/hooks/useUSDCPriceImpact' +import useUSDCPriceImpact from 'lib/hooks/useUSDCPriceImpact' import { Field } from 'lib/state/swap' import styled, { DynamicThemeProvider, ThemedText } from 'lib/theme' -import { PropsWithChildren, useMemo } from 'react' +import { PropsWithChildren } from 'react' import { TradeState } from 'state/routing/types' import { formatCurrencyAmount } from 'utils/formatCurrencyAmount' -import { getPriceImpactWarning } from 'utils/prices' import Column from '../Column' import Row from '../Row' @@ -59,8 +58,11 @@ export default function Output({ disabled, focused, children }: PropsWithChildre // different state true/null/false allow smoother color transition const hasColor = swapOutputCurrency ? Boolean(color) || null : false - const { outputUSDC, priceImpact } = useUSDCPriceImpact(inputCurrencyAmount, outputCurrencyAmount) - const priceImpactWarning = useMemo(() => getPriceImpactWarning(priceImpact), [priceImpact]) + const { + outputUSDC, + priceImpact, + warning: priceImpactWarning, + } = useUSDCPriceImpact(inputCurrencyAmount, outputCurrencyAmount) const amount = useFormattedFieldAmount({ disabled, @@ -88,11 +90,7 @@ export default function Output({ disabled, focused, children }: PropsWithChildre {outputUSDC ? `$${formatCurrencyAmount(outputUSDC, 6, 'en', 2)}` : '-'}{' '} - {priceImpact && ( - - ({toHumanReadablePriceImpact(priceImpact)}) - - )} + {priceImpact && ({priceImpact})} {balance && ( diff --git a/src/lib/components/Swap/Settings/MaxSlippageSelect.tsx b/src/lib/components/Swap/Settings/MaxSlippageSelect.tsx index c0cd40a809..de78aa6fcc 100644 --- a/src/lib/components/Swap/Settings/MaxSlippageSelect.tsx +++ b/src/lib/components/Swap/Settings/MaxSlippageSelect.tsx @@ -2,7 +2,7 @@ import { Trans } from '@lingui/macro' import { useAtom } from 'jotai' import Popover from 'lib/components/Popover' import { useTooltip } from 'lib/components/Tooltip' -import { getSlippageWarning, toPercent } from 'lib/hooks/useAllowedSlippage' +import { getSlippageWarning, toPercent } from 'lib/hooks/useSlippage' import { AlertTriangle, Check, Icon, LargeIcon, XOctagon } from 'lib/icons' import { autoSlippageAtom, maxSlippageAtom } from 'lib/state/settings' import styled, { ThemedText } from 'lib/theme' diff --git a/src/lib/components/Swap/Summary.fixture.tsx b/src/lib/components/Swap/Summary.fixture.tsx index 08eabb0879..eac24a7905 100644 --- a/src/lib/components/Swap/Summary.fixture.tsx +++ b/src/lib/components/Swap/Summary.fixture.tsx @@ -22,7 +22,7 @@ const UNI = (function () { function Fixture() { const setState = useUpdateAtom(swapAtom) const { - allowedSlippage, + slippage, trade: { trade }, } = useSwapInfo() @@ -37,7 +37,7 @@ function Fixture() { return trade ? ( - void 0} trade={trade} allowedSlippage={allowedSlippage} /> + void 0} trade={trade} slippage={slippage} /> ) : null } diff --git a/src/lib/components/Swap/Summary/Details.tsx b/src/lib/components/Swap/Summary/Details.tsx index 1d131ebb77..183a8bfd04 100644 --- a/src/lib/components/Swap/Summary/Details.tsx +++ b/src/lib/components/Swap/Summary/Details.tsx @@ -3,13 +3,12 @@ import { useLingui } from '@lingui/react' import { Trade } from '@uniswap/router-sdk' import { Currency, Percent, TradeType } from '@uniswap/sdk-core' import { useAtomValue } from 'jotai/utils' -import { getSlippageWarning } from 'lib/hooks/useAllowedSlippage' import { feeOptionsAtom } from 'lib/state/swap' import styled, { Color, ThemedText } from 'lib/theme' import { useMemo } from 'react' import { currencyId } from 'utils/currencyId' import { formatCurrencyAmount } from 'utils/formatCurrencyAmount' -import { computeRealizedLPFeeAmount, computeRealizedPriceImpact, getPriceImpactWarning } from 'utils/prices' +import { computeRealizedLPFeeAmount } from 'utils/prices' import Row from '../../Row' @@ -37,16 +36,16 @@ function Detail({ label, value, color }: DetailProps) { interface DetailsProps { trade: Trade - allowedSlippage: Percent + slippage: { auto: boolean; allowed: Percent; warning?: Color } + usdcPriceImpact: { priceImpact?: string; warning?: Color } } -export default function Details({ trade, allowedSlippage }: DetailsProps) { +export default function Details({ trade, slippage, usdcPriceImpact }: DetailsProps) { const { inputAmount, outputAmount } = trade const inputCurrency = inputAmount.currency const outputCurrency = outputAmount.currency const integrator = window.location.hostname const feeOptions = useAtomValue(feeOptionsAtom) - const priceImpact = useMemo(() => computeRealizedPriceImpact(trade), [trade]) const lpFeeAmount = useMemo(() => computeRealizedLPFeeAmount(trade), [trade]) const { i18n } = useLingui() @@ -62,7 +61,9 @@ export default function Details({ trade, allowedSlippage }: DetailsProps) { } } - rows.push([t`Price impact`, `${priceImpact.toFixed(2)}%`, getPriceImpactWarning(priceImpact)]) + if (usdcPriceImpact.priceImpact) { + rows.push([t`Price impact`, usdcPriceImpact.priceImpact, usdcPriceImpact.warning]) + } if (lpFeeAmount) { const parsedLpFee = formatCurrencyAmount(lpFeeAmount, 6, i18n.locale) @@ -70,24 +71,24 @@ export default function Details({ trade, allowedSlippage }: DetailsProps) { } if (trade.tradeType === TradeType.EXACT_OUTPUT) { - const localizedMaxSent = formatCurrencyAmount(trade.maximumAmountIn(allowedSlippage), 6, i18n.locale) + const localizedMaxSent = formatCurrencyAmount(trade.maximumAmountIn(slippage.allowed), 6, i18n.locale) rows.push([t`Maximum sent`, `${localizedMaxSent} ${inputCurrency.symbol}`]) } if (trade.tradeType === TradeType.EXACT_INPUT) { - const localizedMaxSent = formatCurrencyAmount(trade.minimumAmountOut(allowedSlippage), 6, i18n.locale) + const localizedMaxSent = formatCurrencyAmount(trade.minimumAmountOut(slippage.allowed), 6, i18n.locale) rows.push([t`Minimum received`, `${localizedMaxSent} ${outputCurrency.symbol}`]) } - rows.push([t`Slippage tolerance`, `${allowedSlippage.toFixed(2)}%`, getSlippageWarning(allowedSlippage)]) + rows.push([t`Slippage tolerance`, `${slippage.allowed.toFixed(2)}%`, slippage.warning]) return rows }, [ feeOptions, - priceImpact, + usdcPriceImpact, lpFeeAmount, trade, - allowedSlippage, + slippage, outputAmount, i18n.locale, integrator, diff --git a/src/lib/components/Swap/Summary/Summary.tsx b/src/lib/components/Swap/Summary/Summary.tsx index 57ff640e6f..876f9f01b9 100644 --- a/src/lib/components/Swap/Summary/Summary.tsx +++ b/src/lib/components/Swap/Summary/Summary.tsx @@ -1,11 +1,10 @@ import { useLingui } from '@lingui/react' -import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core' -import useUSDCPriceImpact, { toHumanReadablePriceImpact } from 'lib/hooks/useUSDCPriceImpact' +import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core' +import useUSDCPriceImpact from 'lib/hooks/useUSDCPriceImpact' import { ArrowRight } from 'lib/icons' import { ThemedText } from 'lib/theme' -import { useMemo } from 'react' +import { PropsWithChildren } from 'react' import { formatCurrencyAmount } from 'utils/formatCurrencyAmount' -import { getPriceImpactWarning } from 'utils/prices' import Column from '../../Column' import Row from '../../Row' @@ -14,12 +13,10 @@ import TokenImg from '../../TokenImg' interface TokenValueProps { input: CurrencyAmount usdc?: CurrencyAmount - priceImpact?: Percent } -function TokenValue({ input, usdc, priceImpact }: TokenValueProps) { +function TokenValue({ input, usdc, children }: PropsWithChildren) { const { i18n } = useLingui() - const priceImpactWarning = useMemo(() => getPriceImpactWarning(priceImpact), [priceImpact]) return ( @@ -29,16 +26,12 @@ function TokenValue({ input, usdc, priceImpact }: TokenValueProps) { {usdc && ( - - + + ${formatCurrencyAmount(usdc, 6, 'en', 2)} - {priceImpact && ( - - ({toHumanReadablePriceImpact(priceImpact)}) - - )} - - + {children} + + )} ) @@ -47,17 +40,19 @@ function TokenValue({ input, usdc, priceImpact }: TokenValueProps) { interface SummaryProps { input: CurrencyAmount output: CurrencyAmount - showUSDC?: true + usdcPriceImpact?: ReturnType } -export default function Summary({ input, output, showUSDC }: SummaryProps) { - const { inputUSDC, outputUSDC, priceImpact } = useUSDCPriceImpact(input, output) +export default function Summary({ input, output, usdcPriceImpact }: SummaryProps) { + const { inputUSDC, outputUSDC, priceImpact, warning: priceImpactWarning } = usdcPriceImpact || {} return ( - - + + - + + {priceImpact && ({priceImpact})} + ) } diff --git a/src/lib/components/Swap/Summary/index.tsx b/src/lib/components/Swap/Summary/index.tsx index 1d8ffc8f3b..4047fbf566 100644 --- a/src/lib/components/Swap/Summary/index.tsx +++ b/src/lib/components/Swap/Summary/index.tsx @@ -1,17 +1,17 @@ import { Trans } from '@lingui/macro' import { useLingui } from '@lingui/react' import { Trade } from '@uniswap/router-sdk' -import { Currency, Percent, TradeType } from '@uniswap/sdk-core' +import { Currency, TradeType } from '@uniswap/sdk-core' import { IconButton } from 'lib/components/Button' import { useSwapTradeType } from 'lib/hooks/swap' -import { getSlippageWarning } from 'lib/hooks/useAllowedSlippage' import useScrollbar from 'lib/hooks/useScrollbar' +import { Slippage } from 'lib/hooks/useSlippage' +import useUSDCPriceImpact from 'lib/hooks/useUSDCPriceImpact' import { AlertTriangle, BarChart, Expando, Info } from 'lib/icons' -import styled, { ThemedText } from 'lib/theme' +import styled, { Color, ThemedText } from 'lib/theme' import formatLocaleNumber from 'lib/utils/formatLocaleNumber' import { useMemo, useState } from 'react' import { formatCurrencyAmount, formatPrice } from 'utils/formatCurrencyAmount' -import { computeRealizedPriceImpact, getPriceImpactWarning } from 'utils/prices' import { tradeMeaningfullyDiffers } from 'utils/tradeMeaningFullyDiffer' import ActionButton, { Action } from '../../ActionButton' @@ -77,17 +77,38 @@ const Body = styled(Column)<{ open: boolean }>` } ` +function Subhead({ priceImpact, slippage }: { priceImpact: { warning?: Color }; slippage: { warning?: Color } }) { + return ( + + {priceImpact.warning || slippage.warning ? ( + + ) : ( + + )} + + {priceImpact.warning ? ( + High price impact + ) : slippage.warning ? ( + High slippage + ) : ( + Swap details + )} + + + ) +} + interface SummaryDialogProps { trade: Trade - allowedSlippage: Percent + slippage: Slippage onConfirm: () => void } -export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDialogProps) { +export function SummaryDialog({ trade, slippage, onConfirm }: SummaryDialogProps) { const { inputAmount, outputAmount, executionPrice } = trade const inputCurrency = inputAmount.currency const outputCurrency = outputAmount.currency - const priceImpact = useMemo(() => computeRealizedPriceImpact(trade), [trade]) + const usdcPriceImpact = useUSDCPriceImpact(inputAmount, outputAmount) const tradeType = useSwapTradeType() const { i18n } = useLingui() @@ -95,10 +116,6 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial const [details, setDetails] = useState(null) const scrollbar = useScrollbar(details) - const warning = useMemo(() => { - return getPriceImpactWarning(priceImpact) || getSlippageWarning(allowedSlippage) - }, [allowedSlippage, priceImpact]) - const [ackPriceImpact, setAckPriceImpact] = useState(false) const [confirmedTrade, setConfirmedTrade] = useState(trade) @@ -115,7 +132,7 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial onClick: () => setConfirmedTrade(trade), children: Accept, } - } else if (getPriceImpactWarning(priceImpact) === 'error' && !ackPriceImpact) { + } else if (usdcPriceImpact.warning === 'error' && !ackPriceImpact) { return { message: High price impact, onClick: () => setAckPriceImpact(true), @@ -123,7 +140,7 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial } } return - }, [ackPriceImpact, doesTradeDiffer, priceImpact, trade]) + }, [ackPriceImpact, doesTradeDiffer, trade, usdcPriceImpact.warning]) if (!(inputAmount && outputAmount && inputCurrency && outputCurrency)) { return null @@ -134,7 +151,7 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial
Swap summary} ruled /> - + {formatLocaleNumber({ number: 1, sigFigs: 1, locale: i18n.locale })} {inputCurrency.symbol} ={' '} @@ -144,19 +161,14 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial - - {warning ? : } - - Swap details - - + setOpen(!open)} icon={Expando} iconProps={{ open }} /> -
+
@@ -164,13 +176,13 @@ export function SummaryDialog({ trade, allowedSlippage, onConfirm }: SummaryDial {tradeType === TradeType.EXACT_INPUT && ( You will receive at least{' '} - {formatCurrencyAmount(trade.minimumAmountOut(allowedSlippage), 6, i18n.locale)} {outputCurrency.symbol}{' '} + {formatCurrencyAmount(trade.minimumAmountOut(slippage.allowed), 6, i18n.locale)} {outputCurrency.symbol}{' '} or the transaction will revert. )} {tradeType === TradeType.EXACT_OUTPUT && ( - You will send at most {formatCurrencyAmount(trade.maximumAmountIn(allowedSlippage), 6, i18n.locale)}{' '} + You will send at most {formatCurrencyAmount(trade.maximumAmountIn(slippage.allowed), 6, i18n.locale)}{' '} {inputCurrency.symbol} or the transaction will revert. )} diff --git a/src/lib/components/Swap/SwapButton.tsx b/src/lib/components/Swap/SwapButton.tsx index 6146f84932..f03bdddf74 100644 --- a/src/lib/components/Swap/SwapButton.tsx +++ b/src/lib/components/Swap/SwapButton.tsx @@ -41,7 +41,7 @@ export default function SwapButton({ disabled }: SwapButtonProps) { const { tokenColorExtraction } = useTheme() const { - allowedSlippage, + slippage, currencies: { [Field.INPUT]: inputCurrency }, currencyBalances: { [Field.INPUT]: inputCurrencyBalance }, feeOptions, @@ -64,13 +64,13 @@ export default function SwapButton({ disabled }: SwapButtonProps) { // TODO(zzmp): Return an optimized trade directly from useSwapInfo. const optimizedTrade = // Use trade.trade if there is no swap optimized trade. This occurs if approvals are still pending. - useSwapApprovalOptimizedTrade(trade.trade, allowedSlippage, useIsPendingApproval) || trade.trade + useSwapApprovalOptimizedTrade(trade.trade, slippage.allowed, useIsPendingApproval) || trade.trade const approvalCurrencyAmount = useSwapCurrencyAmount(Field.INPUT) const { approvalState, signatureData, handleApproveOrPermit } = useApproveOrPermit( optimizedTrade, - allowedSlippage, + slippage.allowed, useIsPendingApproval, approvalCurrencyAmount ) @@ -151,7 +151,7 @@ export default function SwapButton({ disabled }: SwapButtonProps) { // the callback to execute the swap const { callback: swapCallback } = useSwapCallback({ trade: optimizedTrade, - allowedSlippage, + allowedSlippage: slippage.allowed, recipientAddressOrName: account ?? null, signatureData, deadline, @@ -229,7 +229,7 @@ export default function SwapButton({ disabled }: SwapButtonProps) { {activeTrade && ( - + )} diff --git a/src/lib/components/Swap/Toolbar/Caption.tsx b/src/lib/components/Swap/Toolbar/Caption.tsx index 8a4b238a7e..1aa7f9cda6 100644 --- a/src/lib/components/Swap/Toolbar/Caption.tsx +++ b/src/lib/components/Swap/Toolbar/Caption.tsx @@ -5,13 +5,12 @@ import Rule from 'lib/components/Rule' import Tooltip from 'lib/components/Tooltip' import { loadingCss } from 'lib/css/loading' import { WrapType } from 'lib/hooks/swap/useWrapCallback' -import useUSDCPriceImpact, { toHumanReadablePriceImpact } from 'lib/hooks/useUSDCPriceImpact' +import useUSDCPriceImpact from 'lib/hooks/useUSDCPriceImpact' import { AlertTriangle, Icon, Info, InlineSpinner } from 'lib/icons' import styled, { ThemedText } from 'lib/theme' import { ReactNode, useCallback, useMemo, useState } from 'react' import { InterfaceTrade } from 'state/routing/types' import { formatCurrencyAmount } from 'utils/formatCurrencyAmount' -import { getPriceImpactWarning } from 'utils/prices' import { TextButton } from '../../Button' import Row from '../../Row' @@ -83,8 +82,7 @@ export function WrapCurrency({ loading, wrapType }: { loading: boolean; wrapType export function Trade({ trade }: { trade: InterfaceTrade }) { const [flip, setFlip] = useState(true) const { inputAmount: input, outputAmount: output, executionPrice } = trade - const { inputUSDC, outputUSDC, priceImpact } = useUSDCPriceImpact(input, output) - const isPriceImpactHigh = priceImpact && getPriceImpactWarning(priceImpact) + const { inputUSDC, outputUSDC, priceImpact, warning: priceImpactWarning } = useUSDCPriceImpact(input, output) const ratio = useMemo(() => { const [a, b] = flip ? [output, input] : [input, output] @@ -111,13 +109,12 @@ export function Trade({ trade }: { trade: InterfaceTrade - + - {isPriceImpactHigh && ( + {priceImpactWarning && ( <> - The output amount is estimated at {toHumanReadablePriceImpact(priceImpact)} less than the input amount - due to high price impact + The output amount is estimated at {priceImpact} less than the input amount due to high price impact diff --git a/src/lib/hooks/swap/useSwapInfo.tsx b/src/lib/hooks/swap/useSwapInfo.tsx index 289101daf7..10f95c571f 100644 --- a/src/lib/hooks/swap/useSwapInfo.tsx +++ b/src/lib/hooks/swap/useSwapInfo.tsx @@ -11,7 +11,7 @@ import { InterfaceTrade, TradeState } from 'state/routing/types' import { isAddress } from '../../../utils' import useActiveWeb3React from '../useActiveWeb3React' -import useAllowedSlippage from '../useAllowedSlippage' +import useSlippage, { Slippage } from '../useSlippage' import { useBestTrade } from './useBestTrade' interface SwapInfo { @@ -22,7 +22,7 @@ interface SwapInfo { trade?: InterfaceTrade state: TradeState } - allowedSlippage: Percent + slippage: Slippage feeOptions: FeeOptions | undefined } @@ -89,7 +89,7 @@ function useComputeSwapInfo(): SwapInfo { [trade.trade?.inputAmount, trade.trade?.outputAmount] ) - const allowedSlippage = useAllowedSlippage(trade.trade) + const slippage = useSlippage(trade.trade) const inputError = useMemo(() => { let inputError: ReactNode | undefined @@ -116,14 +116,14 @@ function useComputeSwapInfo(): SwapInfo { } // compare input balance to max input based on version - const [balanceIn, amountIn] = [currencyBalances[Field.INPUT], trade.trade?.maximumAmountIn(allowedSlippage)] + const [balanceIn, amountIn] = [currencyBalances[Field.INPUT], trade.trade?.maximumAmountIn(slippage.allowed)] if (balanceIn && amountIn && balanceIn.lessThan(amountIn)) { inputError = Insufficient {amountIn.currency.symbol} balance } return inputError - }, [account, allowedSlippage, currencies, currencyBalances, parsedAmount, to, trade.trade]) + }, [account, slippage.allowed, currencies, currencyBalances, parsedAmount, to, trade.trade]) return useMemo( () => ({ @@ -132,10 +132,10 @@ function useComputeSwapInfo(): SwapInfo { inputError, trade, tradeCurrencyAmounts, - allowedSlippage, + slippage, feeOptions, }), - [currencies, currencyBalances, inputError, trade, tradeCurrencyAmounts, allowedSlippage, feeOptions] + [currencies, currencyBalances, inputError, trade, tradeCurrencyAmounts, slippage, feeOptions] ) } @@ -144,7 +144,7 @@ const swapInfoAtom = atom({ currencyBalances: {}, trade: { state: TradeState.INVALID }, tradeCurrencyAmounts: {}, - allowedSlippage: new Percent(0), + slippage: { auto: true, allowed: new Percent(0) }, feeOptions: undefined, }) diff --git a/src/lib/hooks/useAllowedSlippage.ts b/src/lib/hooks/useSlippage.ts similarity index 57% rename from src/lib/hooks/useAllowedSlippage.ts rename to src/lib/hooks/useSlippage.ts index d088472a8c..9caba1914c 100644 --- a/src/lib/hooks/useAllowedSlippage.ts +++ b/src/lib/hooks/useSlippage.ts @@ -11,12 +11,24 @@ export function toPercent(maxSlippage: number | undefined): Percent | undefined return new Percent(numerator, 10_000) } -/** Returns the user-inputted max slippage. */ -export default function useAllowedSlippage(trade: InterfaceTrade | undefined): Percent { - const autoSlippage = useAutoSlippageTolerance(trade) +export interface Slippage { + auto: boolean + allowed: Percent + warning?: 'warning' | 'error' +} + +/** Returns the allowed slippage, and whether it is auto-slippage. */ +export default function useSlippage(trade: InterfaceTrade | undefined): Slippage { + const shouldUseAutoSlippage = useAtomValue(autoSlippageAtom) + const autoSlippage = useAutoSlippageTolerance(shouldUseAutoSlippage ? trade : undefined) const maxSlippageValue = useAtomValue(maxSlippageAtom) const maxSlippage = useMemo(() => toPercent(maxSlippageValue), [maxSlippageValue]) - return useAtomValue(autoSlippageAtom) ? autoSlippage : maxSlippage ?? autoSlippage + return useMemo(() => { + const auto = shouldUseAutoSlippage || !maxSlippage + const allowed = shouldUseAutoSlippage ? autoSlippage : maxSlippage ?? autoSlippage + const warning = auto ? undefined : getSlippageWarning(allowed) + return { auto, allowed, warning } + }, [autoSlippage, maxSlippage, shouldUseAutoSlippage]) } export const MAX_VALID_SLIPPAGE = new Percent(1, 2) diff --git a/src/lib/hooks/useUSDCPriceImpact.ts b/src/lib/hooks/useUSDCPriceImpact.ts index eb6b491987..4b135ca978 100644 --- a/src/lib/hooks/useUSDCPriceImpact.ts +++ b/src/lib/hooks/useUSDCPriceImpact.ts @@ -2,24 +2,36 @@ import { Currency, CurrencyAmount, Percent, Token } from '@uniswap/sdk-core' import { useUSDCValue } from 'hooks/useUSDCPrice' import { useMemo } from 'react' import { computeFiatValuePriceImpact } from 'utils/computeFiatValuePriceImpact' +import { getPriceImpactWarning } from 'utils/prices' +/** + * Computes input/output USDC equivalents and the price impact. + * Returns the price impact as a human readable string. + */ export default function useUSDCPriceImpact( inputAmount: CurrencyAmount | undefined, outputAmount: CurrencyAmount | undefined ): { inputUSDC?: CurrencyAmount outputUSDC?: CurrencyAmount - priceImpact?: Percent + priceImpact?: string + warning?: 'warning' | 'error' } { const inputUSDC = useUSDCValue(inputAmount) ?? undefined const outputUSDC = useUSDCValue(outputAmount) ?? undefined return useMemo(() => { const priceImpact = computeFiatValuePriceImpact(inputUSDC, outputUSDC) - return { inputUSDC, outputUSDC, priceImpact } + const warning = getPriceImpactWarning(priceImpact) + return { + inputUSDC, + outputUSDC, + priceImpact: priceImpact && toHumanReadablePriceImpact(priceImpact), + warning, + } }, [inputUSDC, outputUSDC]) } -export function toHumanReadablePriceImpact(priceImpact: Percent): string { +function toHumanReadablePriceImpact(priceImpact: Percent): string { const sign = priceImpact.lessThan(0) ? '+' : '' const number = parseFloat(priceImpact.multiply(-1)?.toSignificant(3)) return `${sign}${number}%`