fix: impact rendering (#3553)

* fix: price impact rendering

* fix: webkit-compat gradient
This commit is contained in:
Zach Pomerantz 2022-03-21 07:26:35 -07:00 committed by GitHub
parent 377026bca8
commit f508788026
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 66 additions and 56 deletions

@ -18,7 +18,7 @@ const ExpandoColumn = styled(Column)<{ height: number; open: boolean }>`
transition: height 0.25s, padding 0.25s;
:after {
background: linear-gradient(#ffffff00, ${({ theme }) => theme.dialog});
background: linear-gradient(transparent, ${({ theme }) => theme.dialog});
bottom: 0;
content: '';
height: 0.75em;

@ -83,7 +83,7 @@ export default function Output({ disabled, focused, children }: PropsWithChildre
<Row>
<USDC gap={0.5} isLoading={isRouteLoading}>
{outputUSDC ? `$${formatCurrencyAmount(outputUSDC, 6, 'en', 2)}` : '-'}{' '}
{impact.display && <ThemedText.Body2 color={impact.warning}>({impact.display})</ThemedText.Body2>}
{impact && <ThemedText.Body2 color={impact.warning}>({impact.toString()})</ThemedText.Body2>}
</USDC>
{balance && (
<Balance focused={focused}>

@ -1,10 +1,12 @@
import { t } 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 { useAtomValue } from 'jotai/utils'
import Column from 'lib/components/Column'
import Row from 'lib/components/Row'
import { Slippage } from 'lib/hooks/useSlippage'
import { PriceImpact } from 'lib/hooks/useUSDCPriceImpact'
import { feeOptionsAtom } from 'lib/state/swap'
import styled, { Color, ThemedText } from 'lib/theme'
import { useMemo } from 'react'
@ -36,11 +38,11 @@ function Detail({ label, value, color }: DetailProps) {
interface DetailsProps {
trade: Trade<Currency, Currency, TradeType>
slippage: { auto: boolean; allowed: Percent; warning?: Color }
priceImpact: { priceImpact?: string; warning?: Color }
slippage: Slippage
impact?: PriceImpact
}
export default function Details({ trade, slippage, priceImpact }: DetailsProps) {
export default function Details({ trade, slippage, impact }: DetailsProps) {
const { inputAmount, outputAmount } = trade
const inputCurrency = inputAmount.currency
const outputCurrency = outputAmount.currency
@ -61,8 +63,8 @@ export default function Details({ trade, slippage, priceImpact }: DetailsProps)
}
}
if (priceImpact.priceImpact) {
rows.push([t`Price impact`, priceImpact.priceImpact, priceImpact.warning])
if (impact) {
rows.push([t`Price impact`, impact.toString(), impact.warning])
}
if (lpFeeAmount) {
@ -85,15 +87,15 @@ export default function Details({ trade, slippage, priceImpact }: DetailsProps)
return rows
}, [
feeOptions,
priceImpact,
lpFeeAmount,
trade,
slippage,
outputAmount,
i18n.locale,
integrator,
outputCurrency,
impact,
inputCurrency,
integrator,
lpFeeAmount,
outputAmount,
outputCurrency,
slippage,
trade,
])
return (

@ -42,16 +42,16 @@ interface SummaryProps {
output: CurrencyAmount<Currency>
inputUSDC?: CurrencyAmount<Currency>
outputUSDC?: CurrencyAmount<Currency>
priceImpact?: PriceImpact
impact?: PriceImpact
}
export default function Summary({ input, output, inputUSDC, outputUSDC, priceImpact }: SummaryProps) {
export default function Summary({ input, output, inputUSDC, outputUSDC, impact }: SummaryProps) {
return (
<Row gap={priceImpact ? 1 : 0.25}>
<Row gap={impact ? 1 : 0.25}>
<TokenValue input={input} usdc={inputUSDC} />
<ArrowRight />
<TokenValue input={output} usdc={outputUSDC}>
{priceImpact && <ThemedText.Caption color={priceImpact.warning}>({priceImpact.display})</ThemedText.Caption>}
{impact && <ThemedText.Caption color={impact.warning}>({impact.toString()})</ThemedText.Caption>}
</TokenValue>
</Row>
)

@ -10,7 +10,7 @@ import Row from 'lib/components/Row'
import { Slippage } from 'lib/hooks/useSlippage'
import { PriceImpact } from 'lib/hooks/useUSDCPriceImpact'
import { AlertTriangle, BarChart, Info } from 'lib/icons'
import styled, { Color, ThemedText } from 'lib/theme'
import styled, { ThemedText } from 'lib/theme'
import { useCallback, useMemo, useState } from 'react'
import { formatCurrencyAmount } from 'utils/formatCurrencyAmount'
import { tradeMeaningfullyDiffers } from 'utils/tradeMeaningFullyDiffer'
@ -41,16 +41,16 @@ const Body = styled(Column)<{ open: boolean }>`
}
`
function Subhead({ priceImpact, slippage }: { priceImpact: { warning?: Color }; slippage: Slippage }) {
function Subhead({ impact, slippage }: { impact?: PriceImpact; slippage: Slippage }) {
return (
<Row gap={0.5}>
{priceImpact.warning || slippage.warning ? (
<AlertTriangle color={priceImpact.warning || slippage.warning} />
{impact?.warning || slippage.warning ? (
<AlertTriangle color={impact?.warning || slippage.warning} />
) : (
<Info color="secondary" />
)}
<ThemedText.Subhead2 color={priceImpact.warning || slippage.warning || 'secondary'}>
{priceImpact.warning ? (
<ThemedText.Subhead2 color={impact?.warning || slippage.warning || 'secondary'}>
{impact?.warning ? (
<Trans>High price impact</Trans>
) : slippage.warning ? (
<Trans>High slippage</Trans>
@ -132,7 +132,7 @@ interface SummaryDialogProps {
slippage: Slippage
inputUSDC?: CurrencyAmount<Currency>
outputUSDC?: CurrencyAmount<Currency>
impact: PriceImpact
impact?: PriceImpact
onConfirm: () => void
}
@ -152,23 +152,23 @@ export function SummaryDialog({ trade, slippage, inputUSDC, outputUSDC, impact,
output={outputAmount}
inputUSDC={inputUSDC}
outputUSDC={outputUSDC}
priceImpact={impact}
impact={impact}
/>
<Price trade={trade} />
</Heading>
<Column gap={open ? 0 : 0.75} style={{ transition: 'gap 0.25s' }}>
<Expando
title={<Subhead priceImpact={impact} slippage={slippage} />}
title={<Subhead impact={impact} slippage={slippage} />}
open={open}
onExpand={onExpand}
height={7}
>
<Details trade={trade} slippage={slippage} priceImpact={impact} />
<Details trade={trade} slippage={slippage} impact={impact} />
</Expando>
<Footing>
<Estimate trade={trade} slippage={slippage} />
</Footing>
<ConfirmButton trade={trade} highPriceImpact={impact.warning === 'error'} onConfirm={onConfirm} />
<ConfirmButton trade={trade} highPriceImpact={impact?.warning === 'error'} onConfirm={onConfirm} />
</Column>
</Body>
</>

@ -84,16 +84,17 @@ export function Trade({
}: {
trade: InterfaceTrade<Currency, Currency, TradeType>
outputUSDC?: CurrencyAmount<Currency>
impact: PriceImpact
impact?: PriceImpact
}) {
return (
<>
<Tooltip placement="bottom" icon={impact.warning ? AlertTriangle : Info}>
<Tooltip placement="bottom" icon={impact?.warning ? AlertTriangle : Info}>
<Column gap={0.75}>
{impact.warning && (
{impact?.warning && (
<>
<ThemedText.Caption>
The output amount is estimated at {impact.display} less than the input amount due to high price impact
The output amount is estimated at {impact.toString()} less than the input amount due to high price
impact
</ThemedText.Caption>
<Rule />
</>

@ -17,6 +17,7 @@ function TokenImg({ token, ...rest }: TokenImgProps) {
// Use the wrapped token info so that it includes the logoURI.
const tokenInfo = useToken(token.isToken ? token.wrapped.address : undefined) ?? token
// TODO(zzmp): TokenImg takes a frame to switch.
const srcs = useCurrencyLogoURIs(tokenInfo)
const [src, setSrc] = useState<string | undefined>()
useEffect(() => {

@ -28,7 +28,7 @@ interface SwapInfo {
state: TradeState
}
slippage: Slippage
impact: PriceImpact
impact?: PriceImpact
}
// from the current swap inputs, compute the best trade and return it.
@ -65,11 +65,7 @@ function useComputeSwapInfo(): SwapInfo {
// Compute slippage and impact off of the trade so that it refreshes with the trade.
// (Using amountIn/amountOut would show (incorrect) intermediate values.)
const slippage = useSlippage(trade.trade)
const {
inputUSDC: usdcIn,
outputUSDC: usdcOut,
priceImpact: impact,
} = useUSDCPriceImpact(trade.trade?.inputAmount, trade.trade?.outputAmount)
const { inputUSDC, outputUSDC, impact } = useUSDCPriceImpact(trade.trade?.inputAmount, trade.trade?.outputAmount)
return useMemo(
() => ({
@ -77,19 +73,31 @@ function useComputeSwapInfo(): SwapInfo {
currency: currencyIn,
amount: amountIn,
balance: balanceIn,
usdc: usdcIn,
usdc: inputUSDC,
},
[Field.OUTPUT]: {
currency: currencyOut,
amount: amountOut,
balance: balanceOut,
usdc: usdcOut,
usdc: outputUSDC,
},
trade,
slippage,
impact,
}),
[amountIn, amountOut, balanceIn, balanceOut, currencyIn, currencyOut, impact, slippage, trade, usdcIn, usdcOut]
[
amountIn,
amountOut,
balanceIn,
balanceOut,
currencyIn,
currencyOut,
impact,
inputUSDC,
outputUSDC,
slippage,
trade,
]
)
}
@ -98,7 +106,6 @@ const swapInfoAtom = atom<SwapInfo>({
[Field.OUTPUT]: {},
trade: { state: TradeState.INVALID },
slippage: { auto: true, allowed: new Percent(0) },
impact: {},
})
export function SwapInfoUpdater() {

@ -5,8 +5,9 @@ import { computeFiatValuePriceImpact } from 'utils/computeFiatValuePriceImpact'
import { getPriceImpactWarning } from 'utils/prices'
export interface PriceImpact {
display?: string
percent: Percent
warning?: 'warning' | 'error'
toString(): string
}
/**
@ -19,22 +20,20 @@ export default function useUSDCPriceImpact(
): {
inputUSDC?: CurrencyAmount<Token>
outputUSDC?: CurrencyAmount<Token>
priceImpact: PriceImpact
impact?: PriceImpact
} {
const inputUSDC = useUSDCValue(inputAmount) ?? undefined
const outputUSDC = useUSDCValue(outputAmount) ?? undefined
return useMemo(() => {
const priceImpact = computeFiatValuePriceImpact(inputUSDC, outputUSDC)
const warning = getPriceImpactWarning(priceImpact)
return {
inputUSDC,
outputUSDC,
priceImpact: {
priceImpact,
display: priceImpact && toHumanReadablePriceImpact(priceImpact),
warning,
},
}
const impact = priceImpact
? {
percent: priceImpact,
warning: getPriceImpactWarning(priceImpact),
toString: () => toHumanReadablePriceImpact(priceImpact),
}
: undefined
return { inputUSDC, outputUSDC, impact }
}, [inputUSDC, outputUSDC])
}