Commit 2c74c5f2 authored by Zach Pomerantz's avatar Zach Pomerantz Committed by GitHub

chore: include usdc in swap info (#3539)

* chore: refactor useComputeSwapInfo to include usdc

* chore: use passed usdc if able

* fix: fixture
parent cbc2ff66
import { useLingui } from '@lingui/react'
import { Currency, CurrencyAmount } from '@uniswap/sdk-core'
import { useUSDCValue } from 'hooks/useUSDCPrice'
import { loadingTransitionCss } from 'lib/css/loading'
import {
useIsSwapFieldIndependent,
......@@ -70,18 +69,16 @@ export function useFormattedFieldAmount({ disabled, currencyAmount, fieldAmount
export default function Input({ disabled, focused }: InputProps) {
const { i18n } = useLingui()
const {
currencyBalances: { [Field.INPUT]: balance },
[Field.INPUT]: { balance, amount: tradeCurrencyAmount, usdc },
trade: { state: tradeState },
tradeCurrencyAmounts: { [Field.INPUT]: swapInputCurrencyAmount },
} = useSwapInfo()
const inputUSDC = useUSDCValue(swapInputCurrencyAmount)
const [swapInputAmount, updateSwapInputAmount] = useSwapAmount(Field.INPUT)
const [swapInputCurrency, updateSwapInputCurrency] = useSwapCurrency(Field.INPUT)
const [inputAmount, updateInputAmount] = useSwapAmount(Field.INPUT)
const [inputCurrency, updateInputCurrency] = useSwapCurrency(Field.INPUT)
const inputCurrencyAmount = useSwapCurrencyAmount(Field.INPUT)
// extract eagerly in case of reversal
usePrefetchCurrencyColor(swapInputCurrency)
usePrefetchCurrencyColor(inputCurrency)
const isRouteLoading = tradeState === TradeState.SYNCING || tradeState === TradeState.LOADING
const isDependentField = !useIsSwapFieldIndependent(Field.INPUT)
......@@ -99,32 +96,30 @@ export default function Input({ disabled, focused }: InputProps) {
const balanceColor = useMemo(() => {
const insufficientBalance =
balance &&
(inputCurrencyAmount ? inputCurrencyAmount.greaterThan(balance) : swapInputCurrencyAmount?.greaterThan(balance))
(inputCurrencyAmount ? inputCurrencyAmount.greaterThan(balance) : tradeCurrencyAmount?.greaterThan(balance))
return insufficientBalance ? 'error' : undefined
}, [balance, inputCurrencyAmount, swapInputCurrencyAmount])
}, [balance, inputCurrencyAmount, tradeCurrencyAmount])
const amount = useFormattedFieldAmount({
disabled,
currencyAmount: swapInputCurrencyAmount,
fieldAmount: swapInputAmount,
currencyAmount: tradeCurrencyAmount,
fieldAmount: inputAmount,
})
return (
<InputColumn gap={0.5} approved={mockApproved}>
<TokenInput
currency={swapInputCurrency}
currency={inputCurrency}
amount={amount}
max={max}
disabled={disabled}
onChangeInput={updateSwapInputAmount}
onChangeCurrency={updateSwapInputCurrency}
onChangeInput={updateInputAmount}
onChangeCurrency={updateInputCurrency}
loading={isLoading}
>
<ThemedText.Body2 color="secondary" userSelect>
<Row>
<USDC isLoading={isRouteLoading}>
{inputUSDC ? `$${formatCurrencyAmount(inputUSDC, 6, 'en', 2)}` : '-'}
</USDC>
<USDC isLoading={isRouteLoading}>{usdc ? `$${formatCurrencyAmount(usdc, 6, 'en', 2)}` : '-'}</USDC>
{balance && (
<Balance color={balanceColor} focused={focused}>
Balance: <span>{formatCurrencyAmount(balance, 4, i18n.locale)}</span>
......
......@@ -5,7 +5,6 @@ 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 from 'lib/hooks/useUSDCPriceImpact'
import { Field } from 'lib/state/swap'
import styled, { DynamicThemeProvider, ThemedText } from 'lib/theme'
import { PropsWithChildren } from 'react'
......@@ -39,9 +38,9 @@ export default function Output({ disabled, focused, children }: PropsWithChildre
const { i18n } = useLingui()
const {
currencyBalances: { [Field.OUTPUT]: balance },
[Field.OUTPUT]: { balance, amount: outputCurrencyAmount, usdc: outputUSDC },
trade: { state: tradeState },
tradeCurrencyAmounts: { [Field.INPUT]: inputCurrencyAmount, [Field.OUTPUT]: outputCurrencyAmount },
impact,
} = useSwapInfo()
const [swapOutputAmount, updateSwapOutputAmount] = useSwapAmount(Field.OUTPUT)
......@@ -58,12 +57,6 @@ 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,
warning: priceImpactWarning,
} = useUSDCPriceImpact(inputCurrencyAmount, outputCurrencyAmount)
const amount = useFormattedFieldAmount({
disabled,
currencyAmount: outputCurrencyAmount,
......@@ -90,7 +83,7 @@ export default function Output({ disabled, focused, children }: PropsWithChildre
<Row>
<USDC gap={0.5} isLoading={isRouteLoading}>
{outputUSDC ? `$${formatCurrencyAmount(outputUSDC, 6, 'en', 2)}` : '-'}{' '}
{priceImpact && <ThemedText.Body2 color={priceImpactWarning}>({priceImpact})</ThemedText.Body2>}
{impact.display && <ThemedText.Body2 color={impact.warning}>({impact.display})</ThemedText.Body2>}
</USDC>
{balance && (
<Balance focused={focused}>
......
import { useLingui } from '@lingui/react'
import { Trade } from '@uniswap/router-sdk'
import { Currency, CurrencyAmount, Token, TradeType } from '@uniswap/sdk-core'
import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
import Row from 'lib/components/Row'
import { ThemedText } from 'lib/theme'
import formatLocaleNumber from 'lib/utils/formatLocaleNumber'
......@@ -11,7 +11,7 @@ import { TextButton } from '../Button'
interface PriceProps {
trade: Trade<Currency, Currency, TradeType>
outputUSDC?: CurrencyAmount<Token>
outputUSDC?: CurrencyAmount<Currency>
}
/** Displays the price of a trade. If outputUSDC is included, also displays the unit price. */
......
......@@ -22,8 +22,11 @@ const UNI = (function () {
function Fixture() {
const setState = useUpdateAtom(swapAtom)
const {
slippage,
[Field.INPUT]: { usdc: inputUSDC },
[Field.OUTPUT]: { usdc: outputUSDC },
trade: { trade },
slippage,
impact,
} = useSwapInfo()
useEffect(() => {
......@@ -37,7 +40,14 @@ function Fixture() {
return trade ? (
<Modal color="dialog">
<SummaryDialog onConfirm={() => void 0} trade={trade} slippage={slippage} />
<SummaryDialog
onConfirm={() => void 0}
trade={trade}
slippage={slippage}
inputUSDC={inputUSDC}
outputUSDC={outputUSDC}
impact={impact}
/>
</Modal>
) : null
}
......
......@@ -37,10 +37,10 @@ function Detail({ label, value, color }: DetailProps) {
interface DetailsProps {
trade: Trade<Currency, Currency, TradeType>
slippage: { auto: boolean; allowed: Percent; warning?: Color }
usdcPriceImpact: { priceImpact?: string; warning?: Color }
priceImpact: { priceImpact?: string; warning?: Color }
}
export default function Details({ trade, slippage, usdcPriceImpact }: DetailsProps) {
export default function Details({ trade, slippage, priceImpact }: DetailsProps) {
const { inputAmount, outputAmount } = trade
const inputCurrency = inputAmount.currency
const outputCurrency = outputAmount.currency
......@@ -61,8 +61,8 @@ export default function Details({ trade, slippage, usdcPriceImpact }: DetailsPro
}
}
if (usdcPriceImpact.priceImpact) {
rows.push([t`Price impact`, usdcPriceImpact.priceImpact, usdcPriceImpact.warning])
if (priceImpact.priceImpact) {
rows.push([t`Price impact`, priceImpact.priceImpact, priceImpact.warning])
}
if (lpFeeAmount) {
......@@ -85,7 +85,7 @@ export default function Details({ trade, slippage, usdcPriceImpact }: DetailsPro
return rows
}, [
feeOptions,
usdcPriceImpact,
priceImpact,
lpFeeAmount,
trade,
slippage,
......
import { useLingui } from '@lingui/react'
import { Currency, CurrencyAmount, Token } from '@uniswap/sdk-core'
import useUSDCPriceImpact from 'lib/hooks/useUSDCPriceImpact'
import { Currency, CurrencyAmount } from '@uniswap/sdk-core'
import { PriceImpact } from 'lib/hooks/useUSDCPriceImpact'
import { ArrowRight } from 'lib/icons'
import { ThemedText } from 'lib/theme'
import { PropsWithChildren } from 'react'
......@@ -12,7 +12,7 @@ import TokenImg from '../../TokenImg'
interface TokenValueProps {
input: CurrencyAmount<Currency>
usdc?: CurrencyAmount<Token>
usdc?: CurrencyAmount<Currency>
}
function TokenValue({ input, usdc, children }: PropsWithChildren<TokenValueProps>) {
......@@ -40,18 +40,18 @@ function TokenValue({ input, usdc, children }: PropsWithChildren<TokenValueProps
interface SummaryProps {
input: CurrencyAmount<Currency>
output: CurrencyAmount<Currency>
usdcPriceImpact?: ReturnType<typeof useUSDCPriceImpact>
inputUSDC?: CurrencyAmount<Currency>
outputUSDC?: CurrencyAmount<Currency>
priceImpact?: PriceImpact
}
export default function Summary({ input, output, usdcPriceImpact }: SummaryProps) {
const { inputUSDC, outputUSDC, priceImpact, warning: priceImpactWarning } = usdcPriceImpact || {}
export default function Summary({ input, output, inputUSDC, outputUSDC, priceImpact }: SummaryProps) {
return (
<Row gap={usdcPriceImpact ? 1 : 0.25}>
<Row gap={priceImpact ? 1 : 0.25}>
<TokenValue input={input} usdc={inputUSDC} />
<ArrowRight />
<TokenValue input={output} usdc={outputUSDC}>
{priceImpact && <ThemedText.Caption color={priceImpactWarning}>({priceImpact})</ThemedText.Caption>}
{priceImpact && <ThemedText.Caption color={priceImpact.warning}>({priceImpact.display})</ThemedText.Caption>}
</TokenValue>
</Row>
)
......
import { Trans } from '@lingui/macro'
import { useLingui } from '@lingui/react'
import { Trade } from '@uniswap/router-sdk'
import { Currency, TradeType } from '@uniswap/sdk-core'
import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
import ActionButton, { Action } from 'lib/components/ActionButton'
import Column from 'lib/components/Column'
import { Header } from 'lib/components/Dialog'
import Expando from 'lib/components/Expando'
import Row from 'lib/components/Row'
import { Slippage } from 'lib/hooks/useSlippage'
import useUSDCPriceImpact from 'lib/hooks/useUSDCPriceImpact'
import { PriceImpact } from 'lib/hooks/useUSDCPriceImpact'
import { AlertTriangle, BarChart, Info } from 'lib/icons'
import styled, { Color, ThemedText } from 'lib/theme'
import { useCallback, useMemo, useState } from 'react'
......@@ -130,12 +130,14 @@ function ConfirmButton({
interface SummaryDialogProps {
trade: Trade<Currency, Currency, TradeType>
slippage: Slippage
inputUSDC?: CurrencyAmount<Currency>
outputUSDC?: CurrencyAmount<Currency>
impact: PriceImpact
onConfirm: () => void
}
export function SummaryDialog({ trade, slippage, onConfirm }: SummaryDialogProps) {
export function SummaryDialog({ trade, slippage, inputUSDC, outputUSDC, impact, onConfirm }: SummaryDialogProps) {
const { inputAmount, outputAmount } = trade
const usdcPriceImpact = useUSDCPriceImpact(inputAmount, outputAmount)
const [open, setOpen] = useState(false)
const onExpand = useCallback(() => setOpen((open) => !open), [])
......@@ -145,22 +147,28 @@ export function SummaryDialog({ trade, slippage, onConfirm }: SummaryDialogProps
<Header title={<Trans>Swap summary</Trans>} ruled />
<Body flex align="stretch" padded gap={0.75} open={open}>
<Heading gap={0.75} flex justify="center">
<Summary input={inputAmount} output={outputAmount} usdcPriceImpact={usdcPriceImpact} />
<Summary
input={inputAmount}
output={outputAmount}
inputUSDC={inputUSDC}
outputUSDC={outputUSDC}
priceImpact={impact}
/>
<Price trade={trade} />
</Heading>
<Column gap={open ? 0 : 0.75} style={{ transition: 'gap 0.25s' }}>
<Expando
title={<Subhead priceImpact={usdcPriceImpact} slippage={slippage} />}
title={<Subhead priceImpact={impact} slippage={slippage} />}
open={open}
onExpand={onExpand}
height={7.25}
>
<Details trade={trade} slippage={slippage} usdcPriceImpact={usdcPriceImpact} />
<Details trade={trade} slippage={slippage} priceImpact={impact} />
</Expando>
<Footing>
<Estimate trade={trade} slippage={slippage} />
</Footing>
<ConfirmButton trade={trade} highPriceImpact={usdcPriceImpact.warning === 'error'} onConfirm={onConfirm} />
<ConfirmButton trade={trade} highPriceImpact={impact.warning === 'error'} onConfirm={onConfirm} />
</Column>
</Body>
</>
......
import { Trans } from '@lingui/macro'
import { Token } from '@uniswap/sdk-core'
import { useUpdateAtom } from 'jotai/utils'
import { useAtomValue, useUpdateAtom } from 'jotai/utils'
import { WrapErrorText } from 'lib/components/Swap/WrapErrorText'
import { useSwapCurrencyAmount, useSwapInfo, useSwapTradeType } from 'lib/hooks/swap'
import {
......@@ -15,7 +15,7 @@ import { useAddTransaction, usePendingApproval } from 'lib/hooks/transactions'
import useActiveWeb3React from 'lib/hooks/useActiveWeb3React'
import useTransactionDeadline from 'lib/hooks/useTransactionDeadline'
import { Spinner } from 'lib/icons'
import { displayTxHashAtom, Field } from 'lib/state/swap'
import { displayTxHashAtom, feeOptionsAtom, Field } from 'lib/state/swap'
import { TransactionType } from 'lib/state/transactions'
import { useTheme } from 'lib/theme'
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
......@@ -41,13 +41,18 @@ export default memo(function SwapButton({ disabled }: SwapButtonProps) {
const { tokenColorExtraction } = useTheme()
const {
slippage,
currencies: { [Field.INPUT]: inputCurrency },
currencyBalances: { [Field.INPUT]: inputCurrencyBalance },
feeOptions,
[Field.INPUT]: {
currency: inputCurrency,
amount: inputTradeCurrencyAmount,
balance: inputCurrencyBalance,
usdc: inputUSDC,
},
[Field.OUTPUT]: { amount: outputTradeCurrencyAmount, usdc: outputUSDC },
trade,
tradeCurrencyAmounts: { [Field.INPUT]: inputTradeCurrencyAmount, [Field.OUTPUT]: outputTradeCurrencyAmount },
slippage,
impact,
} = useSwapInfo()
const feeOptions = useAtomValue(feeOptionsAtom)
const tradeType = useSwapTradeType()
......@@ -240,7 +245,14 @@ export default memo(function SwapButton({ disabled }: SwapButtonProps) {
</ActionButton>
{activeTrade && (
<Dialog color="dialog" onClose={handleDialogClose}>
<SummaryDialog trade={activeTrade} slippage={slippage} onConfirm={onConfirm} />
<SummaryDialog
trade={activeTrade}
slippage={slippage}
inputUSDC={inputUSDC}
outputUSDC={outputUSDC}
impact={impact}
onConfirm={onConfirm}
/>
</Dialog>
)}
</>
......
import { Trans } from '@lingui/macro'
import { Currency, TradeType } from '@uniswap/sdk-core'
import { Currency, CurrencyAmount, TradeType } from '@uniswap/sdk-core'
import Column from 'lib/components/Column'
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 from 'lib/hooks/useUSDCPriceImpact'
import { PriceImpact } from 'lib/hooks/useUSDCPriceImpact'
import { AlertTriangle, Icon, Info, InlineSpinner } from 'lib/icons'
import styled, { ThemedText } from 'lib/theme'
import { ReactNode, useCallback } from 'react'
......@@ -77,17 +77,23 @@ export function WrapCurrency({ loading, wrapType }: { loading: boolean; wrapType
return <Caption icon={Info} caption={<WrapText />} />
}
export function Trade({ trade }: { trade: InterfaceTrade<Currency, Currency, TradeType> }) {
const { inputAmount: input, outputAmount: output } = trade
const { outputUSDC, priceImpact, warning: priceImpactWarning } = useUSDCPriceImpact(input, output)
export function Trade({
trade,
outputUSDC,
impact,
}: {
trade: InterfaceTrade<Currency, Currency, TradeType>
outputUSDC?: CurrencyAmount<Currency>
impact: PriceImpact
}) {
return (
<>
<Tooltip placement="bottom" icon={priceImpactWarning ? AlertTriangle : Info}>
<Tooltip placement="bottom" icon={impact.warning ? AlertTriangle : Info}>
<Column gap={0.75}>
{priceImpactWarning && (
{impact.warning && (
<>
<ThemedText.Caption>
The output amount is estimated at {priceImpact} less than the input amount due to high price impact
The output amount is estimated at {impact.display} less than the input amount due to high price impact
</ThemedText.Caption>
<Rule />
</>
......
......@@ -20,9 +20,10 @@ const ToolbarRow = styled(Row)`
export default memo(function Toolbar({ disabled }: { disabled?: boolean }) {
const { chainId } = useActiveWeb3React()
const {
[Field.INPUT]: { currency: inputCurrency, balance },
[Field.OUTPUT]: { currency: outputCurrency, usdc: outputUSDC },
trade: { trade, state },
currencies: { [Field.INPUT]: inputCurrency, [Field.OUTPUT]: outputCurrency },
currencyBalances: { [Field.INPUT]: balance },
impact,
} = useSwapInfo()
const isRouteLoading = state === TradeState.SYNCING || state === TradeState.LOADING
const isAmountPopulated = useIsAmountPopulated()
......@@ -50,7 +51,7 @@ export default memo(function Toolbar({ disabled }: { disabled?: boolean }) {
return <Caption.InsufficientBalance currency={trade.inputAmount.currency} />
}
if (trade.inputAmount && trade.outputAmount) {
return <Caption.Trade trade={trade} />
return <Caption.Trade trade={trade} outputUSDC={outputUSDC} impact={impact} />
}
}
......@@ -59,10 +60,12 @@ export default memo(function Toolbar({ disabled }: { disabled?: boolean }) {
balance,
chainId,
disabled,
impact,
inputCurrency,
isAmountPopulated,
isRouteLoading,
outputCurrency,
outputUSDC,
trade,
wrapLoading,
wrapType,
......
import { Trans } from '@lingui/macro'
import { Currency, CurrencyAmount, Percent, TradeType } from '@uniswap/sdk-core'
import { FeeOptions } from '@uniswap/v3-sdk'
import { atom } from 'jotai'
import { useAtomValue, useUpdateAtom } from 'jotai/utils'
import { useCurrencyBalances } from 'lib/hooks/useCurrencyBalance'
import { feeOptionsAtom, Field, swapAtom } from 'lib/state/swap'
import { Field, swapAtom } from 'lib/state/swap'
import tryParseCurrencyAmount from 'lib/utils/tryParseCurrencyAmount'
import { ReactNode, useEffect, useMemo } from 'react'
import { useEffect, useMemo } from 'react'
import { InterfaceTrade, TradeState } from 'state/routing/types'
import { isAddress } from '../../../utils'
import useActiveWeb3React from '../useActiveWeb3React'
import useSlippage, { Slippage } from '../useSlippage'
import useUSDCPriceImpact, { PriceImpact } from '../useUSDCPriceImpact'
import { useBestTrade } from './useBestTrade'
import useWrapCallback, { WrapType } from './useWrapCallback'
interface SwapField {
currency?: Currency
amount?: CurrencyAmount<Currency>
balance?: CurrencyAmount<Currency>
usdc?: CurrencyAmount<Currency>
}
interface SwapInfo {
currencies: { [field in Field]?: Currency }
currencyBalances: { [field in Field]?: CurrencyAmount<Currency> }
tradeCurrencyAmounts: { [field in Field]?: CurrencyAmount<Currency> }
[Field.INPUT]: SwapField
[Field.OUTPUT]: SwapField
trade: {
trade?: InterfaceTrade<Currency, Currency, TradeType>
state: TradeState
}
slippage: Slippage
feeOptions: FeeOptions | undefined
}
const BAD_RECIPIENT_ADDRESSES: { [address: string]: true } = {
'0x5C69bEe701ef814a2B6a3EDD4B1652CB9cc5aA6f': true, // v2 factory
'0xf164fC0Ec4E93095b804a4795bBe1e041497b92a': true, // v2 router 01
'0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D': true, // v2 router 02
impact: PriceImpact
}
// from the current swap inputs, compute the best trade and return it.
......@@ -38,106 +36,63 @@ function useComputeSwapInfo(): SwapInfo {
const { account } = useActiveWeb3React()
const { type: wrapType } = useWrapCallback()
const isWrapping = wrapType === WrapType.WRAP || wrapType === WrapType.UNWRAP
const {
independentField,
amount,
[Field.INPUT]: inputCurrency,
[Field.OUTPUT]: outputCurrency,
} = useAtomValue(swapAtom)
const { independentField, amount, [Field.INPUT]: currencyIn, [Field.OUTPUT]: currencyOut } = useAtomValue(swapAtom)
const isExactIn = independentField === Field.INPUT
const feeOptions = useAtomValue(feeOptionsAtom)
const parsedAmount = useMemo(
() => tryParseCurrencyAmount(amount, (isExactIn ? inputCurrency : outputCurrency) ?? undefined),
[inputCurrency, isExactIn, outputCurrency, amount]
() => tryParseCurrencyAmount(amount, (isExactIn ? currencyIn : currencyOut) ?? undefined),
[amount, isExactIn, currencyIn, currencyOut]
)
// TODO(ianlapham): this would eventually be replaced with routing api logic.
const trade = useBestTrade(
isExactIn ? TradeType.EXACT_INPUT : TradeType.EXACT_OUTPUT,
parsedAmount,
(isExactIn ? outputCurrency : inputCurrency) ?? undefined
)
const tradeCurrencyAmounts = useMemo(
() => ({
// Use same amount for input and output if user is wrapping.
[Field.INPUT]: isWrapping || isExactIn ? parsedAmount : trade.trade?.inputAmount,
[Field.OUTPUT]: isWrapping || !isExactIn ? parsedAmount : trade.trade?.outputAmount,
}),
[isExactIn, isWrapping, parsedAmount, trade.trade?.inputAmount, trade.trade?.outputAmount]
(isExactIn ? currencyOut : currencyIn) ?? undefined
)
const slippage = useSlippage(trade.trade)
const currencies = useMemo(
() => ({ [Field.INPUT]: inputCurrency, [Field.OUTPUT]: outputCurrency }),
[inputCurrency, outputCurrency]
const amountIn = useMemo(
() => (isWrapping || isExactIn ? parsedAmount : trade.trade?.inputAmount),
[isExactIn, isWrapping, parsedAmount, trade.trade?.inputAmount]
)
const [inputCurrencyBalance, outputCurrencyBalance] = useCurrencyBalances(
account,
useMemo(() => [inputCurrency, outputCurrency], [inputCurrency, outputCurrency])
const amountOut = useMemo(
() => (isWrapping || !isExactIn ? parsedAmount : trade.trade?.outputAmount),
[isExactIn, isWrapping, parsedAmount, trade.trade?.outputAmount]
)
const currencyBalances = useMemo(
() => ({
[Field.INPUT]: inputCurrencyBalance,
[Field.OUTPUT]: outputCurrencyBalance,
}),
[inputCurrencyBalance, outputCurrencyBalance]
const [balanceIn, balanceOut] = useCurrencyBalances(
account,
useMemo(() => [currencyIn, currencyOut], [currencyIn, currencyOut])
)
const inputError = useMemo(() => {
let inputError: ReactNode | undefined
if (!account) {
inputError = <Trans>Connect Wallet</Trans>
}
if (!currencies[Field.INPUT] || !currencies[Field.OUTPUT]) {
inputError = inputError ?? <Trans>Select a token</Trans>
}
if (!parsedAmount) {
inputError = inputError ?? <Trans>Enter an amount</Trans>
}
const formattedAddress = isAddress(account)
if (!account || !formattedAddress) {
inputError = inputError ?? <Trans>Enter a recipient</Trans>
} else {
if (BAD_RECIPIENT_ADDRESSES[formattedAddress]) {
inputError = inputError ?? <Trans>Invalid recipient</Trans>
}
}
// compare input balance to max input based on version
const [balanceIn, amountIn] = [currencyBalances[Field.INPUT], trade.trade?.maximumAmountIn(slippage.allowed)]
if (balanceIn && amountIn && balanceIn.lessThan(amountIn)) {
inputError = <Trans>Insufficient {amountIn.currency.symbol} balance</Trans>
}
return inputError
}, [account, slippage.allowed, currencies, currencyBalances, parsedAmount, trade.trade])
const slippage = useSlippage(trade.trade)
const { inputUSDC: usdcIn, outputUSDC: usdcOut, priceImpact: impact } = useUSDCPriceImpact(amountIn, amountOut)
return useMemo(
() => ({
currencies,
currencyBalances,
inputError,
[Field.INPUT]: {
currency: currencyIn,
amount: amountIn,
balance: balanceIn,
usdc: usdcIn,
},
[Field.OUTPUT]: {
currency: currencyOut,
amount: amountOut,
balance: balanceOut,
usdc: usdcOut,
},
trade,
tradeCurrencyAmounts,
slippage,
feeOptions,
impact,
}),
[currencies, currencyBalances, inputError, trade, tradeCurrencyAmounts, slippage, feeOptions]
[amountIn, amountOut, balanceIn, balanceOut, currencyIn, currencyOut, impact, slippage, trade, usdcIn, usdcOut]
)
}
const swapInfoAtom = atom<SwapInfo>({
currencies: {},
currencyBalances: {},
[Field.INPUT]: {},
[Field.OUTPUT]: {},
trade: { state: TradeState.INVALID },
tradeCurrencyAmounts: {},
slippage: { auto: true, allowed: new Percent(0) },
feeOptions: undefined,
impact: {},
})
export function SwapInfoUpdater() {
......
......@@ -4,6 +4,11 @@ import { useMemo } from 'react'
import { computeFiatValuePriceImpact } from 'utils/computeFiatValuePriceImpact'
import { getPriceImpactWarning } from 'utils/prices'
export interface PriceImpact {
display?: string
warning?: 'warning' | 'error'
}
/**
* Computes input/output USDC equivalents and the price impact.
* Returns the price impact as a human readable string.
......@@ -14,8 +19,7 @@ export default function useUSDCPriceImpact(
): {
inputUSDC?: CurrencyAmount<Token>
outputUSDC?: CurrencyAmount<Token>
priceImpact?: string
warning?: 'warning' | 'error'
priceImpact: PriceImpact
} {
const inputUSDC = useUSDCValue(inputAmount) ?? undefined
const outputUSDC = useUSDCValue(outputAmount) ?? undefined
......@@ -25,8 +29,11 @@ export default function useUSDCPriceImpact(
return {
inputUSDC,
outputUSDC,
priceImpact: priceImpact && toHumanReadablePriceImpact(priceImpact),
priceImpact: {
priceImpact,
display: priceImpact && toHumanReadablePriceImpact(priceImpact),
warning,
},
}
}, [inputUSDC, outputUSDC])
}
......
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