simplify range ui

This commit is contained in:
Noah Zinsmeister 2021-04-26 14:15:32 -04:00
parent c3ad129658
commit 2d7642ed9b
No known key found for this signature in database
GPG Key ID: 83022DD49188C9F2
3 changed files with 146 additions and 69 deletions

@ -2,7 +2,7 @@ import React, { useMemo } from 'react'
import { Position } from '@uniswap/v3-sdk'
import Badge, { BadgeVariant } from 'components/Badge'
import DoubleCurrencyLogo from 'components/DoubleLogo'
import { PoolState, usePool } from 'hooks/usePools'
import { usePool } from 'hooks/usePools'
import { useToken } from 'hooks/Tokens'
import { AlertTriangle } from 'react-feather'
import { useTranslation } from 'react-i18next'
@ -11,11 +11,12 @@ import styled from 'styled-components'
import { MEDIA_WIDTHS } from 'theme'
import { PositionDetails } from 'types/position'
import { basisPointsToPercent } from 'utils'
import { TokenAmount } from '@uniswap/sdk-core'
import { TokenAmount, WETH9, Price, Token } from '@uniswap/sdk-core'
import { formatPrice, formatTokenAmount } from 'utils/formatTokenAmount'
import Loader from 'components/Loader'
import { unwrappedToken } from 'utils/wrappedCurrency'
import { useV3PositionFees } from 'hooks/useV3PositionFees'
import { DAI, USDC, USDT, WBTC } from '../../constants'
const ActiveDot = styled.span`
background-color: ${({ theme }) => theme.success};
@ -123,6 +124,62 @@ export interface PositionListItemProps {
positionDetails: PositionDetails
}
export function getPriceOrderingFromPositionForUI(
position?: Position
): {
priceLower?: Price
priceUpper?: Price
quote?: Token
base?: Token
} {
if (!position) {
return {}
}
const token0 = position.amount0.token
const token1 = position.amount1.token
// if token0 is a dollar-stable asset, set it as the quote token
const stables = [DAI, USDC, USDT]
if (stables.some((stable) => stable.equals(token0))) {
return {
priceLower: position.token0PriceUpper.invert(),
priceUpper: position.token0PriceLower.invert(),
quote: token0,
base: token1,
}
}
// if token1 is an ETH-/BTC-stable asset, set it as the base token
const bases = [...Object.values(WETH9), WBTC]
if (bases.some((base) => base.equals(token1))) {
return {
priceLower: position.token0PriceUpper.invert(),
priceUpper: position.token0PriceLower.invert(),
quote: token0,
base: token1,
}
}
// if both prices are below 1, invert
if (position.token0PriceUpper.lessThan(1)) {
return {
priceLower: position.token0PriceUpper.invert(),
priceUpper: position.token0PriceLower.invert(),
quote: token0,
base: token1,
}
}
// otherwise, just return the default
return {
priceLower: position.token0PriceUpper.invert(),
priceUpper: position.token0PriceLower.invert(),
quote: token1,
base: token0,
}
}
export default function PositionListItem({ positionDetails }: PositionListItemProps) {
const { t } = useTranslation()
@ -142,7 +199,8 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
const currency1 = token1 ? unwrappedToken(token1) : undefined
// construct Position from details returned
const [poolState, pool] = usePool(currency0 ?? undefined, currency1 ?? undefined, feeAmount)
const [, pool] = usePool(currency0 ?? undefined, currency1 ?? undefined, feeAmount)
const position = useMemo(() => {
if (pool) {
return new Position({ pool, liquidity: liquidity.toString(), tickLower, tickUpper })
@ -150,8 +208,6 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
return undefined
}, [liquidity, pool, tickLower, tickUpper])
const poolLoading = poolState === PoolState.LOADING
// liquidity amounts in tokens
const amount0: TokenAmount | undefined = position?.amount0
const amount1: TokenAmount | undefined = position?.amount1
@ -159,10 +215,10 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
const formattedAmount1 = formatTokenAmount(amount1, 4)
// prices
const price0Lower = position?.token0PriceLower
const price0Upper = position?.token0PriceUpper
const price1Lower = price0Lower?.invert()
const price1Upper = price0Upper?.invert()
const { priceLower, priceUpper, base } = getPriceOrderingFromPositionForUI(position)
const inverted = token1 ? base?.equals(token1) : undefined
const currencyQuote = inverted ? currency0 : currency1
const currencyBase = inverted ? currency1 : currency0
// fees
const [feeValue0, feeValue1] = useV3PositionFees(pool ?? undefined, positionDetails)
@ -176,9 +232,9 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
<Row to={positionSummaryLink}>
<LabelData>
<PrimaryPositionIdData>
<DoubleCurrencyLogo currency0={currency0 ?? undefined} currency1={currency1 ?? undefined} size={16} margin />
<DoubleCurrencyLogo currency0={currencyBase} currency1={currencyQuote} size={16} margin />
<DataText>
&nbsp;{currency0?.symbol}&nbsp;/&nbsp;{currency1?.symbol}
&nbsp;{currencyQuote?.symbol}&nbsp;/&nbsp;{currencyBase?.symbol}
</DataText>
&nbsp;
<Badge>
@ -201,17 +257,13 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
</BadgeWrapper>
</LabelData>
<RangeData>
{price0Lower && price1Lower && price0Upper && price1Upper ? (
{priceLower && priceUpper ? (
<>
<DataLineItem>
{formatPrice(price0Lower, 4)} <DoubleArrow></DoubleArrow> {formatPrice(price0Upper, 4)}{' '}
{currency1?.symbol}&nbsp;/&nbsp;
{currency0?.symbol}
</DataLineItem>
<DataLineItem>
{formatPrice(price1Lower, 4)} <DoubleArrow></DoubleArrow> {formatPrice(price1Upper, 4)}{' '}
{currency0?.symbol}&nbsp;/&nbsp;
{currency1?.symbol}
{formatPrice(priceLower, 4)} <DoubleArrow></DoubleArrow> {formatPrice(priceUpper, 4)}{' '}
{currencyQuote?.symbol}
&nbsp;/&nbsp;
{currencyBase?.symbol}
</DataLineItem>
</>
) : (
@ -219,13 +271,13 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
)}
</RangeData>
<AmountData>
{!poolLoading ? (
{formattedAmount0 && formattedAmount1 ? (
<>
<DataLineItem>
{formattedAmount0}&nbsp;{currency0?.symbol}
{inverted ? formattedAmount0 : formattedAmount1}&nbsp;{currencyQuote?.symbol}
</DataLineItem>
<DataLineItem>
{formattedAmount1}&nbsp;{currency1?.symbol}
{inverted ? formattedAmount1 : formattedAmount0}&nbsp;{currencyBase?.symbol}
</DataLineItem>
</>
) : (
@ -236,10 +288,10 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
{feeValue0 && feeValue1 ? (
<>
<DataLineItem>
{formatTokenAmount(feeValue0, 4)}&nbsp;{currency0?.symbol}
{formatTokenAmount(inverted ? feeValue0 : feeValue1, 4)}&nbsp;{currencyQuote?.symbol}
</DataLineItem>
<DataLineItem>
{formatTokenAmount(feeValue1, 4)}&nbsp;{currency1?.symbol}
{formatTokenAmount(inverted ? feeValue1 : feeValue0, 4)}&nbsp;{currencyBase?.symbol}
</DataLineItem>
</>
) : (

@ -10,13 +10,13 @@ import styled from 'styled-components'
import { AutoColumn } from 'components/Column'
import { RowBetween, RowFixed } from 'components/Row'
import DoubleCurrencyLogo from 'components/DoubleLogo'
import { TYPE } from 'theme'
import { ButtonText, TYPE } from 'theme'
import Badge, { BadgeVariant } from 'components/Badge'
import { basisPointsToPercent } from 'utils'
import { ButtonConfirmed, ButtonPrimary } from 'components/Button'
import { DarkCard, DarkGreyCard } from 'components/Card'
import CurrencyLogo from 'components/CurrencyLogo'
import { AlertTriangle } from 'react-feather'
import { AlertTriangle, ToggleLeft, ToggleRight } from 'react-feather'
import { useTranslation } from 'react-i18next'
import { currencyId } from 'utils/currencyId'
import { formatTokenAmount } from 'utils/formatTokenAmount'
@ -30,6 +30,7 @@ import { useIsTransactionPending, useTransactionAdder } from 'state/transactions
import ReactGA from 'react-ga'
import { TransactionResponse } from '@ethersproject/providers'
import { Dots } from 'components/swap/styleds'
import { getPriceOrderingFromPositionForUI } from '../../components/PositionListItem'
const PageWrapper = styled.div`
min-width: 800px;
@ -122,10 +123,15 @@ export function PositionPage({
return undefined
}, [liquidity, pool, tickLower, tickUpper])
const price0Lower = position?.token0PriceLower
const price0Upper = position?.token0PriceUpper
const price1Lower = price0Lower?.invert()
const price1Upper = price0Upper?.invert()
let { priceLower, priceUpper, base, quote } = getPriceOrderingFromPositionForUI(position)
const [manuallyInverted, setManuallyInverted] = useState(false)
// handle manual inversion
if (manuallyInverted) {
;[priceLower, priceUpper, base, quote] = [priceUpper?.invert(), priceLower?.invert(), quote, base]
}
const inverted = token1 ? base?.equals(token1) : undefined
const currencyQuote = inverted ? currency0 : currency1
const currencyBase = inverted ? currency1 : currency0
// check if price is within range
const outOfRange: boolean =
@ -225,9 +231,9 @@ export function PositionPage({
<AutoColumn gap="sm">
<RowBetween>
<RowFixed>
<DoubleCurrencyLogo currency0={currency0} currency1={currency1} size={20} margin={true} />
<DoubleCurrencyLogo currency0={currencyBase} currency1={currencyQuote} size={20} margin={true} />
<TYPE.label fontSize={'20px'} mr="10px">
&nbsp;{currency0?.symbol}&nbsp;/&nbsp;{currency1?.symbol}
&nbsp;{currencyQuote?.symbol}&nbsp;/&nbsp;{currencyBase?.symbol}
</TYPE.label>
<Badge>
<BadgeText>{basisPointsToPercent(feeAmount / 100).toSignificant()}%</BadgeText>
@ -290,75 +296,93 @@ export function PositionPage({
<AutoColumn gap="lg">
<ResponsiveGrid>
<Label>Tokens</Label>
<Label end={true}>Amount Deposited</Label>
<Label end={true}>Liquidity</Label>
<Label end={true}>Fees</Label>
</ResponsiveGrid>
<ResponsiveGrid>
<RowFixed>
<CurrencyLogo currency={currency0} />
<TYPE.label ml="10px">{currency0?.symbol}</TYPE.label>
<CurrencyLogo currency={currencyQuote} />
<TYPE.label ml="10px">{currencyQuote?.symbol}</TYPE.label>
</RowFixed>
<Label end={true}>{position?.amount0.toSignificant(4)}</Label>
<Label end={true}>{feeValue0 ? formatTokenAmount(feeValue0, 4) : '-'}</Label>
<Label end={true}>
{inverted ? position?.amount0.toSignificant(4) : position?.amount1.toSignificant(4)}
</Label>
<Label end={true}>
{inverted
? feeValue0
? formatTokenAmount(feeValue0, 4)
: '-'
: feeValue1
? formatTokenAmount(feeValue1, 4)
: '-'}
</Label>
</ResponsiveGrid>
<ResponsiveGrid>
<RowFixed>
<CurrencyLogo currency={currency1} />
<TYPE.label ml="10px">{currency1?.symbol}</TYPE.label>
<CurrencyLogo currency={currencyBase} />
<TYPE.label ml="10px">{currencyBase?.symbol}</TYPE.label>
</RowFixed>
<Label end={true}>{position?.amount1.toSignificant(4)}</Label>
<Label end={true}>{feeValue1 ? formatTokenAmount(feeValue1, 4) : '-'}</Label>
<Label end={true}>
{inverted ? position?.amount1.toSignificant(4) : position?.amount0.toSignificant(4)}
</Label>
<Label end={true}>
{inverted
? feeValue1
? formatTokenAmount(feeValue1, 4)
: '-'
: feeValue0
? formatTokenAmount(feeValue0, 4)
: '-'}
</Label>
</ResponsiveGrid>
</AutoColumn>
</DarkCard>
<DarkCard>
<AutoColumn gap="lg">
<TYPE.label>Position Limits</TYPE.label>
<RowBetween>
<DarkGreyCard width="49%">
<AutoColumn gap="sm" justify="flex-start">
<TYPE.main>Lower Limit</TYPE.main>
<RowFixed>
<TYPE.label>{price0Lower?.toSignificant(4)}</TYPE.label>
<TYPE.label ml="10px">
{currency0?.symbol} / {currency1?.symbol}
<TYPE.label display="flex">
Position Limits
<ButtonText style={{ marginLeft: '10px', color: 'inherit' }}>
{manuallyInverted ? (
<ToggleLeft onClick={() => setManuallyInverted(false)} />
) : (
<ToggleRight onClick={() => setManuallyInverted(true)} />
)}
</ButtonText>
</TYPE.label>
</RowFixed>
<RowBetween>
<DarkGreyCard width="48%">
<AutoColumn gap="sm" justify="flex-start">
<TYPE.main>Lower</TYPE.main>
<RowFixed>
<TYPE.label>{price1Lower?.toSignificant(4)}</TYPE.label>
<TYPE.label ml="10px">
{currency1?.symbol} / {currency0?.symbol}
<TYPE.label>
{priceLower?.toSignificant(4)} {currencyQuote?.symbol} / 1 {currencyBase?.symbol}
</TYPE.label>
</RowFixed>
<DarkBadge>
<RowFixed>
<TYPE.label mr="6px">100%</TYPE.label>
<CurrencyLogo currency={currency0} size="16px" />
<TYPE.label ml="4px">{currency0?.symbol}</TYPE.label>
<CurrencyLogo currency={inverted ? currency1 : currency0} size="16px" />
<TYPE.label ml="4px">{inverted ? currency1?.symbol : currency0?.symbol}</TYPE.label>
</RowFixed>
</DarkBadge>
</AutoColumn>
</DarkGreyCard>
<DarkGreyCard width="49%">
<DarkGreyCard width="48%">
<AutoColumn gap="sm" justify="flex-start">
<TYPE.main>Upper Limit</TYPE.main>
<TYPE.main>Upper</TYPE.main>
<RowFixed>
<TYPE.label>{price0Upper?.toSignificant(4)}</TYPE.label>
<TYPE.label ml="10px">
{currency0?.symbol} / {currency1?.symbol}
</TYPE.label>
</RowFixed>
<RowFixed>
<TYPE.label>{price1Upper?.toSignificant(4)}</TYPE.label>
<TYPE.label ml="10px">
{currency1?.symbol} / {currency0?.symbol}
<TYPE.label>
{priceUpper?.toSignificant(4)} {currencyQuote?.symbol} / 1 {currencyBase?.symbol}
</TYPE.label>
</RowFixed>
<DarkBadge>
<RowFixed>
<TYPE.label mr="6px">100%</TYPE.label>
<CurrencyLogo currency={currency1} size="16px" />
<TYPE.label ml="4px">{currency1?.symbol}</TYPE.label>
<CurrencyLogo currency={inverted ? currency0 : currency1} size="16px" />
<TYPE.label ml="4px">{inverted ? currency0?.symbol : currency1?.symbol}</TYPE.label>
</RowFixed>
</DarkBadge>
</AutoColumn>

@ -67,6 +67,7 @@ const loadingAnimation = keyframes`
export const LoadingRows = styled.div`
display: grid;
min-width: 75%;
grid-column-gap: 0.5em;
grid-row-gap: 0.8em;
grid-template-columns: repeat(3, 1fr);