diff --git a/src/components/Tokens/TokenDetails/ChartSection.tsx b/src/components/Tokens/TokenDetails/ChartSection.tsx
index 2e1240f00..c424335e9 100644
--- a/src/components/Tokens/TokenDetails/ChartSection.tsx
+++ b/src/components/Tokens/TokenDetails/ChartSection.tsx
@@ -9,16 +9,72 @@ import { startTransition, Suspense, useMemo } from 'react'
import { PriceChart } from './PriceChart'
import TimePeriodSelector from './TimeSelector'
+import { ti } from 'make-plural'
-function usePriceHistory(tokenPriceData: TokenPriceQuery): PricePoint[] | undefined {
+function fillMissingTimestamps(priceHistory: any, interval: number, totalTime: number) {
+ if (!Array.isArray(priceHistory) || priceHistory.length === 0) {
+ return priceHistory; // Return the original array if invalid or empty
+ }
+
+ // Sort the array by timestamp to ensure proper filling
+ priceHistory.sort((a, b) => a.timestamp - b.timestamp);
+ const currentTimestamp = Date.now() / 1000
+ const filledHistory = [];
+
+ for (let i = 0; i < priceHistory.length - 1; i++) {
+ const current = priceHistory[i];
+ const next = priceHistory[i + 1];
+
+ // Add the current object to the filled array
+ if(next.timestamp + totalTime >= currentTimestamp) {
+ if(current.timestamp + totalTime >= currentTimestamp) filledHistory.push(current);
+
+ // Fill missing timestamps
+ let timestamp = current.timestamp + interval;
+ while (timestamp < next.timestamp) {
+ if(timestamp + totalTime >= currentTimestamp)
+ filledHistory.push({
+ ...current, // Copy previous values
+ timestamp, // Update timestamp
+ });
+ timestamp += interval;
+ }
+ }
+ }
+
+ // Add the last object to the filled array
+ filledHistory.push(priceHistory[priceHistory.length - 1]);
+ return filledHistory;
+}
+
+function getTimeInterval(timePeriod:any) {
+ switch(timePeriod) {
+ case 0:
+ return [300, 3600];
+ case 1:
+ return [600, 86400];
+ case 2:
+ return [3600, 604800];
+ case 3:
+ return [3600, 2592000];
+ case 4:
+ return [86400, 31536000];
+ }
+ return [86400, 0];
+}
+
+function usePriceHistory(tokenPriceData: TokenPriceQuery, timePeriod: any): PricePoint[] | undefined {
+
+ const [timeInterval, totalTime] = getTimeInterval(timePeriod);
// Appends the current price to the end of the priceHistory array
const priceHistory = useMemo(() => {
const market = tokenPriceData.token?.market
const priceHistory = market?.priceHistory?.filter(isPricePoint)
+ // const priceHistory = market?.priceHistory?.filter(isPricePoint)
const currentPrice = market?.price?.value
if (Array.isArray(priceHistory) && currentPrice !== undefined) {
const timestamp = Date.now() / 1000
- return [...priceHistory, { timestamp, value: currentPrice }]
+ return fillMissingTimestamps([...priceHistory, { timestamp, value: currentPrice }], timeInterval, totalTime)
}
return priceHistory
}, [tokenPriceData])
@@ -55,7 +111,7 @@ function Chart({
}) {
// Initializes time period to global & maintain separate time period for subsequent changes
const timePeriod = useAtomValue(pageTimePeriodAtom)
- const prices = usePriceHistory(tokenPriceQuery)
+ const prices = usePriceHistory(tokenPriceQuery, timePeriod)
return (
@@ -70,4 +126,4 @@ function Chart({
/>
)
-}
+}
\ No newline at end of file
diff --git a/src/pages/TokenDetails/index.tsx b/src/pages/TokenDetails/index.tsx
index 159ec26ed..18b165399 100644
--- a/src/pages/TokenDetails/index.tsx
+++ b/src/pages/TokenDetails/index.tsx
@@ -15,7 +15,7 @@ import { Chain, TokenQuery, Currency, TokenQueryData } from 'graphql/data/Token'
import { TokenPriceQuery } from 'graphql/data/TokenPrice'
const GetTokenInfo = gql`
-query GetTokenInfo($tokenAddress: String!) {
+query GetTokenInfo($tokenAddress: String!, $days: Int, $hours: Int) {
bundles(first: 10) {
ethPriceUSD
}
@@ -29,7 +29,7 @@ query GetTokenInfo($tokenAddress: String!) {
derivedETH
# Get daily data for more detailed metrics
- tokenDayData(first: 365, orderBy: date, orderDirection: asc) {
+ tokenDayData(first: $days, orderBy: date, orderDirection: desc) {
id
date
priceUSD # The price of the token in USD for the day
@@ -37,6 +37,14 @@ query GetTokenInfo($tokenAddress: String!) {
volumeUSD
}
+ tokenHourData(first: $hours, orderBy: periodStartUnix, orderDirection: desc) {
+ id
+ periodStartUnix
+ priceUSD # The price of the token in USD for the day
+ totalValueLockedUSD
+ volumeUSD
+ }
+
# Get all pools involving this token for liquidity details
whitelistPools {
id
@@ -57,11 +65,29 @@ query GetTokenInfo($tokenAddress: String!) {
export const pageTimePeriodAtom = atomWithStorage('tokenDetailsTimePeriod', TimePeriod.DAY)
+function getQueryParams(timePeriod:any) {
+ switch(timePeriod) {
+ case 0:
+ return [2, 2];
+ case 1:
+ return [2, 24];
+ case 2:
+ return [2, 168];
+ case 3:
+ return [30, 2];
+ case 4:
+ return [365, 2];
+ }
+ return [2, 2];
+}
+
+
export default function TokenDetailsPage() {
const { tokenAddress, chainName } = useParams<{ tokenAddress: string; chainName?: string }>()
const chain = validateUrlChainParam(chainName)
const isNative = tokenAddress === NATIVE_CHAIN_ID
const [timePeriod, setTimePeriod] = useAtom(pageTimePeriodAtom)
+ const [totalDays, totalHours] = getQueryParams(timePeriod);
const [address, duration] = useMemo(
/* tokenAddress will always be defined in the path for for this page to render, but useParams will always
return optional arguments; nullish coalescing operator is present here to appease typechecker */
@@ -82,11 +108,12 @@ export default function TokenDetailsPage() {
duration,
},
})
-
const { data: luxData, loading: luxLoading } = useQuery(GetTokenInfo, {
client: luxClient,
variables: {
tokenAddress: address,
+ days: totalDays,
+ hours: totalHours,
},
})
if (luxLoading) {
@@ -152,28 +179,29 @@ const transformedTokenDetail: TokenQuery = tokenPriceQuery??{
};
const ethPriceUSD = luxData?.bundles[0]?.ethPriceUSD;
const ethPrice = luxData?.token?.derivedETH;
+const tokenDayData = luxData?.token?.tokenDayData.filter((data: any) => parseFloat(data.priceUSD) !== 0).map((data: any) => ({
+ id: `VGltZXN0YW1wZWRBbW91bnQ6MV8x${data.date}_VVNE`, // Encoded version of the timestamped amount
+ timestamp: data.date,
+ value: parseFloat(data.priceUSD),
+}))
+const tokenHourData = luxData?.token?.tokenHourData.filter((data: any) => parseFloat(data.priceUSD) !== 0).map((data: any) => ({
+ id: `VGltZXN0YW1wZWRBbW91bnQ6MV8x${data.periodStartUnix}_VVNE`, // Encoded version of the timestamped amount
+ timestamp: data.periodStartUnix,
+ value: parseFloat(data.priceUSD),
+}))
const transformedTokenPriceHistory:TokenPriceQuery = {
token: {
- __typename: "Token",
id: "VG9rZW46RVRIRVJFVU1fMHhhMGI4Njk5MWM2MjE4YjM2YzFkMTlkNGEyZTllYjBjZTM2MDZlYjQ4", // Encoded version of the token ID
address: luxData?.token?.id,
chain: Chain.Lux,
market: {
- __typename: "TokenMarket",
id: "VG9rZW5NYXJrZXQ6RVRIRVJFVU1fMHhhMGI4Njk5MWM2MjE4YjM2YzFkMTlkNGEyZTllYjBjZTM2MDZlYjQ4X1VTRA==", // Encoded ID for the market
price: {
- __typename: "Amount",
id: "QW1vdW50OjFfVVNE", // Encoded amount ID
value: parseFloat(ethPriceUSD) * parseFloat(ethPrice),
},
- priceHistory: luxData?.token?.tokenDayData.filter((data: any) => parseFloat(data.priceUSD) !== 0)
- .map((data: any) => ({
- __typename: "TimestampedAmount",
- id: `VGltZXN0YW1wZWRBbW91bnQ6MV8x${data.date}_VVNE`, // Encoded version of the timestamped amount
- timestamp: data.date,
- value: parseFloat(data.priceUSD),
- })),
+ priceHistory: timePeriod < 3 ? tokenHourData : tokenDayData,
},
},
};
@@ -200,4 +228,4 @@ const renderTokenDetail = (tokenAddress: any, chain: any, tokenQuery: any) => (
}
if (!tokenQuery) return
return renderTokenDetail(tokenAddress, chain, tokenQuery)
-}
+}
\ No newline at end of file