simplify range ui
This commit is contained in:
parent
c3ad129658
commit
2d7642ed9b
@ -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>
|
||||
{currency0?.symbol} / {currency1?.symbol}
|
||||
{currencyQuote?.symbol} / {currencyBase?.symbol}
|
||||
</DataText>
|
||||
|
||||
<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} /
|
||||
{currency0?.symbol}
|
||||
</DataLineItem>
|
||||
<DataLineItem>
|
||||
{formatPrice(price1Lower, 4)} <DoubleArrow>↔</DoubleArrow> {formatPrice(price1Upper, 4)}{' '}
|
||||
{currency0?.symbol} /
|
||||
{currency1?.symbol}
|
||||
{formatPrice(priceLower, 4)} <DoubleArrow>↔</DoubleArrow> {formatPrice(priceUpper, 4)}{' '}
|
||||
{currencyQuote?.symbol}
|
||||
/
|
||||
{currencyBase?.symbol}
|
||||
</DataLineItem>
|
||||
</>
|
||||
) : (
|
||||
@ -219,13 +271,13 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
|
||||
)}
|
||||
</RangeData>
|
||||
<AmountData>
|
||||
{!poolLoading ? (
|
||||
{formattedAmount0 && formattedAmount1 ? (
|
||||
<>
|
||||
<DataLineItem>
|
||||
{formattedAmount0} {currency0?.symbol}
|
||||
{inverted ? formattedAmount0 : formattedAmount1} {currencyQuote?.symbol}
|
||||
</DataLineItem>
|
||||
<DataLineItem>
|
||||
{formattedAmount1} {currency1?.symbol}
|
||||
{inverted ? formattedAmount1 : formattedAmount0} {currencyBase?.symbol}
|
||||
</DataLineItem>
|
||||
</>
|
||||
) : (
|
||||
@ -236,10 +288,10 @@ export default function PositionListItem({ positionDetails }: PositionListItemPr
|
||||
{feeValue0 && feeValue1 ? (
|
||||
<>
|
||||
<DataLineItem>
|
||||
{formatTokenAmount(feeValue0, 4)} {currency0?.symbol}
|
||||
{formatTokenAmount(inverted ? feeValue0 : feeValue1, 4)} {currencyQuote?.symbol}
|
||||
</DataLineItem>
|
||||
<DataLineItem>
|
||||
{formatTokenAmount(feeValue1, 4)} {currency1?.symbol}
|
||||
{formatTokenAmount(inverted ? feeValue1 : feeValue0, 4)} {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">
|
||||
{currency0?.symbol} / {currency1?.symbol}
|
||||
{currencyQuote?.symbol} / {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>
|
||||
<TYPE.label display="flex">
|
||||
Position Limits
|
||||
<ButtonText style={{ marginLeft: '10px', color: 'inherit' }}>
|
||||
{manuallyInverted ? (
|
||||
<ToggleLeft onClick={() => setManuallyInverted(false)} />
|
||||
) : (
|
||||
<ToggleRight onClick={() => setManuallyInverted(true)} />
|
||||
)}
|
||||
</ButtonText>
|
||||
</TYPE.label>
|
||||
|
||||
<RowBetween>
|
||||
<DarkGreyCard width="49%">
|
||||
<DarkGreyCard width="48%">
|
||||
<AutoColumn gap="sm" justify="flex-start">
|
||||
<TYPE.main>Lower Limit</TYPE.main>
|
||||
<TYPE.main>Lower</TYPE.main>
|
||||
<RowFixed>
|
||||
<TYPE.label>{price0Lower?.toSignificant(4)}</TYPE.label>
|
||||
<TYPE.label ml="10px">
|
||||
{currency0?.symbol} / {currency1?.symbol}
|
||||
</TYPE.label>
|
||||
</RowFixed>
|
||||
<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);
|
||||
|
Loading…
Reference in New Issue
Block a user