show currency values and price impact in the confirmation modal (fixes https://github.com/Uniswap/v3-interface/issues/92)

This commit is contained in:
Moody Salem 2021-05-04 08:38:47 -05:00
parent f4e994867e
commit 300dd70804
No known key found for this signature in database
GPG Key ID: 8CB5CD10385138DB
6 changed files with 71 additions and 45 deletions

@ -0,0 +1,32 @@
import { CurrencyAmount, Percent } from '@uniswap/sdk-core'
import React, { useMemo } from 'react'
import useTheme from '../../hooks/useTheme'
import { TYPE } from '../../theme'
import { warningSeverity } from '../../utils/prices'
export function FiatValue({
fiatValue,
priceImpact,
}: {
fiatValue: CurrencyAmount | null | undefined
priceImpact?: Percent
}) {
const theme = useTheme()
const priceImpactColor = useMemo(() => {
if (!priceImpact) return undefined
if (priceImpact.lessThan('0')) return theme.green1
const severity = warningSeverity(priceImpact)
if (severity < 1) return theme.text4
if (severity < 3) return theme.yellow1
return theme.red1
}, [priceImpact, theme.green1, theme.red1, theme.text4, theme.yellow1])
return (
<TYPE.body fontSize={14} color={fiatValue ? theme.text2 : theme.text4}>
{fiatValue ? '~' : ''}${fiatValue ? Number(fiatValue?.toSignificant(6)).toLocaleString('en') : '-'}
{priceImpact ? (
<span style={{ color: priceImpactColor }}> ({priceImpact.multiply(-100).toSignificant(3)}%)</span>
) : null}
</TYPE.body>
)
}

@ -1,10 +1,9 @@
import { Pair } from '@uniswap/v2-sdk' import { Pair } from '@uniswap/v2-sdk'
import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core' import { Currency, CurrencyAmount, Percent } from '@uniswap/sdk-core'
import React, { useState, useCallback, useMemo } from 'react' import React, { useState, useCallback } from 'react'
import styled from 'styled-components' import styled from 'styled-components'
import { darken } from 'polished' import { darken } from 'polished'
import { useCurrencyBalance } from '../../state/wallet/hooks' import { useCurrencyBalance } from '../../state/wallet/hooks'
import { warningSeverity } from '../../utils/prices'
import CurrencySearchModal from '../SearchModal/CurrencySearchModal' import CurrencySearchModal from '../SearchModal/CurrencySearchModal'
import CurrencyLogo from '../CurrencyLogo' import CurrencyLogo from '../CurrencyLogo'
import DoubleCurrencyLogo from '../DoubleLogo' import DoubleCurrencyLogo from '../DoubleLogo'
@ -18,6 +17,7 @@ import { useTranslation } from 'react-i18next'
import useTheme from '../../hooks/useTheme' import useTheme from '../../hooks/useTheme'
import { Lock } from 'react-feather' import { Lock } from 'react-feather'
import { AutoColumn } from 'components/Column' import { AutoColumn } from 'components/Column'
import { FiatValue } from './FiatValue'
const InputPanel = styled.div<{ hideInput?: boolean }>` const InputPanel = styled.div<{ hideInput?: boolean }>`
${({ theme }) => theme.flexColumnNoWrap} ${({ theme }) => theme.flexColumnNoWrap}
@ -196,15 +196,6 @@ export default function CurrencyInputPanel({
setModalOpen(false) setModalOpen(false)
}, [setModalOpen]) }, [setModalOpen])
const priceImpactColor = useMemo(() => {
if (!priceImpact) return undefined
if (priceImpact.lessThan('0')) return theme.green1
const severity = warningSeverity(priceImpact)
if (severity < 1) return theme.text4
if (severity < 3) return theme.yellow1
return theme.red1
}, [priceImpact, theme.green1, theme.red1, theme.text4, theme.yellow1])
return ( return (
<InputPanel id={id} hideInput={hideInput} {...rest}> <InputPanel id={id} hideInput={hideInput} {...rest}>
{locked && ( {locked && (
@ -291,12 +282,7 @@ export default function CurrencyInputPanel({
</RowFixed> </RowFixed>
)} )}
<TYPE.body fontSize={14} color={fiatValue ? theme.text2 : theme.text4}> <FiatValue fiatValue={fiatValue} priceImpact={priceImpact} />
{fiatValue ? '~' : ''}${fiatValue ? Number(fiatValue?.toSignificant(6)).toLocaleString('en') : '-'}
{priceImpact ? (
<span style={{ color: priceImpactColor }}> ({priceImpact.multiply(-100).toSignificant(3)}%)</span>
) : null}
</TYPE.body>
</RowBetween> </RowBetween>
</FiatRow> </FiatRow>
)} )}

@ -5,10 +5,12 @@ import React, { useContext, useState } from 'react'
import { ArrowDown, AlertTriangle } from 'react-feather' import { ArrowDown, AlertTriangle } from 'react-feather'
import { Text } from 'rebass' import { Text } from 'rebass'
import styled, { ThemeContext } from 'styled-components' import styled, { ThemeContext } from 'styled-components'
import { useUSDCValue } from '../../hooks/useUSDCPrice'
import { TYPE } from '../../theme' import { TYPE } from '../../theme'
import { ButtonPrimary } from '../Button' import { ButtonPrimary } from '../Button'
import { isAddress, shortenAddress } from '../../utils' import { computeFiatValuePriceImpact, isAddress, shortenAddress } from '../../utils'
import { AutoColumn } from '../Column' import { AutoColumn } from '../Column'
import { FiatValue } from '../CurrencyInputPanel/FiatValue'
import CurrencyLogo from '../CurrencyLogo' import CurrencyLogo from '../CurrencyLogo'
import { RowBetween, RowFixed } from '../Row' import { RowBetween, RowFixed } from '../Row'
import { TruncatedText, SwapShowAcceptChanges } from './styleds' import { TruncatedText, SwapShowAcceptChanges } from './styleds'
@ -57,17 +59,18 @@ export default function SwapModalHeader({
const [showInverted, setShowInverted] = useState<boolean>(false) const [showInverted, setShowInverted] = useState<boolean>(false)
const fiatValueInput = useUSDCValue(maximumAmountIn)
const fiatValueOutput = useUSDCValue(minimumAmountOut)
return ( return (
<AutoColumn gap={'4px'} style={{ marginTop: '1rem' }}> <AutoColumn gap={'4px'} style={{ marginTop: '1rem' }}>
<DarkGreyCard padding="0.75rem 1rem"> <DarkGreyCard padding="0.75rem 1rem">
<AutoColumn gap={'8px'}> <AutoColumn gap={'8px'}>
<RowBetween> <RowBetween>
<TYPE.body color={theme.text3} fontWeight={500} fontSize={14}> <TYPE.body color={theme.text3} fontWeight={500} fontSize={14}>
{'From'} From
</TYPE.body>
<TYPE.body fontSize={14} color={theme.text3}>
{'$-'}
</TYPE.body> </TYPE.body>
<FiatValue fiatValue={fiatValueInput} />
</RowBetween> </RowBetween>
<RowBetween align="center"> <RowBetween align="center">
<RowFixed gap={'0px'}> <RowFixed gap={'0px'}>
@ -95,10 +98,13 @@ export default function SwapModalHeader({
<AutoColumn gap={'8px'}> <AutoColumn gap={'8px'}>
<RowBetween> <RowBetween>
<TYPE.body color={theme.text3} fontWeight={500} fontSize={14}> <TYPE.body color={theme.text3} fontWeight={500} fontSize={14}>
{'To'} To
</TYPE.body> </TYPE.body>
<TYPE.body fontSize={14} color={theme.text3}> <TYPE.body fontSize={14} color={theme.text3}>
{'$-'} <FiatValue
fiatValue={fiatValueOutput}
priceImpact={computeFiatValuePriceImpact(fiatValueInput, fiatValueOutput)}
/>
</TYPE.body> </TYPE.body>
</RowBetween> </RowBetween>
<RowBetween align="flex-end"> <RowBetween align="flex-end">

@ -1,4 +1,4 @@
import { CurrencyAmount, currencyEquals, Percent, Token } from '@uniswap/sdk-core' import { CurrencyAmount, Token } 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 { AdvancedSwapDetails } from 'components/swap/AdvancedSwapDetails' import { AdvancedSwapDetails } from 'components/swap/AdvancedSwapDetails'
@ -6,26 +6,27 @@ import UnsupportedCurrencyFooter from 'components/swap/UnsupportedCurrencyFooter
import { MouseoverTooltip, MouseoverTooltipContent } from 'components/Tooltip' import { MouseoverTooltip, MouseoverTooltipContent } from 'components/Tooltip'
import JSBI from 'jsbi' import JSBI from 'jsbi'
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react' import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react'
import { ArrowDown, HelpCircle, CheckCircle, Info, X } from 'react-feather' import { ArrowDown, CheckCircle, HelpCircle, Info, X } from 'react-feather'
import ReactGA from 'react-ga' import ReactGA from 'react-ga'
import { RouteComponentProps } from 'react-router-dom' import { Link, RouteComponentProps } from 'react-router-dom'
import { Text } from 'rebass' import { Text } from 'rebass'
import { ThemeContext } from 'styled-components' import { ThemeContext } from 'styled-components'
import AddressInputPanel from '../../components/AddressInputPanel' import AddressInputPanel from '../../components/AddressInputPanel'
import { ButtonConfirmed, ButtonError, ButtonLight, ButtonPrimary, ButtonGray } from '../../components/Button' import { ButtonConfirmed, ButtonError, ButtonGray, ButtonLight, ButtonPrimary } from '../../components/Button'
import { GreyCard } from '../../components/Card' import { GreyCard } from '../../components/Card'
import { AutoColumn } from '../../components/Column' import { AutoColumn } from '../../components/Column'
import CurrencyInputPanel from '../../components/CurrencyInputPanel' import CurrencyInputPanel from '../../components/CurrencyInputPanel'
import CurrencyLogo from '../../components/CurrencyLogo' import CurrencyLogo from '../../components/CurrencyLogo'
import Loader from '../../components/Loader' import Loader from '../../components/Loader'
import { AutoRow, RowBetween, RowFixed } from '../../components/Row' import { AutoRow, RowBetween, RowFixed } from '../../components/Row'
import BetterTradeLink from '../../components/swap/BetterTradeLink'
import confirmPriceImpactWithoutFee from '../../components/swap/confirmPriceImpactWithoutFee' import confirmPriceImpactWithoutFee from '../../components/swap/confirmPriceImpactWithoutFee'
import ConfirmSwapModal from '../../components/swap/ConfirmSwapModal' import ConfirmSwapModal from '../../components/swap/ConfirmSwapModal'
import { ArrowWrapper, BottomGrouping, Dots, SwapCallbackError, Wrapper } from '../../components/swap/styleds' import { ArrowWrapper, BottomGrouping, Dots, SwapCallbackError, Wrapper } from '../../components/swap/styleds'
import SwapHeader from '../../components/swap/SwapHeader'
import TradePrice from '../../components/swap/TradePrice' import TradePrice from '../../components/swap/TradePrice'
import TokenWarningModal from '../../components/TokenWarningModal' import TokenWarningModal from '../../components/TokenWarningModal'
import { ONE_HUNDRED_PERCENT } from '../../constants'
import { useActiveWeb3React } from '../../hooks' import { useActiveWeb3React } from '../../hooks'
import { useAllTokens, useCurrency } from '../../hooks/Tokens' import { useAllTokens, useCurrency } from '../../hooks/Tokens'
import { ApprovalState, useApproveCallbackFromTrade } from '../../hooks/useApproveCallback' import { ApprovalState, useApproveCallbackFromTrade } from '../../hooks/useApproveCallback'
@ -47,27 +48,13 @@ import {
} from '../../state/swap/hooks' } from '../../state/swap/hooks'
import { useExpertModeManager, useUserSingleHopOnly, useUserSlippageTolerance } from '../../state/user/hooks' import { useExpertModeManager, useUserSingleHopOnly, useUserSlippageTolerance } from '../../state/user/hooks'
import { LinkStyledButton, TYPE } from '../../theme' import { LinkStyledButton, TYPE } from '../../theme'
import { computeFiatValuePriceImpact } from '../../utils'
import { getTradeVersion } from '../../utils/getTradeVersion' import { getTradeVersion } from '../../utils/getTradeVersion'
import { isTradeBetter } from '../../utils/isTradeBetter'
import { maxAmountSpend } from '../../utils/maxAmountSpend' import { maxAmountSpend } from '../../utils/maxAmountSpend'
import { warningSeverity } from '../../utils/prices' import { warningSeverity } from '../../utils/prices'
import AppBody from '../AppBody' import AppBody from '../AppBody'
import { Link } from 'react-router-dom'
import { isTradeBetter } from '../../utils/isTradeBetter'
import BetterTradeLink from '../../components/swap/BetterTradeLink'
import SwapHeader from '../../components/swap/SwapHeader'
function computeFiatValuePriceImpact(
fiatValueInput: CurrencyAmount | undefined | null,
fiatValueOutput: CurrencyAmount | undefined | null
): Percent | undefined {
if (!fiatValueOutput || !fiatValueInput) return undefined
if (!currencyEquals(fiatValueInput.currency, fiatValueOutput.currency)) return undefined
if (JSBI.equal(fiatValueInput.raw, JSBI.BigInt(0))) return undefined
const pct = ONE_HUNDRED_PERCENT.subtract(fiatValueOutput.divide(fiatValueInput))
return new Percent(pct.numerator, pct.denominator)
}
export default function Swap({ history }: RouteComponentProps) { export default function Swap({ history }: RouteComponentProps) {
const loadedUrlParams = useDefaultsFromURLSearch() const loadedUrlParams = useDefaultsFromURLSearch()

@ -0,0 +1,14 @@
import { CurrencyAmount, currencyEquals, Percent } from '@uniswap/sdk-core'
import JSBI from 'jsbi'
import { ONE_HUNDRED_PERCENT } from '../constants'
export function computeFiatValuePriceImpact(
fiatValueInput: CurrencyAmount | undefined | null,
fiatValueOutput: CurrencyAmount | undefined | null
): Percent | undefined {
if (!fiatValueOutput || !fiatValueInput) return undefined
if (!currencyEquals(fiatValueInput.currency, fiatValueOutput.currency)) return undefined
if (JSBI.equal(fiatValueInput.raw, JSBI.BigInt(0))) return undefined
const pct = ONE_HUNDRED_PERCENT.subtract(fiatValueOutput.divide(fiatValueInput))
return new Percent(pct.numerator, pct.denominator)
}

@ -119,3 +119,4 @@ export function supportedChainId(chainId: number): ChainId | undefined {
export function formattedFeeAmount(feeAmount: FeeAmount): number { export function formattedFeeAmount(feeAmount: FeeAmount): number {
return feeAmount / 10000 return feeAmount / 10000
} }
export { computeFiatValuePriceImpact } from './computeFiatValuePriceImpact'