Commit 751ba3c6 authored by Zach Pomerantz's avatar Zach Pomerantz Committed by GitHub

fix: token price (#5018)

* feat: add decimals, wrapper to token query

* fix: construct token in details page

* fix: clean widget default behavior

* fix: actual defaulting again

* fix: split token from price queries

* fix: reimplement TokenPrice query

* chore: rm old code

* fix: keep loading chart while loading

* fix: mv loader down

* fix: loading chart
parent 83bc6db7
import { SparkLineLoadingBubble } from 'components/Tokens/TokenTable/TokenRow' import { SparkLineLoadingBubble } from 'components/Tokens/TokenTable/TokenRow'
import { curveCardinal, scaleLinear } from 'd3' import { curveCardinal, scaleLinear } from 'd3'
import { PricePoint } from 'graphql/data/Token' import { PricePoint } from 'graphql/data/TokenPrice'
import { SparklineMap, TopToken } from 'graphql/data/TopTokens' import { SparklineMap, TopToken } from 'graphql/data/TopTokens'
import { TimePeriod } from 'graphql/data/util' import { TimePeriod } from 'graphql/data/util'
import { memo } from 'react' import { memo } from 'react'
......
...@@ -3,12 +3,12 @@ import { Currency, NativeCurrency, Token } from '@uniswap/sdk-core' ...@@ -3,12 +3,12 @@ import { Currency, NativeCurrency, Token } from '@uniswap/sdk-core'
import { ParentSize } from '@visx/responsive' import { ParentSize } from '@visx/responsive'
import CurrencyLogo from 'components/CurrencyLogo' import CurrencyLogo from 'components/CurrencyLogo'
import { getChainInfo } from 'constants/chainInfo' import { getChainInfo } from 'constants/chainInfo'
import { PriceDurations, PricePoint, SingleTokenData } from 'graphql/data/Token' import { TokenQueryData } from 'graphql/data/Token'
import { PriceDurations } from 'graphql/data/TokenPrice'
import { TopToken } from 'graphql/data/TopTokens' import { TopToken } from 'graphql/data/TopTokens'
import { CHAIN_NAME_TO_CHAIN_ID, TimePeriod } from 'graphql/data/util' import { CHAIN_NAME_TO_CHAIN_ID } from 'graphql/data/util'
import { useAtomValue } from 'jotai/utils' import { useAtomValue } from 'jotai/utils'
import useCurrencyLogoURIs from 'lib/hooks/useCurrencyLogoURIs' import useCurrencyLogoURIs from 'lib/hooks/useCurrencyLogoURIs'
import { useMemo } from 'react'
import styled from 'styled-components/macro' import styled from 'styled-components/macro'
import { textFadeIn } from 'theme/animations' import { textFadeIn } from 'theme/animations'
...@@ -54,7 +54,7 @@ const TokenActions = styled.div` ...@@ -54,7 +54,7 @@ const TokenActions = styled.div`
` `
export function useTokenLogoURI( export function useTokenLogoURI(
token: NonNullable<SingleTokenData> | NonNullable<TopToken>, token: NonNullable<TokenQueryData> | NonNullable<TopToken>,
nativeCurrency?: Token | NativeCurrency nativeCurrency?: Token | NativeCurrency
) { ) {
const chainId = CHAIN_NAME_TO_CHAIN_ID[token.chain] const chainId = CHAIN_NAME_TO_CHAIN_ID[token.chain]
...@@ -71,10 +71,10 @@ export default function ChartSection({ ...@@ -71,10 +71,10 @@ export default function ChartSection({
nativeCurrency, nativeCurrency,
prices, prices,
}: { }: {
token: NonNullable<SingleTokenData> token: NonNullable<TokenQueryData>
currency?: Currency | null currency?: Currency | null
nativeCurrency?: Token | NativeCurrency nativeCurrency?: Token | NativeCurrency
prices: PriceDurations prices?: PriceDurations
}) { }) {
const chainId = CHAIN_NAME_TO_CHAIN_ID[token.chain] const chainId = CHAIN_NAME_TO_CHAIN_ID[token.chain]
const L2Icon = getChainInfo(chainId)?.circleLogoUrl const L2Icon = getChainInfo(chainId)?.circleLogoUrl
...@@ -82,26 +82,6 @@ export default function ChartSection({ ...@@ -82,26 +82,6 @@ export default function ChartSection({
const logoSrc = useTokenLogoURI(token, nativeCurrency) const logoSrc = useTokenLogoURI(token, nativeCurrency)
// Backend doesn't always return latest price point for every duration.
// Thus we need to manually determine latest price point available, and
// append it to the prices list for every duration.
useMemo(() => {
let latestPricePoint: PricePoint = { value: 0, timestamp: 0 }
let latestPricePointTimePeriod: TimePeriod
Object.keys(prices).forEach((key) => {
const latestPricePointForTimePeriod = prices[key as unknown as TimePeriod]?.slice(-1)[0]
if (latestPricePointForTimePeriod && latestPricePointForTimePeriod.timestamp > latestPricePoint.timestamp) {
latestPricePoint = latestPricePointForTimePeriod
latestPricePointTimePeriod = key as unknown as TimePeriod
}
})
Object.keys(prices).forEach((key) => {
if ((key as unknown as TimePeriod) !== latestPricePointTimePeriod) {
prices[key as unknown as TimePeriod]?.push(latestPricePoint)
}
})
}, [prices])
return ( return (
<ChartHeader> <ChartHeader>
<TokenInfoContainer> <TokenInfoContainer>
...@@ -124,7 +104,7 @@ export default function ChartSection({ ...@@ -124,7 +104,7 @@ export default function ChartSection({
</TokenInfoContainer> </TokenInfoContainer>
<ChartContainer> <ChartContainer>
<ParentSize> <ParentSize>
{({ width }) => prices && <PriceChart prices={prices[timePeriod]} width={width} height={436} />} {({ width }) => <PriceChart prices={prices ? prices?.[timePeriod] : null} width={width} height={436} />}
</ParentSize> </ParentSize>
</ChartContainer> </ChartContainer>
</ChartHeader> </ChartHeader>
......
...@@ -7,7 +7,7 @@ import { Line } from '@visx/shape' ...@@ -7,7 +7,7 @@ import { Line } from '@visx/shape'
import AnimatedInLineChart from 'components/Charts/AnimatedInLineChart' import AnimatedInLineChart from 'components/Charts/AnimatedInLineChart'
import { filterTimeAtom } from 'components/Tokens/state' import { filterTimeAtom } from 'components/Tokens/state'
import { bisect, curveCardinal, NumberValue, scaleLinear, timeDay, timeHour, timeMinute, timeMonth } from 'd3' import { bisect, curveCardinal, NumberValue, scaleLinear, timeDay, timeHour, timeMinute, timeMonth } from 'd3'
import { PricePoint } from 'graphql/data/Token' import { PricePoint } from 'graphql/data/TokenPrice'
import { TimePeriod } from 'graphql/data/util' import { TimePeriod } from 'graphql/data/util'
import { useActiveLocale } from 'hooks/useActiveLocale' import { useActiveLocale } from 'hooks/useActiveLocale'
import { useAtom } from 'jotai' import { useAtom } from 'jotai'
...@@ -59,7 +59,7 @@ export function getDeltaArrow(delta: number | null | undefined) { ...@@ -59,7 +59,7 @@ export function getDeltaArrow(delta: number | null | undefined) {
export function formatDelta(delta: number | null | undefined) { export function formatDelta(delta: number | null | undefined) {
// Null-check not including zero // Null-check not including zero
if (delta === null || delta === undefined) { if (delta === null || delta === undefined || delta === Infinity || isNaN(delta)) {
return '-' return '-'
} }
let formattedDelta = delta.toFixed(2) + '%' let formattedDelta = delta.toFixed(2) + '%'
...@@ -133,7 +133,7 @@ const timeOptionsHeight = 44 ...@@ -133,7 +133,7 @@ const timeOptionsHeight = 44
interface PriceChartProps { interface PriceChartProps {
width: number width: number
height: number height: number
prices: PricePoint[] | undefined prices: PricePoint[] | undefined | null
} }
export function PriceChart({ width, height, prices }: PriceChartProps) { export function PriceChart({ width, height, prices }: PriceChartProps) {
...@@ -281,7 +281,15 @@ export function PriceChart({ width, height, prices }: PriceChartProps) { ...@@ -281,7 +281,15 @@ export function PriceChart({ width, height, prices }: PriceChartProps) {
<MissingPriceChart <MissingPriceChart
width={width} width={width}
height={graphHeight} height={graphHeight}
message={prices && prices.length === 0 ? <NoV3DataMessage /> : <MissingDataMessage />} message={
prices === null ? (
<Trans>Loading chart data</Trans>
) : prices?.length === 0 ? (
<Trans>This token doesn&apos;t have chart data because it hasn&apos;t been traded on Uniswap v3</Trans>
) : (
<Trans>Missing chart data</Trans>
)
}
/> />
) : ( ) : (
<svg width={width} height={graphHeight} style={{ minWidth: '100%' }}> <svg width={width} height={graphHeight} style={{ minWidth: '100%' }}>
...@@ -395,11 +403,6 @@ const StyledMissingChart = styled.svg` ...@@ -395,11 +403,6 @@ const StyledMissingChart = styled.svg`
const chartBottomPadding = 15 const chartBottomPadding = 15
const NoV3DataMessage = () => (
<Trans>This token doesn&apos;t have chart data because it hasn&apos;t been traded on Uniswap v3</Trans>
)
const MissingDataMessage = () => <Trans>Missing chart data</Trans>
function MissingPriceChart({ width, height, message }: { width: number; height: number; message: ReactNode }) { function MissingPriceChart({ width, height, message }: { width: number; height: number; message: ReactNode }) {
const theme = useTheme() const theme = useTheme()
const midPoint = height / 2 + 45 const midPoint = height / 2 + 45
......
import { Trans } from '@lingui/macro' import { Trans } from '@lingui/macro'
import { NATIVE_CHAIN_ID } from 'constants/tokens' import { NATIVE_CHAIN_ID } from 'constants/tokens'
import { SingleTokenData } from 'graphql/data/Token' import { TokenQueryData } from 'graphql/data/Token'
import { useOnClickOutside } from 'hooks/useOnClickOutside' import { useOnClickOutside } from 'hooks/useOnClickOutside'
import { useRef } from 'react' import { useRef } from 'react'
import { Twitter } from 'react-feather' import { Twitter } from 'react-feather'
...@@ -64,7 +64,7 @@ const ShareAction = styled.div` ...@@ -64,7 +64,7 @@ const ShareAction = styled.div`
` `
interface TokenInfo { interface TokenInfo {
token: NonNullable<SingleTokenData> token: NonNullable<TokenQueryData>
isNative: boolean isNative: boolean
} }
......
import graphql from 'babel-plugin-relay/macro' import graphql from 'babel-plugin-relay/macro'
import { DEFAULT_ERC20_DECIMALS } from 'constants/tokens' import { DEFAULT_ERC20_DECIMALS } from 'constants/tokens'
import { useMemo, useState } from 'react' import { useMemo } from 'react'
import { fetchQuery, useLazyLoadQuery } from 'react-relay' import { useLazyLoadQuery } from 'react-relay'
import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo' import { WrappedTokenInfo } from 'state/lists/wrappedTokenInfo'
import { Chain, TokenPriceQuery } from './__generated__/TokenPriceQuery.graphql' import { Chain } from './__generated__/TokenPriceQuery.graphql'
import { ContractInput, HistoryDuration, TokenQuery, TokenQuery$data } from './__generated__/TokenQuery.graphql' import { TokenQuery, TokenQuery$data } from './__generated__/TokenQuery.graphql'
import environment from './RelayEnvironment' import { CHAIN_NAME_TO_CHAIN_ID } from './util'
import { CHAIN_NAME_TO_CHAIN_ID, TimePeriod, toHistoryDuration } from './util'
/* /*
The difference between Token and TokenProject: The difference between Token and TokenProject:
...@@ -18,7 +17,7 @@ The difference between Token and TokenProject: ...@@ -18,7 +17,7 @@ The difference between Token and TokenProject:
TokenProjectMarket is aggregated market data (aggregated over multiple dexes and centralized exchanges) that we get from coingecko. TokenProjectMarket is aggregated market data (aggregated over multiple dexes and centralized exchanges) that we get from coingecko.
*/ */
const tokenQuery = graphql` const tokenQuery = graphql`
query TokenQuery($contract: ContractInput!, $duration: HistoryDuration!) { query TokenQuery($contract: ContractInput!) {
tokens(contracts: [$contract]) { tokens(contracts: [$contract]) {
id @required(action: LOG) id @required(action: LOG)
decimals decimals
...@@ -31,10 +30,6 @@ const tokenQuery = graphql` ...@@ -31,10 +30,6 @@ const tokenQuery = graphql`
value value
currency currency
} }
priceHistory(duration: $duration) {
timestamp
value
}
price { price {
value value
currency currency
...@@ -64,120 +59,17 @@ const tokenQuery = graphql` ...@@ -64,120 +59,17 @@ const tokenQuery = graphql`
} }
` `
const tokenPriceQuery = graphql` export type TokenQueryData = NonNullable<TokenQuery$data['tokens']>[number]
query TokenPriceQuery(
$contract: ContractInput!
$skip1H: Boolean!
$skip1D: Boolean!
$skip1W: Boolean!
$skip1M: Boolean!
$skip1Y: Boolean!
) {
tokens(contracts: [$contract]) {
market(currency: USD) {
priceHistory1H: priceHistory(duration: HOUR) @skip(if: $skip1H) {
timestamp
value
}
priceHistory1D: priceHistory(duration: DAY) @skip(if: $skip1D) {
timestamp
value
}
priceHistory1W: priceHistory(duration: WEEK) @skip(if: $skip1W) {
timestamp
value
}
priceHistory1M: priceHistory(duration: MONTH) @skip(if: $skip1M) {
timestamp
value
}
priceHistory1Y: priceHistory(duration: YEAR) @skip(if: $skip1Y) {
timestamp
value
}
}
}
}
`
export type PricePoint = { value: number; timestamp: number }
export function filterPrices(prices: NonNullable<NonNullable<SingleTokenData>['market']>['priceHistory'] | undefined) {
return prices?.filter((p): p is PricePoint => Boolean(p && p.value))
}
export type PriceDurations = Record<TimePeriod, PricePoint[] | undefined>
function fetchAllPriceDurations(contract: ContractInput, originalDuration: HistoryDuration) {
return fetchQuery<TokenPriceQuery>(environment, tokenPriceQuery, {
contract,
skip1H: originalDuration === 'HOUR',
skip1D: originalDuration === 'DAY',
skip1W: originalDuration === 'WEEK',
skip1M: originalDuration === 'MONTH',
skip1Y: originalDuration === 'YEAR',
})
}
export type SingleTokenData = NonNullable<TokenQuery$data['tokens']>[number]
export function useTokenQuery(
address: string,
chain: Chain,
timePeriod: TimePeriod
): [SingleTokenData | undefined, PriceDurations] {
const [prices, setPrices] = useState<PriceDurations>({
[TimePeriod.HOUR]: undefined,
[TimePeriod.DAY]: undefined,
[TimePeriod.WEEK]: undefined,
[TimePeriod.MONTH]: undefined,
[TimePeriod.YEAR]: undefined,
})
const contract = useMemo(() => {
return { address: address.toLowerCase(), chain }
}, [address, chain])
// eslint-disable-next-line react-hooks/exhaustive-deps
const originalTimePeriod = useMemo(() => timePeriod, [contract])
const updatePrices = (response: TokenPriceQuery['response']) => {
const priceData = response.tokens?.[0]?.market
if (priceData) {
setPrices((current) => {
return {
[TimePeriod.HOUR]: filterPrices(priceData.priceHistory1H) ?? current[TimePeriod.HOUR],
[TimePeriod.DAY]: filterPrices(priceData.priceHistory1D) ?? current[TimePeriod.DAY],
[TimePeriod.WEEK]: filterPrices(priceData.priceHistory1W) ?? current[TimePeriod.WEEK],
[TimePeriod.MONTH]: filterPrices(priceData.priceHistory1M) ?? current[TimePeriod.MONTH],
[TimePeriod.YEAR]: filterPrices(priceData.priceHistory1Y) ?? current[TimePeriod.YEAR],
}
})
}
}
// Fetch prices & token info in tandem so we can render faster
useMemo(
() => fetchAllPriceDurations(contract, toHistoryDuration(originalTimePeriod)).subscribe({ next: updatePrices }),
[contract, originalTimePeriod]
)
const token = useLazyLoadQuery<TokenQuery>(tokenQuery, {
contract,
duration: toHistoryDuration(originalTimePeriod),
}).tokens?.[0]
useMemo(
() =>
setPrices((current) => {
current[originalTimePeriod] = filterPrices(token?.market?.priceHistory)
return current
}),
[originalTimePeriod, token?.market?.priceHistory]
)
return [token, prices] export function useTokenQuery(address: string, chain: Chain): TokenQueryData | undefined {
const contract = useMemo(() => ({ address: address.toLowerCase(), chain }), [address, chain])
const token = useLazyLoadQuery<TokenQuery>(tokenQuery, { contract }).tokens?.[0]
return token
} }
// TODO: Return a QueryToken from useTokenQuery instead of SingleTokenData to make it more usable in Currency-centric interfaces. // TODO: Return a QueryToken from useTokenQuery instead of TokenQueryData to make it more usable in Currency-centric interfaces.
export class QueryToken extends WrappedTokenInfo { export class QueryToken extends WrappedTokenInfo {
constructor(data: NonNullable<SingleTokenData>) { constructor(data: NonNullable<TokenQueryData>) {
super({ super({
chainId: CHAIN_NAME_TO_CHAIN_ID[data.chain], chainId: CHAIN_NAME_TO_CHAIN_ID[data.chain],
address: data.address, address: data.address,
......
import graphql from 'babel-plugin-relay/macro'
import { useEffect, useMemo, useState } from 'react'
import { fetchQuery } from 'react-relay'
import { Chain, TokenPriceQuery } from './__generated__/TokenPriceQuery.graphql'
import environment from './RelayEnvironment'
import { TimePeriod } from './util'
const tokenPriceQuery = graphql`
query TokenPriceQuery($contract: ContractInput!) {
tokens(contracts: [$contract]) {
market(currency: USD) {
priceHistory1H: priceHistory(duration: HOUR) {
timestamp
value
}
priceHistory1D: priceHistory(duration: DAY) {
timestamp
value
}
priceHistory1W: priceHistory(duration: WEEK) {
timestamp
value
}
priceHistory1M: priceHistory(duration: MONTH) {
timestamp
value
}
priceHistory1Y: priceHistory(duration: YEAR) {
timestamp
value
}
}
}
}
`
export type PricePoint = { timestamp: number; value: number }
export type PriceDurations = Partial<Record<TimePeriod, PricePoint[]>>
export function isPricePoint(p: { timestamp: number; value: number | null } | null): p is PricePoint {
return Boolean(p && p.value)
}
export function useTokenPriceQuery(address: string, chain: Chain): PriceDurations | undefined {
const contract = useMemo(() => ({ address: address.toLowerCase(), chain }), [address, chain])
const [prices, setPrices] = useState<PriceDurations>()
useEffect(() => {
const subscription = fetchQuery<TokenPriceQuery>(environment, tokenPriceQuery, { contract }).subscribe({
next: (response: TokenPriceQuery['response']) => {
const priceData = response.tokens?.[0]?.market
const prices = {
[TimePeriod.HOUR]: priceData?.priceHistory1H?.filter(isPricePoint),
[TimePeriod.DAY]: priceData?.priceHistory1D?.filter(isPricePoint),
[TimePeriod.WEEK]: priceData?.priceHistory1W?.filter(isPricePoint),
[TimePeriod.MONTH]: priceData?.priceHistory1M?.filter(isPricePoint),
[TimePeriod.YEAR]: priceData?.priceHistory1Y?.filter(isPricePoint),
}
// Ensure the latest price available is available for every TimePeriod.
const latests = Object.values(prices)
.map((prices) => prices?.slice(-1)?.[0] ?? null)
.filter(isPricePoint)
if (latests.length) {
const latest = latests.reduce((latest, pricePoint) =>
latest.timestamp > pricePoint.timestamp ? latest : pricePoint
)
Object.values(prices)
.filter((prices) => prices && prices.slice(-1)[0] !== latest)
.forEach((prices) => prices?.push(latest))
}
setPrices(prices)
},
})
return () => {
setPrices(undefined)
subscription.unsubscribe()
}
}, [contract])
return prices
}
...@@ -12,7 +12,7 @@ import { fetchQuery, useLazyLoadQuery, useRelayEnvironment } from 'react-relay' ...@@ -12,7 +12,7 @@ import { fetchQuery, useLazyLoadQuery, useRelayEnvironment } from 'react-relay'
import type { Chain, TopTokens100Query } from './__generated__/TopTokens100Query.graphql' import type { Chain, TopTokens100Query } from './__generated__/TopTokens100Query.graphql'
import { TopTokensSparklineQuery } from './__generated__/TopTokensSparklineQuery.graphql' import { TopTokensSparklineQuery } from './__generated__/TopTokensSparklineQuery.graphql'
import { filterPrices, PricePoint } from './Token' import { isPricePoint, PricePoint } from './TokenPrice'
import { CHAIN_NAME_TO_CHAIN_ID, toHistoryDuration, unwrapToken } from './util' import { CHAIN_NAME_TO_CHAIN_ID, toHistoryDuration, unwrapToken } from './util'
const topTokens100Query = graphql` const topTokens100Query = graphql`
...@@ -137,7 +137,8 @@ export function useTopTokens(chain: Chain): UseTopTokensReturnValue { ...@@ -137,7 +137,8 @@ export function useTopTokens(chain: Chain): UseTopTokensReturnValue {
next(data) { next(data) {
const map: SparklineMap = {} const map: SparklineMap = {}
data.topTokens?.forEach( data.topTokens?.forEach(
(current) => current?.address && (map[current.address] = filterPrices(current?.market?.priceHistory)) (current) =>
current?.address && (map[current.address] = current?.market?.priceHistory?.filter(isPricePoint))
) )
setSparklines(map) setSparklines(map)
}, },
......
...@@ -2,7 +2,7 @@ import { SupportedChainId } from 'constants/chains' ...@@ -2,7 +2,7 @@ import { SupportedChainId } from 'constants/chains'
import { ZERO_ADDRESS } from 'constants/misc' import { ZERO_ADDRESS } from 'constants/misc'
import { NATIVE_CHAIN_ID, nativeOnChain, WRAPPED_NATIVE_CURRENCY } from 'constants/tokens' import { NATIVE_CHAIN_ID, nativeOnChain, WRAPPED_NATIVE_CURRENCY } from 'constants/tokens'
import { Chain, HistoryDuration } from './__generated__/TokenQuery.graphql' import { Chain, HistoryDuration } from './__generated__/TopTokens100Query.graphql'
export enum TimePeriod { export enum TimePeriod {
HOUR, HOUR,
......
import { Currency, Token } from '@uniswap/sdk-core' import { Currency, Token } from '@uniswap/sdk-core'
import { PageName } from 'analytics/constants' import { PageName } from 'analytics/constants'
import { Trace } from 'analytics/Trace' import { Trace } from 'analytics/Trace'
import { filterTimeAtom } from 'components/Tokens/state'
import { AboutSection } from 'components/Tokens/TokenDetails/About' import { AboutSection } from 'components/Tokens/TokenDetails/About'
import AddressSection from 'components/Tokens/TokenDetails/AddressSection' import AddressSection from 'components/Tokens/TokenDetails/AddressSection'
import BalanceSummary from 'components/Tokens/TokenDetails/BalanceSummary' import BalanceSummary from 'components/Tokens/TokenDetails/BalanceSummary'
...@@ -22,10 +21,10 @@ import { DEFAULT_ERC20_DECIMALS, NATIVE_CHAIN_ID, nativeOnChain } from 'constant ...@@ -22,10 +21,10 @@ import { DEFAULT_ERC20_DECIMALS, NATIVE_CHAIN_ID, nativeOnChain } from 'constant
import { checkWarning } from 'constants/tokenSafety' import { checkWarning } from 'constants/tokenSafety'
import { Chain } from 'graphql/data/__generated__/TokenQuery.graphql' import { Chain } from 'graphql/data/__generated__/TokenQuery.graphql'
import { QueryToken, useTokenQuery } from 'graphql/data/Token' import { QueryToken, useTokenQuery } from 'graphql/data/Token'
import { useTokenPriceQuery } from 'graphql/data/TokenPrice'
import { CHAIN_NAME_TO_CHAIN_ID, validateUrlChainParam } from 'graphql/data/util' import { CHAIN_NAME_TO_CHAIN_ID, validateUrlChainParam } from 'graphql/data/util'
import { useIsUserAddedTokenOnChain } from 'hooks/Tokens' import { useIsUserAddedTokenOnChain } from 'hooks/Tokens'
import { useOnGlobalChainSwitch } from 'hooks/useGlobalChainSwitch' import { useOnGlobalChainSwitch } from 'hooks/useGlobalChainSwitch'
import { useAtomValue } from 'jotai/utils'
import { useCallback, useMemo, useState, useTransition } from 'react' import { useCallback, useMemo, useState, useTransition } from 'react'
import { ArrowLeft } from 'react-feather' import { ArrowLeft } from 'react-feather'
import { useNavigate, useParams } from 'react-router-dom' import { useNavigate, useParams } from 'react-router-dom'
...@@ -35,13 +34,9 @@ export default function TokenDetails() { ...@@ -35,13 +34,9 @@ export default function TokenDetails() {
const chain = validateUrlChainParam(chainName) const chain = validateUrlChainParam(chainName)
const pageChainId = CHAIN_NAME_TO_CHAIN_ID[chain] const pageChainId = CHAIN_NAME_TO_CHAIN_ID[chain]
const nativeCurrency = nativeOnChain(pageChainId) const nativeCurrency = nativeOnChain(pageChainId)
const timePeriod = useAtomValue(filterTimeAtom)
const isNative = tokenAddress === NATIVE_CHAIN_ID const isNative = tokenAddress === NATIVE_CHAIN_ID
const [tokenQueryData, prices] = useTokenQuery( const tokenQueryData = useTokenQuery(isNative ? nativeCurrency.wrapped.address : tokenAddress ?? '', chain)
isNative ? nativeCurrency.wrapped.address : tokenAddress ?? '', const prices = useTokenPriceQuery(isNative ? nativeCurrency.wrapped.address : tokenAddress ?? '', chain)
chain,
timePeriod
)
const token = useMemo(() => { const token = useMemo(() => {
if (!tokenAddress) return undefined if (!tokenAddress) return undefined
if (isNative) return nativeCurrency if (isNative) return nativeCurrency
......
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