Commit 184a1419 authored by Connor McEwen's avatar Connor McEwen Committed by GitHub

feat: fetch stablecoin price with SOR, PI warning (#4217)

* feat: fetch stablecoins price with SOR, PI warning

* calculate realized price impact

* remove unrelated changes

* dupe import

* pr feedback

* use the same calculation function for PI

* use proper var
parent 6cb6faa9
...@@ -10,7 +10,7 @@ import { InterfaceTrade } from 'state/routing/types' ...@@ -10,7 +10,7 @@ import { InterfaceTrade } from 'state/routing/types'
import styled, { ThemeContext } from 'styled-components/macro' import styled, { ThemeContext } from 'styled-components/macro'
import { Separator, ThemedText } from '../../theme' import { Separator, ThemedText } from '../../theme'
import { computeRealizedLPFeePercent } from '../../utils/prices' import { computeRealizedPriceImpact } from '../../utils/prices'
import { AutoColumn } from '../Column' import { AutoColumn } from '../Column'
import { RowBetween, RowFixed } from '../Row' import { RowBetween, RowFixed } from '../Row'
import { MouseoverTooltip } from '../Tooltip' import { MouseoverTooltip } from '../Tooltip'
...@@ -45,13 +45,6 @@ function TextWithLoadingPlaceholder({ ...@@ -45,13 +45,6 @@ function TextWithLoadingPlaceholder({
) )
} }
export function getPriceImpactPercent(
lpFeePercent: Percent,
trade: InterfaceTrade<Currency, Currency, TradeType>
): Percent {
return trade.priceImpact.subtract(lpFeePercent)
}
export function AdvancedSwapDetails({ export function AdvancedSwapDetails({
trade, trade,
allowedSlippage, allowedSlippage,
...@@ -63,11 +56,10 @@ export function AdvancedSwapDetails({ ...@@ -63,11 +56,10 @@ export function AdvancedSwapDetails({
const nativeCurrency = useNativeCurrency() const nativeCurrency = useNativeCurrency()
const { expectedOutputAmount, priceImpact } = useMemo(() => { const { expectedOutputAmount, priceImpact } = useMemo(() => {
if (!trade) return { expectedOutputAmount: undefined, priceImpact: undefined } return {
const expectedOutputAmount = trade.outputAmount expectedOutputAmount: trade?.outputAmount,
const realizedLpFeePercent = computeRealizedLPFeePercent(trade) priceImpact: trade ? computeRealizedPriceImpact(trade) : undefined,
const priceImpact = getPriceImpactPercent(realizedLpFeePercent, trade) }
return { expectedOutputAmount, priceImpact }
}, [trade]) }, [trade])
return !trade ? null : ( return !trade ? null : (
......
...@@ -3,13 +3,15 @@ import { Percent } from '@uniswap/sdk-core' ...@@ -3,13 +3,15 @@ import { Percent } from '@uniswap/sdk-core'
import { warningSeverity } from '../../utils/prices' import { warningSeverity } from '../../utils/prices'
import { ErrorText } from './styleds' import { ErrorText } from './styleds'
export const formatPriceImpact = (priceImpact: Percent) => `${priceImpact.multiply(-1).toFixed(2)}%`
/** /**
* Formatted version of price impact text with warning colors * Formatted version of price impact text with warning colors
*/ */
export default function FormattedPriceImpact({ priceImpact }: { priceImpact?: Percent }) { export default function FormattedPriceImpact({ priceImpact }: { priceImpact?: Percent }) {
return ( return (
<ErrorText fontWeight={500} fontSize={14} severity={warningSeverity(priceImpact)}> <ErrorText fontWeight={500} fontSize={14} severity={warningSeverity(priceImpact)}>
{priceImpact ? `${priceImpact.multiply(-1).toFixed(2)}%` : '-'} {priceImpact ? formatPriceImpact(priceImpact) : '-'}
</ErrorText> </ErrorText>
) )
} }
import { Trans } from '@lingui/macro'
import { Percent } from '@uniswap/sdk-core'
import { OutlineCard } from 'components/Card'
import { useContext } from 'react'
import styled, { ThemeContext } from 'styled-components/macro'
import { opacify } from 'theme/utils'
import { ThemedText } from '../../theme'
import { AutoColumn } from '../Column'
import { RowBetween, RowFixed } from '../Row'
import { MouseoverTooltip } from '../Tooltip'
import { formatPriceImpact } from './FormattedPriceImpact'
const StyledCard = styled(OutlineCard)`
padding: 12px;
border: 1px solid ${({ theme }) => opacify(24, theme.deprecated_error)};
`
interface PriceImpactWarningProps {
priceImpact: Percent
}
export default function PriceImpactWarning({ priceImpact }: PriceImpactWarningProps) {
const theme = useContext(ThemeContext)
return (
<StyledCard>
<AutoColumn gap="8px">
<MouseoverTooltip
text={
<Trans>
A swap of this size may have a high price impact, given the current liquidity in the pool. There may be a
large difference between the amount of your input token and what you will receive in the output token
</Trans>
}
>
<RowBetween>
<RowFixed>
<ThemedText.DeprecatedSubHeader color={theme.deprecated_error}>
<Trans>Price impact warning</Trans>
</ThemedText.DeprecatedSubHeader>
</RowFixed>
<ThemedText.DeprecatedLabel textAlign="right" fontSize={14} color={theme.deprecated_error}>
{formatPriceImpact(priceImpact)}
</ThemedText.DeprecatedLabel>
</RowBetween>
</MouseoverTooltip>
</AutoColumn>
</StyledCard>
)
}
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Currency, Percent, TradeType } from '@uniswap/sdk-core' import { Currency, Percent, TradeType } from '@uniswap/sdk-core'
import { ElementName, EventName } from 'components/AmplitudeAnalytics/constants' import { ElementName, Event, EventName } from 'components/AmplitudeAnalytics/constants'
import { Event } from 'components/AmplitudeAnalytics/constants'
import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent' import { TraceEvent } from 'components/AmplitudeAnalytics/TraceEvent'
import { import {
formatPercentInBasisPointsNumber, formatPercentInBasisPointsNumber,
...@@ -16,11 +15,10 @@ import { ReactNode } from 'react' ...@@ -16,11 +15,10 @@ import { ReactNode } from 'react'
import { Text } from 'rebass' import { Text } from 'rebass'
import { InterfaceTrade } from 'state/routing/types' import { InterfaceTrade } from 'state/routing/types'
import { useClientSideRouter, useUserSlippageTolerance } from 'state/user/hooks' import { useClientSideRouter, useUserSlippageTolerance } from 'state/user/hooks'
import { computeRealizedLPFeePercent } from 'utils/prices' import { computeRealizedPriceImpact } from 'utils/prices'
import { ButtonError } from '../Button' import { ButtonError } from '../Button'
import { AutoRow } from '../Row' import { AutoRow } from '../Row'
import { getPriceImpactPercent } from './AdvancedSwapDetails'
import { SwapCallbackError } from './styleds' import { SwapCallbackError } from './styleds'
interface AnalyticsEventProps { interface AnalyticsEventProps {
...@@ -32,7 +30,6 @@ interface AnalyticsEventProps { ...@@ -32,7 +30,6 @@ interface AnalyticsEventProps {
isAutoRouterApi: boolean isAutoRouterApi: boolean
tokenInAmountUsd: string | undefined tokenInAmountUsd: string | undefined
tokenOutAmountUsd: string | undefined tokenOutAmountUsd: string | undefined
lpFeePercent: Percent
swapQuoteReceivedDate: Date | undefined swapQuoteReceivedDate: Date | undefined
} }
...@@ -45,7 +42,6 @@ const formatAnalyticsEventProperties = ({ ...@@ -45,7 +42,6 @@ const formatAnalyticsEventProperties = ({
isAutoRouterApi, isAutoRouterApi,
tokenInAmountUsd, tokenInAmountUsd,
tokenOutAmountUsd, tokenOutAmountUsd,
lpFeePercent,
swapQuoteReceivedDate, swapQuoteReceivedDate,
}: AnalyticsEventProps) => ({ }: AnalyticsEventProps) => ({
estimated_network_fee_usd: trade.gasUseEstimateUSD ? formatToDecimal(trade.gasUseEstimateUSD, 2) : undefined, estimated_network_fee_usd: trade.gasUseEstimateUSD ? formatToDecimal(trade.gasUseEstimateUSD, 2) : undefined,
...@@ -59,7 +55,7 @@ const formatAnalyticsEventProperties = ({ ...@@ -59,7 +55,7 @@ const formatAnalyticsEventProperties = ({
token_out_symbol: trade.outputAmount.currency.symbol, token_out_symbol: trade.outputAmount.currency.symbol,
token_in_amount: formatToDecimal(trade.inputAmount, trade.inputAmount.currency.decimals), token_in_amount: formatToDecimal(trade.inputAmount, trade.inputAmount.currency.decimals),
token_out_amount: formatToDecimal(trade.outputAmount, trade.outputAmount.currency.decimals), token_out_amount: formatToDecimal(trade.outputAmount, trade.outputAmount.currency.decimals),
price_impact_basis_points: formatPercentInBasisPointsNumber(getPriceImpactPercent(lpFeePercent, trade)), price_impact_basis_points: formatPercentInBasisPointsNumber(computeRealizedPriceImpact(trade)),
allowed_slippage_basis_points: formatPercentInBasisPointsNumber(allowedSlippage), allowed_slippage_basis_points: formatPercentInBasisPointsNumber(allowedSlippage),
is_auto_router_api: isAutoRouterApi, is_auto_router_api: isAutoRouterApi,
is_auto_slippage: isAutoSlippage, is_auto_slippage: isAutoSlippage,
...@@ -94,7 +90,6 @@ export default function SwapModalFooter({ ...@@ -94,7 +90,6 @@ export default function SwapModalFooter({
const [clientSideRouter] = useClientSideRouter() const [clientSideRouter] = useClientSideRouter()
const tokenInAmountUsd = useStablecoinValue(trade.inputAmount)?.toFixed(2) const tokenInAmountUsd = useStablecoinValue(trade.inputAmount)?.toFixed(2)
const tokenOutAmountUsd = useStablecoinValue(trade.outputAmount)?.toFixed(2) const tokenOutAmountUsd = useStablecoinValue(trade.outputAmount)?.toFixed(2)
const lpFeePercent = computeRealizedLPFeePercent(trade)
return ( return (
<> <>
...@@ -112,7 +107,6 @@ export default function SwapModalFooter({ ...@@ -112,7 +107,6 @@ export default function SwapModalFooter({
isAutoRouterApi: !clientSideRouter, isAutoRouterApi: !clientSideRouter,
tokenInAmountUsd, tokenInAmountUsd,
tokenOutAmountUsd, tokenOutAmountUsd,
lpFeePercent,
swapQuoteReceivedDate, swapQuoteReceivedDate,
})} })}
> >
......
import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
import { Pair, Trade } from '@uniswap/v2-sdk'
import { useMemo } from 'react'
import { isTradeBetter } from 'utils/isTradeBetter'
import { BETTER_TRADE_LESS_HOPS_THRESHOLD } from '../constants/misc'
import { useAllCurrencyCombinations } from './useAllCurrencyCombinations'
import { PairState, useV2Pairs } from './useV2Pairs'
function useAllCommonPairs(currencyA?: Currency, currencyB?: Currency): Pair[] {
const allCurrencyCombinations = useAllCurrencyCombinations(currencyA, currencyB)
const allPairs = useV2Pairs(allCurrencyCombinations)
return useMemo(
() =>
Object.values(
allPairs
// filter out invalid pairs
.filter((result): result is [PairState.EXISTS, Pair] => Boolean(result[0] === PairState.EXISTS && result[1]))
.map(([, pair]) => pair)
),
[allPairs]
)
}
const MAX_HOPS = 3
/**
* Returns the best v2 trade for a desired swap
* @param tradeType whether the swap is an exact in/out
* @param amountSpecified the exact amount to swap in/out
* @param otherCurrency the desired output/payment currency
*/
export function useBestV2Trade(
tradeType: TradeType.EXACT_INPUT | TradeType.EXACT_OUTPUT,
amountSpecified?: CurrencyAmount<Currency>,
otherCurrency?: Currency,
{ maxHops = MAX_HOPS } = {}
): Trade<Currency, Currency, TradeType.EXACT_INPUT | TradeType.EXACT_OUTPUT> | null {
const [currencyIn, currencyOut] = useMemo(
() =>
tradeType === TradeType.EXACT_INPUT
? [amountSpecified?.currency, otherCurrency]
: [otherCurrency, amountSpecified?.currency],
[tradeType, amountSpecified, otherCurrency]
)
const allowedPairs = useAllCommonPairs(currencyIn, currencyOut)
return useMemo(() => {
if (amountSpecified && currencyIn && currencyOut && allowedPairs.length > 0) {
if (maxHops === 1) {
const options = { maxHops: 1, maxNumResults: 1 }
if (tradeType === TradeType.EXACT_INPUT) {
const amountIn = amountSpecified
return Trade.bestTradeExactIn(allowedPairs, amountIn, currencyOut, options)[0] ?? null
} else {
const amountOut = amountSpecified
return Trade.bestTradeExactOut(allowedPairs, currencyIn, amountOut, options)[0] ?? null
}
}
// search through trades with varying hops, find best trade out of them
let bestTradeSoFar: Trade<Currency, Currency, TradeType.EXACT_INPUT | TradeType.EXACT_OUTPUT> | null = null
for (let i = 1; i <= maxHops; i++) {
const options = { maxHops: i, maxNumResults: 1 }
let currentTrade: Trade<Currency, Currency, TradeType.EXACT_INPUT | TradeType.EXACT_OUTPUT> | null
if (tradeType === TradeType.EXACT_INPUT) {
const amountIn = amountSpecified
currentTrade = Trade.bestTradeExactIn(allowedPairs, amountIn, currencyOut, options)[0] ?? null
} else {
const amountOut = amountSpecified
currentTrade = Trade.bestTradeExactOut(allowedPairs, currencyIn, amountOut, options)[0] ?? null
}
// if current trade is best yet, save it
if (isTradeBetter(bestTradeSoFar, currentTrade, BETTER_TRADE_LESS_HOPS_THRESHOLD)) {
bestTradeSoFar = currentTrade
}
}
return bestTradeSoFar
}
return null
}, [tradeType, amountSpecified, currencyIn, currencyOut, allowedPairs, maxHops])
}
...@@ -2,11 +2,10 @@ import { Currency, CurrencyAmount, Price, Token, TradeType } from '@uniswap/sdk- ...@@ -2,11 +2,10 @@ import { Currency, CurrencyAmount, Price, Token, TradeType } from '@uniswap/sdk-
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount' import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
import { useMemo, useRef } from 'react' import { useMemo, useRef } from 'react'
import { RouterPreference, useRoutingAPITrade } from 'state/routing/useRoutingAPITrade'
import { SupportedChainId } from '../constants/chains' import { SupportedChainId } from '../constants/chains'
import { CUSD_CELO, DAI_OPTIMISM, USDC_ARBITRUM, USDC_MAINNET, USDC_POLYGON } from '../constants/tokens' import { CUSD_CELO, DAI_OPTIMISM, USDC_ARBITRUM, USDC_MAINNET, USDC_POLYGON } from '../constants/tokens'
import { useBestV2Trade } from './useBestV2Trade'
import { useClientSideV3Trade } from './useClientSideV3Trade'
// Stablecoin amounts used when calculating spot price for a given currency. // Stablecoin amounts used when calculating spot price for a given currency.
// The amount is large enough to filter low liquidity pairs. // The amount is large enough to filter low liquidity pairs.
...@@ -28,11 +27,7 @@ export default function useStablecoinPrice(currency?: Currency): Price<Currency, ...@@ -28,11 +27,7 @@ export default function useStablecoinPrice(currency?: Currency): Price<Currency,
const amountOut = chainId ? STABLECOIN_AMOUNT_OUT[chainId] : undefined const amountOut = chainId ? STABLECOIN_AMOUNT_OUT[chainId] : undefined
const stablecoin = amountOut?.currency const stablecoin = amountOut?.currency
// TODO(#2808): remove dependency on useBestV2Trade const { trade } = useRoutingAPITrade(TradeType.EXACT_OUTPUT, amountOut, currency, RouterPreference.CLIENT)
const v2USDCTrade = useBestV2Trade(TradeType.EXACT_OUTPUT, amountOut, currency, {
maxHops: 2,
})
const v3USDCTrade = useClientSideV3Trade(TradeType.EXACT_OUTPUT, amountOut, currency)
const price = useMemo(() => { const price = useMemo(() => {
if (!currency || !stablecoin) { if (!currency || !stablecoin) {
return undefined return undefined
...@@ -43,17 +38,13 @@ export default function useStablecoinPrice(currency?: Currency): Price<Currency, ...@@ -43,17 +38,13 @@ export default function useStablecoinPrice(currency?: Currency): Price<Currency,
return new Price(stablecoin, stablecoin, '1', '1') return new Price(stablecoin, stablecoin, '1', '1')
} }
// use v2 price if available, v3 as fallback if (trade) {
if (v2USDCTrade) { const { numerator, denominator } = trade.routes[0].midPrice
const { numerator, denominator } = v2USDCTrade.route.midPrice
return new Price(currency, stablecoin, denominator, numerator)
} else if (v3USDCTrade.trade) {
const { numerator, denominator } = v3USDCTrade.trade.routes[0].midPrice
return new Price(currency, stablecoin, denominator, numerator) return new Price(currency, stablecoin, denominator, numerator)
} }
return undefined return undefined
}, [currency, stablecoin, v2USDCTrade, v3USDCTrade.trade]) }, [currency, stablecoin, trade])
const lastPrice = useRef(price) const lastPrice = useRef(price)
if (!price || !lastPrice.current || !price.equalTo(lastPrice.current)) { if (!price || !lastPrice.current || !price.equalTo(lastPrice.current)) {
......
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { Trade } from '@uniswap/router-sdk' import { Trade } from '@uniswap/router-sdk'
import { Currency, CurrencyAmount, Token, TradeType } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Percent, Token, TradeType } from '@uniswap/sdk-core'
import { Trade as V2Trade } from '@uniswap/v2-sdk' import { Trade as V2Trade } from '@uniswap/v2-sdk'
import { Trade as V3Trade } from '@uniswap/v3-sdk' import { Trade as V3Trade } from '@uniswap/v3-sdk'
import { useWeb3React } from '@web3-react/core' import { useWeb3React } from '@web3-react/core'
...@@ -16,7 +16,7 @@ import { ...@@ -16,7 +16,7 @@ import {
} from 'components/AmplitudeAnalytics/utils' } from 'components/AmplitudeAnalytics/utils'
import { sendEvent } from 'components/analytics' import { sendEvent } from 'components/analytics'
import { NetworkAlert } from 'components/NetworkAlert/NetworkAlert' import { NetworkAlert } from 'components/NetworkAlert/NetworkAlert'
import { getPriceImpactPercent } from 'components/swap/AdvancedSwapDetails' import PriceImpactWarning from 'components/swap/PriceImpactWarning'
import SwapDetailsDropdown from 'components/swap/SwapDetailsDropdown' import SwapDetailsDropdown from 'components/swap/SwapDetailsDropdown'
import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter' import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter'
import { MouseoverTooltip } from 'components/Tooltip' import { MouseoverTooltip } from 'components/Tooltip'
...@@ -68,8 +68,7 @@ import { useExpertModeManager } from '../../state/user/hooks' ...@@ -68,8 +68,7 @@ import { useExpertModeManager } from '../../state/user/hooks'
import { LinkStyledButton, ThemedText } from '../../theme' import { LinkStyledButton, ThemedText } from '../../theme'
import { computeFiatValuePriceImpact } from '../../utils/computeFiatValuePriceImpact' import { computeFiatValuePriceImpact } from '../../utils/computeFiatValuePriceImpact'
import { maxAmountSpend } from '../../utils/maxAmountSpend' import { maxAmountSpend } from '../../utils/maxAmountSpend'
import { computeRealizedLPFeePercent } from '../../utils/prices' import { computeRealizedPriceImpact, warningSeverity } from '../../utils/prices'
import { warningSeverity } from '../../utils/prices'
import { supportedChainId } from '../../utils/supportedChainId' import { supportedChainId } from '../../utils/supportedChainId'
import AppBody from '../AppBody' import AppBody from '../AppBody'
...@@ -86,19 +85,27 @@ export function getIsValidSwapQuote( ...@@ -86,19 +85,27 @@ export function getIsValidSwapQuote(
return !!swapInputError && !!trade && (tradeState === TradeState.VALID || tradeState === TradeState.SYNCING) return !!swapInputError && !!trade && (tradeState === TradeState.VALID || tradeState === TradeState.SYNCING)
} }
function largerPercentValue(a?: Percent, b?: Percent) {
if (a && b) {
return a.greaterThan(b) ? a : b
} else if (a) {
return a
} else if (b) {
return b
}
return undefined
}
const formatAnalyticsEventProperties = ( const formatAnalyticsEventProperties = (
trade: InterfaceTrade<Currency, Currency, TradeType>, trade: InterfaceTrade<Currency, Currency, TradeType>,
fetchingSwapQuoteStartTime: Date | undefined fetchingSwapQuoteStartTime: Date | undefined
) => { ) => {
const lpFeePercent = trade ? computeRealizedLPFeePercent(trade) : undefined
return { return {
token_in_symbol: trade.inputAmount.currency.symbol, token_in_symbol: trade.inputAmount.currency.symbol,
token_out_symbol: trade.outputAmount.currency.symbol, token_out_symbol: trade.outputAmount.currency.symbol,
token_in_address: getTokenAddress(trade.inputAmount.currency), token_in_address: getTokenAddress(trade.inputAmount.currency),
token_out_address: getTokenAddress(trade.outputAmount.currency), token_out_address: getTokenAddress(trade.outputAmount.currency),
price_impact_basis_points: lpFeePercent price_impact_basis_points: trade ? formatPercentInBasisPointsNumber(computeRealizedPriceImpact(trade)) : undefined,
? formatPercentInBasisPointsNumber(getPriceImpactPercent(lpFeePercent, trade))
: undefined,
estimated_network_fee_usd: trade.gasUseEstimateUSD ? formatToDecimal(trade.gasUseEstimateUSD, 2) : undefined, estimated_network_fee_usd: trade.gasUseEstimateUSD ? formatToDecimal(trade.gasUseEstimateUSD, 2) : undefined,
chain_id: chain_id:
trade.inputAmount.currency.chainId === trade.outputAmount.currency.chainId trade.inputAmount.currency.chainId === trade.outputAmount.currency.chainId
...@@ -205,7 +212,7 @@ export default function Swap() { ...@@ -205,7 +212,7 @@ export default function Swap() {
const outputValue = showWrap ? parsedAmount : trade?.outputAmount const outputValue = showWrap ? parsedAmount : trade?.outputAmount
const fiatValueInput = useStablecoinValue(inputValue) const fiatValueInput = useStablecoinValue(inputValue)
const fiatValueOutput = useStablecoinValue(outputValue) const fiatValueOutput = useStablecoinValue(outputValue)
const priceImpact = useMemo( const stablecoinPriceImpact = useMemo(
() => (routeIsSyncing ? undefined : computeFiatValuePriceImpact(fiatValueInput, fiatValueOutput)), () => (routeIsSyncing ? undefined : computeFiatValuePriceImpact(fiatValueInput, fiatValueOutput)),
[fiatValueInput, fiatValueOutput, routeIsSyncing] [fiatValueInput, fiatValueOutput, routeIsSyncing]
) )
...@@ -334,7 +341,7 @@ export default function Swap() { ...@@ -334,7 +341,7 @@ export default function Swap() {
if (!swapCallback) { if (!swapCallback) {
return return
} }
if (priceImpact && !confirmPriceImpactWithoutFee(priceImpact)) { if (stablecoinPriceImpact && !confirmPriceImpactWithoutFee(stablecoinPriceImpact)) {
return return
} }
setSwapState({ attemptingTxn: true, tradeToConfirm, showConfirm, swapErrorMessage: undefined, txHash: undefined }) setSwapState({ attemptingTxn: true, tradeToConfirm, showConfirm, swapErrorMessage: undefined, txHash: undefined })
...@@ -373,7 +380,7 @@ export default function Swap() { ...@@ -373,7 +380,7 @@ export default function Swap() {
}) })
}, [ }, [
swapCallback, swapCallback,
priceImpact, stablecoinPriceImpact,
tradeToConfirm, tradeToConfirm,
showConfirm, showConfirm,
recipient, recipient,
...@@ -389,16 +396,11 @@ export default function Swap() { ...@@ -389,16 +396,11 @@ export default function Swap() {
const [swapQuoteReceivedDate, setSwapQuoteReceivedDate] = useState<Date | undefined>() const [swapQuoteReceivedDate, setSwapQuoteReceivedDate] = useState<Date | undefined>()
// warnings on the greater of fiat value price impact and execution price impact // warnings on the greater of fiat value price impact and execution price impact
const priceImpactSeverity = useMemo(() => { const { priceImpactSeverity, largerPriceImpact } = useMemo(() => {
const executionPriceImpact = trade?.priceImpact const marketPriceImpact = trade?.priceImpact ? computeRealizedPriceImpact(trade) : undefined
return warningSeverity( const largerPriceImpact = largerPercentValue(marketPriceImpact, stablecoinPriceImpact)
executionPriceImpact && priceImpact return { priceImpactSeverity: warningSeverity(largerPriceImpact), largerPriceImpact }
? executionPriceImpact.greaterThan(priceImpact) }, [stablecoinPriceImpact, trade])
? executionPriceImpact
: priceImpact
: executionPriceImpact ?? priceImpact
)
}, [priceImpact, trade])
const isArgentWallet = useIsArgentWallet() const isArgentWallet = useIsArgentWallet()
...@@ -448,6 +450,7 @@ export default function Swap() { ...@@ -448,6 +450,7 @@ export default function Swap() {
const swapIsUnsupported = useIsSwapUnsupported(currencies[Field.INPUT], currencies[Field.OUTPUT]) const swapIsUnsupported = useIsSwapUnsupported(currencies[Field.INPUT], currencies[Field.OUTPUT])
const priceImpactTooHigh = priceImpactSeverity > 3 && !isExpertMode const priceImpactTooHigh = priceImpactSeverity > 3 && !isExpertMode
const showPriceImpactWarning = largerPriceImpact && priceImpactSeverity > 3
// Handle time based logging events and event properties. // Handle time based logging events and event properties.
useEffect(() => { useEffect(() => {
...@@ -562,7 +565,7 @@ export default function Swap() { ...@@ -562,7 +565,7 @@ export default function Swap() {
showMaxButton={false} showMaxButton={false}
hideBalance={false} hideBalance={false}
fiatValue={fiatValueOutput ?? undefined} fiatValue={fiatValueOutput ?? undefined}
priceImpact={priceImpact} priceImpact={stablecoinPriceImpact}
currency={currencies[Field.OUTPUT] ?? null} currency={currencies[Field.OUTPUT] ?? null}
onCurrencySelect={handleOutputSelect} onCurrencySelect={handleOutputSelect}
otherCurrency={currencies[Field.INPUT]} otherCurrency={currencies[Field.INPUT]}
...@@ -596,6 +599,7 @@ export default function Swap() { ...@@ -596,6 +599,7 @@ export default function Swap() {
allowedSlippage={allowedSlippage} allowedSlippage={allowedSlippage}
/> />
)} )}
{showPriceImpactWarning && <PriceImpactWarning priceImpact={largerPriceImpact} />}
<div> <div>
{swapIsUnsupported ? ( {swapIsUnsupported ? (
<ButtonPrimary disabled={true}> <ButtonPrimary disabled={true}>
......
...@@ -13,6 +13,11 @@ import { useClientSideRouter } from 'state/user/hooks' ...@@ -13,6 +13,11 @@ import { useClientSideRouter } from 'state/user/hooks'
import { GetQuoteResult, InterfaceTrade, TradeState } from './types' import { GetQuoteResult, InterfaceTrade, TradeState } from './types'
import { computeRoutes, transformRoutesToTrade } from './utils' import { computeRoutes, transformRoutesToTrade } from './utils'
export enum RouterPreference {
CLIENT = 'client',
API = 'api',
}
/** /**
* Returns the best trade by invoking the routing api or the smart order router on the client * Returns the best trade by invoking the routing api or the smart order router on the client
* @param tradeType whether the swap is an exact in/out * @param tradeType whether the swap is an exact in/out
...@@ -22,7 +27,8 @@ import { computeRoutes, transformRoutesToTrade } from './utils' ...@@ -22,7 +27,8 @@ import { computeRoutes, transformRoutesToTrade } from './utils'
export function useRoutingAPITrade<TTradeType extends TradeType>( export function useRoutingAPITrade<TTradeType extends TradeType>(
tradeType: TTradeType, tradeType: TTradeType,
amountSpecified?: CurrencyAmount<Currency>, amountSpecified?: CurrencyAmount<Currency>,
otherCurrency?: Currency otherCurrency?: Currency,
routerPreference?: RouterPreference
): { ): {
state: TradeState state: TradeState
trade: InterfaceTrade<Currency, Currency, TTradeType> | undefined trade: InterfaceTrade<Currency, Currency, TTradeType> | undefined
...@@ -35,7 +41,10 @@ export function useRoutingAPITrade<TTradeType extends TradeType>( ...@@ -35,7 +41,10 @@ export function useRoutingAPITrade<TTradeType extends TradeType>(
[amountSpecified, otherCurrency, tradeType] [amountSpecified, otherCurrency, tradeType]
) )
const [clientSideRouter] = useClientSideRouter() const [clientSideRouterStoredPreference] = useClientSideRouter()
const clientSideRouter = routerPreference
? routerPreference === RouterPreference.CLIENT
: clientSideRouterStoredPreference
const queryArgs = useRoutingAPIArguments({ const queryArgs = useRoutingAPIArguments({
tokenIn: currencyIn, tokenIn: currencyIn,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment