feat: [info] add new stats box (#7522)

* feat: [info] add new stats section, wip

* add stats section

* implement fdv and market cap

* use fdv from backend gql

* code cleanup

* update cypress tests

* should only wrap if screen width <= 640

* minor design nits

* remove sitemap change

* nit pr review
This commit is contained in:
Kristie Huang 2023-11-06 15:54:43 -05:00 committed by GitHub
parent 098c7b9cbe
commit 5cbc56cf65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 131 additions and 39 deletions

@ -1,4 +1,5 @@
import { ChainId, WETH9 } from '@uniswap/sdk-core'
import { FeatureFlag } from 'featureFlags'
import { ARB, UNI } from '../../src/constants/tokens'
import { getTestSelector } from '../utils'
@ -14,8 +15,9 @@ describe('Token details', () => {
it('Uniswap token should have all information populated', () => {
// Uniswap token
cy.visit(`/tokens/ethereum/${UNI_ADDRESS}`)
cy.visit(`/tokens/ethereum/${UNI_ADDRESS}`, {
featureFlags: [{ name: FeatureFlag.infoTDP, value: false }],
})
// Price chart should be filled in
cy.get('[data-cy="chart-header"]').should('include.text', '$')
cy.get('[data-cy="price-chart"]').should('exist')
@ -47,6 +49,22 @@ describe('Token details', () => {
cy.contains(UNI_ADDRESS).should('exist')
})
it('Uniswap token should have correct stats boxes if infoTDP flag on', () => {
// Uniswap token
cy.visit(`/tokens/ethereum/${UNI_ADDRESS}`, {
featureFlags: [{ name: FeatureFlag.infoTDP, value: true }],
})
// Stats should have: TVL, FDV, market cap, 24H volume
cy.get(getTestSelector('token-details-stats')).should('exist')
cy.get(getTestSelector('token-details-stats')).within(() => {
cy.get('[data-cy="tvl"]').should('include.text', '$')
cy.get('[data-cy="fdv"]').should('include.text', '$')
cy.get('[data-cy="market-cap"]').should('include.text', '$')
cy.get('[data-cy="volume-24h"]').should('include.text', '$')
})
})
it('token with warning and low trading volume should have all information populated', () => {
// Null token created for this test, 0 trading volume and has warning modal
cy.visit('/tokens/ethereum/0x1eFBB78C8b917f67986BcE54cE575069c0143681')

@ -2,6 +2,8 @@ import { Trans } from '@lingui/macro'
import { ChainId } from '@uniswap/sdk-core'
import { MouseoverTooltip } from 'components/Tooltip'
import { getChainInfo } from 'constants/chainInfo'
import { useInfoTDPEnabled } from 'featureFlags/flags/infoTDP'
import { TokenQueryData } from 'graphql/data/Token'
import { ReactNode } from 'react'
import styled from 'styled-components'
import { ExternalLink, ThemedText } from 'theme/components'
@ -15,9 +17,13 @@ import { HEADER_DESCRIPTIONS } from '../TokenTable/TokenRow'
export const StatWrapper = styled.div`
color: ${({ theme }) => theme.neutral2};
font-size: 14px;
min-width: 168px;
min-width: 121px;
flex: 1;
padding: 24px 0px;
@media screen and (max-width: ${({ theme }) => theme.breakpoint.sm}px) {
min-width: 168px;
}
`
const TokenStatsSection = styled.div`
display: flex;
@ -77,22 +83,76 @@ function Stat({
type StatsSectionProps = {
chainId: ChainId
address: string
priceLow52W?: NumericStat
priceHigh52W?: NumericStat
TVL?: NumericStat
volume24H?: NumericStat
tokenQueryData: TokenQueryData
}
export default function StatsSection(props: StatsSectionProps) {
const { chainId, address, priceLow52W, priceHigh52W, TVL, volume24H } = props
const { chainId, address, tokenQueryData } = props
const { label, infoLink } = getChainInfo(chainId)
const isInfoTDPEnabled = useInfoTDPEnabled()
if (TVL || volume24H || priceLow52W || priceHigh52W) {
const tokenMarketInfo = tokenQueryData?.market
const tokenProjectMarketInfo = tokenQueryData?.project?.markets?.[0] // aggregated market price from CoinGecko
const FDV = tokenProjectMarketInfo?.fullyDilutedValuation?.value
const marketCap = tokenProjectMarketInfo?.marketCap?.value
const TVL = tokenMarketInfo?.totalValueLocked?.value
const volume24H = tokenMarketInfo?.volume24H?.value
const priceHigh52W = tokenMarketInfo?.priceHigh52W?.value
const priceLow52W = tokenMarketInfo?.priceLow52W?.value
const hasStats = isInfoTDPEnabled
? TVL || FDV || marketCap || volume24H
: TVL || volume24H || priceLow52W || priceHigh52W
if (hasStats) {
return (
<StatsWrapper data-testid="token-details-stats">
<Header>
<Trans>Stats</Trans>
</Header>
<TokenStatsSection>
{isInfoTDPEnabled ? (
<>
<StatPair>
<Stat
dataCy="tvl"
value={TVL}
description={HEADER_DESCRIPTIONS[TokenSortMethod.TOTAL_VALUE_LOCKED]}
title={<Trans>TVL</Trans>}
/>
<Stat
dataCy="market-cap"
value={marketCap}
description={
<Trans>
Market capitalization is the total market value of an asset&apos;s circulating supply.
</Trans>
}
title={<Trans>Market cap</Trans>}
/>
</StatPair>
<StatPair>
<Stat
dataCy="fdv"
value={FDV}
description={HEADER_DESCRIPTIONS[TokenSortMethod.FULLY_DILUTED_VALUATION]}
title={<Trans>FDV</Trans>}
/>
<Stat
dataCy="volume-24h"
value={volume24H}
description={
<Trans>
1 day volume is the amount of the asset that has been traded on Uniswap v3 during the past 24
hours.
</Trans>
}
title={<Trans>1 day volume</Trans>}
/>
</StatPair>
</>
) : (
<>
<StatPair>
<Stat
dataCy="tvl"
@ -115,6 +175,8 @@ export default function StatsSection(props: StatsSectionProps) {
<Stat dataCy="52w-low" value={priceLow52W} title={<Trans>52W low</Trans>} />
<Stat dataCy="52w-high" value={priceHigh52W} title={<Trans>52W high</Trans>} />
</StatPair>
</>
)}
</TokenStatsSection>
</StatsWrapper>
)

@ -237,14 +237,7 @@ export default function TokenDetails({
</TokenInfoContainer>
<ChartSection tokenPriceQuery={tokenPriceQuery} onChangeTimePeriod={onChangeTimePeriod} />
<StatsSection
chainId={pageChainId}
address={address}
TVL={tokenQueryData?.market?.totalValueLocked?.value}
volume24H={tokenQueryData?.market?.volume24H?.value}
priceHigh52W={tokenQueryData?.market?.priceHigh52W?.value}
priceLow52W={tokenQueryData?.market?.priceLow52W?.value}
/>
<StatsSection chainId={pageChainId} address={address} tokenQueryData={tokenQueryData} />
<Hr />
<AboutSection
address={address}

@ -304,6 +304,12 @@ export const HEADER_DESCRIPTIONS: Record<TokenSortMethod, ReactNode | undefined>
Total value locked (TVL) is the aggregate amount of the asset available across all Uniswap v3 liquidity pools.
</Trans>
),
[TokenSortMethod.FULLY_DILUTED_VALUATION]: (
<Trans>
Fully diluted valuation (FDV) is the market capitalization of an asset if maximum token supply were in
circulation.
</Trans>
),
[TokenSortMethod.VOLUME]: (
<Trans>Volume is the amount of the asset that has been traded on Uniswap v3 during the selected time frame.</Trans>
),

@ -4,6 +4,7 @@ import { atomWithReset } from 'jotai/utils'
import { useCallback } from 'react'
export enum TokenSortMethod {
FULLY_DILUTED_VALUATION = 'FDV',
PRICE = 'Price',
PERCENT_CHANGE = 'Change',
TOTAL_VALUE_LOCKED = 'TVL',

@ -58,6 +58,18 @@ gql`
chain
address
}
markets(currencies: [USD]) {
fullyDilutedValuation {
id
value
currency
}
marketCap {
id
value
currency
}
}
}
}
}