feat: [info] Migrate Historical Pool Data Queries (#7310)
* correctly query pool data for t24, t48, and tWeek timestamps * add comments * sanitize pool data and update tests * correct test data * add todo * lint * remove logs * 1st class var support courtesy of carter * remove logging and adds comments
This commit is contained in:
parent
df6c44d2c4
commit
622c72d4a8
@ -23,6 +23,18 @@ import { ARBITRUM_LIST, AVALANCHE_LIST, BASE_LIST, CELO_LIST, OPTIMISM_LIST, PLA
|
|||||||
|
|
||||||
export const AVERAGE_L1_BLOCK_TIME = ms(`12s`)
|
export const AVERAGE_L1_BLOCK_TIME = ms(`12s`)
|
||||||
|
|
||||||
|
// The block number at which v3 was deployed on each chain, separate from the UNIVERSAL_ROUTER_CREATION_BLOCK
|
||||||
|
export const START_BLOCKS: { [key: number]: number } = {
|
||||||
|
[ChainId.MAINNET]: 14292820,
|
||||||
|
[ChainId.POLYGON]: 25459720,
|
||||||
|
[ChainId.ARBITRUM_ONE]: 175,
|
||||||
|
[ChainId.OPTIMISM]: 10028767,
|
||||||
|
[ChainId.CELO]: 13916355,
|
||||||
|
[ChainId.BNB]: 26324014,
|
||||||
|
[ChainId.AVALANCHE]: 31422450,
|
||||||
|
[ChainId.BASE]: 1371680,
|
||||||
|
}
|
||||||
|
|
||||||
export enum NetworkType {
|
export enum NetworkType {
|
||||||
L1,
|
L1,
|
||||||
L2,
|
L2,
|
||||||
|
@ -2,12 +2,20 @@ import { ChainId } from '@uniswap/sdk-core'
|
|||||||
import gql from 'graphql-tag'
|
import gql from 'graphql-tag'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
import { usePoolDataQuery } from './__generated__/types-and-hooks'
|
import { Pool, Token, usePoolDataQuery } from './__generated__/types-and-hooks'
|
||||||
import { chainToApolloClient } from './apollo'
|
import { chainToApolloClient } from './apollo'
|
||||||
|
import { useBlocksFromTimestamps } from './useBlocksFromTimestamps'
|
||||||
|
import { get2DayChange, useDeltaTimestamps } from './utils'
|
||||||
|
|
||||||
gql`
|
gql`
|
||||||
query PoolData($poolId: [ID!]) {
|
query PoolData($poolId: [ID!], $block: Block_height = null) {
|
||||||
data: pools(where: { id_in: $poolId }, orderBy: totalValueLockedUSD, orderDirection: desc, subgraphError: allow) {
|
pools(
|
||||||
|
where: { id_in: $poolId }
|
||||||
|
block: $block
|
||||||
|
orderBy: totalValueLockedUSD
|
||||||
|
orderDirection: desc
|
||||||
|
subgraphError: allow
|
||||||
|
) {
|
||||||
id
|
id
|
||||||
feeTier
|
feeTier
|
||||||
liquidity
|
liquidity
|
||||||
@ -43,14 +51,187 @@ gql`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
export function usePoolData(poolAddress: string, chainId?: ChainId) {
|
interface PoolData {
|
||||||
|
// basic token info
|
||||||
|
address: string
|
||||||
|
feeTier: number
|
||||||
|
|
||||||
|
token0: Token
|
||||||
|
|
||||||
|
token1: Token
|
||||||
|
|
||||||
|
// for tick math
|
||||||
|
liquidity: number
|
||||||
|
sqrtPrice: number
|
||||||
|
tick: number
|
||||||
|
|
||||||
|
// volume
|
||||||
|
volumeUSD: number
|
||||||
|
volumeUSDChange: number
|
||||||
|
volumeUSDWeek: number
|
||||||
|
|
||||||
|
// liquidity
|
||||||
|
tvlUSD: number
|
||||||
|
tvlUSDChange: number
|
||||||
|
|
||||||
|
// prices
|
||||||
|
token0Price: number
|
||||||
|
token1Price: number
|
||||||
|
|
||||||
|
// token amounts
|
||||||
|
tvlToken0: number
|
||||||
|
tvlToken1: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export function usePoolData(
|
||||||
|
poolAddress: string,
|
||||||
|
chainId?: ChainId
|
||||||
|
): {
|
||||||
|
loading: boolean
|
||||||
|
error: boolean
|
||||||
|
data?: PoolData
|
||||||
|
} {
|
||||||
const poolId = [poolAddress]
|
const poolId = [poolAddress]
|
||||||
const apolloClient = chainToApolloClient[chainId || ChainId.MAINNET]
|
const apolloClient = chainToApolloClient[chainId || ChainId.MAINNET]
|
||||||
const { data, loading } = usePoolDataQuery({ variables: { poolId }, client: apolloClient })
|
|
||||||
|
// get blocks from historic timestamps
|
||||||
|
const [t24, t48, tWeek] = useDeltaTimestamps()
|
||||||
|
const { blocks, error: blockError } = useBlocksFromTimestamps([t24, t48, tWeek], chainId || ChainId.MAINNET)
|
||||||
|
const [block24, block48, blockWeek] = blocks ?? []
|
||||||
|
|
||||||
|
const { loading, error, data } = usePoolDataQuery({
|
||||||
|
variables: { poolId },
|
||||||
|
client: apolloClient,
|
||||||
|
fetchPolicy: 'no-cache',
|
||||||
|
})
|
||||||
|
|
||||||
|
const {
|
||||||
|
loading: loading24,
|
||||||
|
error: error24,
|
||||||
|
data: data24,
|
||||||
|
} = usePoolDataQuery({
|
||||||
|
variables: { poolId, block: { number: parseFloat(block24?.number) } },
|
||||||
|
client: apolloClient,
|
||||||
|
fetchPolicy: 'no-cache',
|
||||||
|
})
|
||||||
|
const {
|
||||||
|
loading: loading48,
|
||||||
|
error: error48,
|
||||||
|
data: data48,
|
||||||
|
} = usePoolDataQuery({
|
||||||
|
variables: { poolId, block: { number: parseFloat(block48?.number) } },
|
||||||
|
client: apolloClient,
|
||||||
|
fetchPolicy: 'no-cache',
|
||||||
|
})
|
||||||
|
const {
|
||||||
|
loading: loadingWeek,
|
||||||
|
error: errorWeek,
|
||||||
|
data: dataWeek,
|
||||||
|
} = usePoolDataQuery({
|
||||||
|
variables: { poolId, block: { number: parseFloat(blockWeek?.number) } },
|
||||||
|
client: apolloClient,
|
||||||
|
fetchPolicy: 'no-cache',
|
||||||
|
})
|
||||||
|
|
||||||
return useMemo(() => {
|
return useMemo(() => {
|
||||||
return {
|
const anyError = Boolean(error || error24 || error48 || blockError || errorWeek)
|
||||||
data: data?.data[0],
|
const anyLoading = Boolean(loading || loading24 || loading48 || loadingWeek)
|
||||||
loading,
|
|
||||||
|
// return early if not all data yet
|
||||||
|
if (anyError || anyLoading) {
|
||||||
|
return {
|
||||||
|
loading: anyLoading,
|
||||||
|
error: anyError,
|
||||||
|
data: undefined,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [data, loading])
|
|
||||||
|
// format data and calculate daily changes
|
||||||
|
const current: Pool | undefined = data?.pools[0] as Pool
|
||||||
|
const oneDay: Pool | undefined = data24?.pools[0] as Pool
|
||||||
|
const twoDay: Pool | undefined = data48?.pools[0] as Pool
|
||||||
|
const week: Pool | undefined = dataWeek?.pools[0] as Pool
|
||||||
|
|
||||||
|
const ethPriceUSD = data?.bundles?.[0]?.ethPriceUSD ? parseFloat(data?.bundles?.[0]?.ethPriceUSD) : 0
|
||||||
|
|
||||||
|
const [volumeUSD, volumeUSDChange] =
|
||||||
|
current && oneDay && twoDay
|
||||||
|
? get2DayChange(current.volumeUSD, oneDay.volumeUSD, twoDay.volumeUSD)
|
||||||
|
: current
|
||||||
|
? [parseFloat(current.volumeUSD), 0]
|
||||||
|
: [0, 0]
|
||||||
|
|
||||||
|
const volumeUSDWeek =
|
||||||
|
current && week
|
||||||
|
? parseFloat(current.volumeUSD) - parseFloat(week.volumeUSD)
|
||||||
|
: current
|
||||||
|
? parseFloat(current.volumeUSD)
|
||||||
|
: 0
|
||||||
|
|
||||||
|
// Hotifx: Subtract fees from TVL to correct data while subgraph is fixed.
|
||||||
|
/**
|
||||||
|
* Note: see issue desribed here https://github.com/Uniswap/v3-subgraph/issues/74
|
||||||
|
* During subgraph deploy switch this month we lost logic to fix this accounting.
|
||||||
|
* Grafted sync pending fix now.
|
||||||
|
* Verified that this hotfix is still required as of 2023-09-13
|
||||||
|
* TODO(DAT-139): Diagnose and address subgraph issue that requires this hotfix
|
||||||
|
*/
|
||||||
|
const feePercent = current ? parseFloat(current.feeTier) / 10000 / 100 : 0
|
||||||
|
const tvlAdjust0 = current?.volumeToken0 ? (parseFloat(current.volumeToken0) * feePercent) / 2 : 0
|
||||||
|
const tvlAdjust1 = current?.volumeToken1 ? (parseFloat(current.volumeToken1) * feePercent) / 2 : 0
|
||||||
|
const tvlToken0 = current ? parseFloat(current.totalValueLockedToken0) - tvlAdjust0 : 0
|
||||||
|
const tvlToken1 = current ? parseFloat(current.totalValueLockedToken1) - tvlAdjust1 : 0
|
||||||
|
let tvlUSD = current ? parseFloat(current.totalValueLockedUSD) : 0
|
||||||
|
|
||||||
|
const tvlUSDChange =
|
||||||
|
current && oneDay
|
||||||
|
? ((parseFloat(current.totalValueLockedUSD) - parseFloat(oneDay.totalValueLockedUSD)) /
|
||||||
|
parseFloat(oneDay.totalValueLockedUSD === '0' ? '1' : oneDay.totalValueLockedUSD)) *
|
||||||
|
100
|
||||||
|
: 0
|
||||||
|
|
||||||
|
// Part of TVL fix
|
||||||
|
const tvlUpdated = current
|
||||||
|
? tvlToken0 * parseFloat(current.token0.derivedETH) * ethPriceUSD +
|
||||||
|
tvlToken1 * parseFloat(current.token1.derivedETH) * ethPriceUSD
|
||||||
|
: undefined
|
||||||
|
if (tvlUpdated) {
|
||||||
|
tvlUSD = tvlUpdated
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: current
|
||||||
|
? {
|
||||||
|
...current,
|
||||||
|
address: poolAddress,
|
||||||
|
volumeUSD,
|
||||||
|
volumeUSDChange,
|
||||||
|
volumeUSDWeek,
|
||||||
|
tvlUSD,
|
||||||
|
tvlUSDChange,
|
||||||
|
tvlToken0,
|
||||||
|
tvlToken1,
|
||||||
|
tick: parseFloat(current.tick),
|
||||||
|
}
|
||||||
|
: undefined,
|
||||||
|
error: anyError,
|
||||||
|
loading: anyLoading,
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
blockError,
|
||||||
|
data?.bundles,
|
||||||
|
data?.pools,
|
||||||
|
data24?.pools,
|
||||||
|
data48?.pools,
|
||||||
|
dataWeek?.pools,
|
||||||
|
error,
|
||||||
|
error24,
|
||||||
|
error48,
|
||||||
|
errorWeek,
|
||||||
|
loading,
|
||||||
|
loading24,
|
||||||
|
loading48,
|
||||||
|
loadingWeek,
|
||||||
|
poolAddress,
|
||||||
|
])
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,18 @@ const CHAIN_SUBGRAPH_URL: Record<number, string> = {
|
|||||||
[ChainId.CELO]: 'https://api.thegraph.com/subgraphs/name/jesse-sawa/uniswap-celo?source=uniswap',
|
[ChainId.CELO]: 'https://api.thegraph.com/subgraphs/name/jesse-sawa/uniswap-celo?source=uniswap',
|
||||||
[ChainId.BNB]: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-bsc?source=uniswap',
|
[ChainId.BNB]: 'https://api.thegraph.com/subgraphs/name/ianlapham/uniswap-v3-bsc?source=uniswap',
|
||||||
[ChainId.AVALANCHE]: 'https://api.thegraph.com/subgraphs/name/lynnshaoyu/uniswap-v3-avax?source=uniswap',
|
[ChainId.AVALANCHE]: 'https://api.thegraph.com/subgraphs/name/lynnshaoyu/uniswap-v3-avax?source=uniswap',
|
||||||
|
[ChainId.BASE]: 'https://api.studio.thegraph.com/query/48211/uniswap-v3-base/version/latest',
|
||||||
|
}
|
||||||
|
|
||||||
|
const CHAIN_BLOCK_SUBGRAPH_URL: Record<number, string> = {
|
||||||
|
[ChainId.MAINNET]: 'https://api.thegraph.com/subgraphs/name/blocklytics/ethereum-blocks?source=uniswap',
|
||||||
|
[ChainId.ARBITRUM_ONE]: 'https://api.thegraph.com/subgraphs/name/ianlapham/arbitrum-one-blocks?source=uniswap',
|
||||||
|
[ChainId.OPTIMISM]: 'https://api.thegraph.com/subgraphs/name/ianlapham/uni-testing-subgraph?source=uniswap',
|
||||||
|
[ChainId.POLYGON]: 'https://api.thegraph.com/subgraphs/name/ianlapham/polygon-blocks?source=uniswap',
|
||||||
|
[ChainId.CELO]: 'https://api.thegraph.com/subgraphs/name/jesse-sawa/celo-blocks?source=uniswap',
|
||||||
|
[ChainId.BNB]: 'https://api.thegraph.com/subgraphs/name/wombat-exchange/bnb-chain-block?source=uniswap',
|
||||||
|
[ChainId.AVALANCHE]: 'https://api.thegraph.com/subgraphs/name/lynnshaoyu/avalanche-blocks?source=uniswap',
|
||||||
|
[ChainId.BASE]: 'https://api.studio.thegraph.com/query/48211/base-blocks/version/latest?source=uniswap',
|
||||||
}
|
}
|
||||||
|
|
||||||
const httpLink = new HttpLink({ uri: CHAIN_SUBGRAPH_URL[ChainId.MAINNET] })
|
const httpLink = new HttpLink({ uri: CHAIN_SUBGRAPH_URL[ChainId.MAINNET] })
|
||||||
@ -63,3 +75,34 @@ export const chainToApolloClient: Record<number, ApolloClient<NormalizedCacheObj
|
|||||||
uri: CHAIN_SUBGRAPH_URL[ChainId.AVALANCHE],
|
uri: CHAIN_SUBGRAPH_URL[ChainId.AVALANCHE],
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const chainToApolloBlockClient: Record<number, ApolloClient<NormalizedCacheObject>> = {
|
||||||
|
[ChainId.MAINNET]: new ApolloClient({
|
||||||
|
uri: CHAIN_BLOCK_SUBGRAPH_URL[ChainId.MAINNET],
|
||||||
|
cache: new InMemoryCache(),
|
||||||
|
}),
|
||||||
|
[ChainId.ARBITRUM_ONE]: new ApolloClient({
|
||||||
|
uri: CHAIN_BLOCK_SUBGRAPH_URL[ChainId.ARBITRUM_ONE],
|
||||||
|
cache: new InMemoryCache(),
|
||||||
|
}),
|
||||||
|
[ChainId.OPTIMISM]: new ApolloClient({
|
||||||
|
uri: CHAIN_BLOCK_SUBGRAPH_URL[ChainId.OPTIMISM],
|
||||||
|
cache: new InMemoryCache(),
|
||||||
|
}),
|
||||||
|
[ChainId.POLYGON]: new ApolloClient({
|
||||||
|
uri: CHAIN_BLOCK_SUBGRAPH_URL[ChainId.POLYGON],
|
||||||
|
cache: new InMemoryCache(),
|
||||||
|
}),
|
||||||
|
[ChainId.CELO]: new ApolloClient({
|
||||||
|
uri: CHAIN_BLOCK_SUBGRAPH_URL[ChainId.CELO],
|
||||||
|
cache: new InMemoryCache(),
|
||||||
|
}),
|
||||||
|
[ChainId.BNB]: new ApolloClient({
|
||||||
|
uri: CHAIN_BLOCK_SUBGRAPH_URL[ChainId.BNB],
|
||||||
|
cache: new InMemoryCache(),
|
||||||
|
}),
|
||||||
|
[ChainId.AVALANCHE]: new ApolloClient({
|
||||||
|
uri: CHAIN_BLOCK_SUBGRAPH_URL[ChainId.AVALANCHE],
|
||||||
|
cache: new InMemoryCache(),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
83
src/graphql/thegraph/useBlocksFromTimestamps.ts
Normal file
83
src/graphql/thegraph/useBlocksFromTimestamps.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import { ChainId } from '@uniswap/sdk-core'
|
||||||
|
import { START_BLOCKS } from 'constants/chainInfo'
|
||||||
|
import gql from 'graphql-tag'
|
||||||
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
|
|
||||||
|
import { chainToApolloBlockClient } from './apollo'
|
||||||
|
import { splitQuery } from './utils'
|
||||||
|
|
||||||
|
const GET_BLOCKS = (timestamps: string[]) => {
|
||||||
|
let queryString = 'query blocks {'
|
||||||
|
queryString += timestamps.map((timestamp) => {
|
||||||
|
return `t${timestamp}:blocks(first: 1, orderBy: timestamp, orderDirection: desc, where: { timestamp_gt: ${timestamp}, timestamp_lt: ${
|
||||||
|
timestamp + 600
|
||||||
|
} }) {
|
||||||
|
number
|
||||||
|
}`
|
||||||
|
})
|
||||||
|
queryString += '}'
|
||||||
|
return gql(queryString)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* for a given array of timestamps, returns block entities
|
||||||
|
* @param timestamps
|
||||||
|
*/
|
||||||
|
export function useBlocksFromTimestamps(
|
||||||
|
timestamps: number[],
|
||||||
|
chainId: ChainId
|
||||||
|
): {
|
||||||
|
blocks?: {
|
||||||
|
timestamp: string
|
||||||
|
number: any
|
||||||
|
}[]
|
||||||
|
error: boolean
|
||||||
|
} {
|
||||||
|
const [blocks, setBlocks] = useState<any>()
|
||||||
|
const [error, setError] = useState(false)
|
||||||
|
|
||||||
|
const chainBlockClient = chainToApolloBlockClient[chainId]
|
||||||
|
|
||||||
|
// derive blocks based on active network
|
||||||
|
const networkBlocks = blocks?.[chainId]
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
async function fetchData() {
|
||||||
|
const results = await splitQuery(GET_BLOCKS, chainBlockClient, [], timestamps)
|
||||||
|
if (results) {
|
||||||
|
setBlocks({ ...(blocks ?? {}), [chainId]: results })
|
||||||
|
} else {
|
||||||
|
setError(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!networkBlocks && !error) {
|
||||||
|
fetchData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const blocksFormatted = useMemo(() => {
|
||||||
|
if (blocks?.[chainId]) {
|
||||||
|
const networkBlocks = blocks?.[chainId]
|
||||||
|
const formatted = []
|
||||||
|
for (const t in networkBlocks) {
|
||||||
|
if (networkBlocks[t].length > 0) {
|
||||||
|
const number = networkBlocks[t][0]['number']
|
||||||
|
const deploymentBlock = START_BLOCKS[chainId]
|
||||||
|
const adjustedNumber = number > deploymentBlock ? number : deploymentBlock
|
||||||
|
|
||||||
|
formatted.push({
|
||||||
|
timestamp: t.split('t')[1],
|
||||||
|
number: adjustedNumber,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return formatted
|
||||||
|
}
|
||||||
|
return undefined
|
||||||
|
}, [chainId, blocks])
|
||||||
|
|
||||||
|
return {
|
||||||
|
blocks: blocksFormatted,
|
||||||
|
error,
|
||||||
|
}
|
||||||
|
}
|
79
src/graphql/thegraph/utils.ts
Normal file
79
src/graphql/thegraph/utils.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { ApolloClient, NormalizedCacheObject } from '@apollo/client'
|
||||||
|
import ms from 'ms'
|
||||||
|
|
||||||
|
// TODO(WEB-2878): See if splitQuery can be replaced with proper Apollo usage
|
||||||
|
/**
|
||||||
|
* Used to get large amounts of data when larger than the Apollo limit
|
||||||
|
* Splits query into multiple queries and returns the combined data
|
||||||
|
* @param query - the query to be split
|
||||||
|
* @param localClient - Apollo client for a specific chain
|
||||||
|
* @param vars - any variables that are passed in every query
|
||||||
|
* @param values - the keys that are used as the values to map over if
|
||||||
|
* @param skipCount - amount of entities to skip per query
|
||||||
|
*/
|
||||||
|
export async function splitQuery<Type extends object>(
|
||||||
|
query: any,
|
||||||
|
client: ApolloClient<NormalizedCacheObject>,
|
||||||
|
vars: any[],
|
||||||
|
values: any[],
|
||||||
|
skipCount = 1000
|
||||||
|
) {
|
||||||
|
let fetchedData = {}
|
||||||
|
let allFound = false
|
||||||
|
let skip = 0
|
||||||
|
try {
|
||||||
|
while (!allFound) {
|
||||||
|
let end = values.length
|
||||||
|
if (skip + skipCount < values.length) {
|
||||||
|
end = skip + skipCount
|
||||||
|
}
|
||||||
|
const sliced = values.slice(skip, end)
|
||||||
|
const result = await client.query<Type>({
|
||||||
|
query: query(...vars, sliced),
|
||||||
|
fetchPolicy: 'network-only',
|
||||||
|
})
|
||||||
|
fetchedData = {
|
||||||
|
...fetchedData,
|
||||||
|
...result.data,
|
||||||
|
}
|
||||||
|
if (Object.keys(result.data).length < skipCount || skip + skipCount > values.length) {
|
||||||
|
allFound = true
|
||||||
|
} else {
|
||||||
|
skip += skipCount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fetchedData
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the 24hr, 48hr, and 1 week ago timestamps
|
||||||
|
* @returns [t24, t48, tWeek]
|
||||||
|
*/
|
||||||
|
export function useDeltaTimestamps(): [number, number, number] {
|
||||||
|
const utcCurrentTime = Date.now()
|
||||||
|
const t24 = Math.floor((utcCurrentTime - ms('1d')) / 1000)
|
||||||
|
const t48 = Math.floor((utcCurrentTime - ms('2d')) / 1000)
|
||||||
|
const tWeek = Math.floor((utcCurrentTime - ms('7d')) / 1000)
|
||||||
|
return [t24, t48, tWeek]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets the amount difference plus the % change in change itself (second order change)
|
||||||
|
* @param {*} valueNow
|
||||||
|
* @param {*} value24HoursAgo
|
||||||
|
* @param {*} value48HoursAgo
|
||||||
|
*/
|
||||||
|
export const get2DayChange = (valueNow: string, value24HoursAgo: string, value48HoursAgo: string): [number, number] => {
|
||||||
|
// get volume info for both 24 hour periods
|
||||||
|
const currentChange = parseFloat(valueNow) - parseFloat(value24HoursAgo)
|
||||||
|
const previousChange = parseFloat(value24HoursAgo) - parseFloat(value48HoursAgo)
|
||||||
|
const adjustedPercentChange = ((currentChange - previousChange) / previousChange) * 100
|
||||||
|
if (isNaN(adjustedPercentChange) || !isFinite(adjustedPercentChange)) {
|
||||||
|
return [currentChange, 0]
|
||||||
|
}
|
||||||
|
return [currentChange, adjustedPercentChange]
|
||||||
|
}
|
@ -67,6 +67,7 @@ describe('PoolDetailsPage', () => {
|
|||||||
mocked(usePoolData).mockReturnValue({
|
mocked(usePoolData).mockReturnValue({
|
||||||
data: undefined,
|
data: undefined,
|
||||||
loading: false,
|
loading: false,
|
||||||
|
error: false,
|
||||||
})
|
})
|
||||||
render(<PoolDetails />)
|
render(<PoolDetails />)
|
||||||
|
|
||||||
@ -77,7 +78,11 @@ describe('PoolDetailsPage', () => {
|
|||||||
|
|
||||||
// TODO replace with loading skeleton when designed
|
// TODO replace with loading skeleton when designed
|
||||||
it('nothing displayed while data is loading', () => {
|
it('nothing displayed while data is loading', () => {
|
||||||
mocked(usePoolData).mockReturnValue({ data: undefined, loading: true })
|
mocked(usePoolData).mockReturnValue({
|
||||||
|
data: undefined,
|
||||||
|
loading: true,
|
||||||
|
error: false,
|
||||||
|
})
|
||||||
render(<PoolDetails />)
|
render(<PoolDetails />)
|
||||||
|
|
||||||
waitFor(() => {
|
waitFor(() => {
|
||||||
|
@ -1,37 +1,47 @@
|
|||||||
|
import { Token } from 'graphql/thegraph/__generated__/types-and-hooks'
|
||||||
|
|
||||||
export const validParams = { poolAddress: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640', chainName: 'ethereum' }
|
export const validParams = { poolAddress: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640', chainName: 'ethereum' }
|
||||||
export const validPoolDataResponse = {
|
export const validPoolDataResponse = {
|
||||||
data: {
|
data: {
|
||||||
__typename: 'Pool' as const,
|
|
||||||
id: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640',
|
id: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640',
|
||||||
feeTier: '500',
|
feeTier: 500,
|
||||||
liquidity: '32118065613640312417',
|
liquidity: parseFloat('26414803986874770777'),
|
||||||
sqrtPrice: '1943494374075311739809880994923792',
|
sqrtPrice: parseFloat('1977320351696380862605029898750440'),
|
||||||
tick: '202163',
|
tick: 202508,
|
||||||
token0: {
|
token0: {
|
||||||
__typename: 'Token' as const,
|
|
||||||
id: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
id: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||||
symbol: 'USDC',
|
symbol: 'USDC',
|
||||||
name: 'USD Coin',
|
name: 'USD Coin',
|
||||||
decimals: '6',
|
decimals: '6',
|
||||||
derivedETH: '0.000602062055419695968472438533210813',
|
derivedETH: '0.0006240873011635544626425964678706127',
|
||||||
},
|
__typename: 'Token',
|
||||||
|
} as Token,
|
||||||
token1: {
|
token1: {
|
||||||
__typename: 'Token' as const,
|
|
||||||
id: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
|
id: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
|
||||||
symbol: 'WETH',
|
symbol: 'WETH',
|
||||||
name: 'Wrapped Ether',
|
name: 'Wrapped Ether',
|
||||||
decimals: '18',
|
decimals: '18',
|
||||||
derivedETH: '1',
|
derivedETH: '1',
|
||||||
},
|
__typename: 'Token',
|
||||||
token0Price: '1661.85294822715829371652214854595',
|
} as Token,
|
||||||
token1Price: '0.0006017379582632664031212782038199158',
|
token0Price: 1605.481,
|
||||||
volumeUSD: '394920157156.0515346899898790592366',
|
token1Price: 0.000622,
|
||||||
volumeToken0: '394894081779.781168',
|
volumeUSD: 233379442.64648438,
|
||||||
volumeToken1: '190965971.266407832255075308',
|
volumeToken0: '397309311915.656392',
|
||||||
txCount: '5406827',
|
volumeToken1: '192461624.767400825529358443',
|
||||||
totalValueLockedToken0: '180078648.881221',
|
txCount: '5456494',
|
||||||
totalValueLockedToken1: '142782.017882048454494774',
|
totalValueLockedToken0: '190258041.714605',
|
||||||
totalValueLockedUSD: '417233634.1468435997761171520463339',
|
totalValueLockedToken1: '130641.89297715763283183',
|
||||||
|
totalValueLockedUSD: '399590762.8476702153638342035105795',
|
||||||
|
__typename: 'Pool',
|
||||||
|
address: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640',
|
||||||
|
volumeUSDChange: -17.753809465717136,
|
||||||
|
volumeUSDWeek: 1359911419.265625,
|
||||||
|
tvlUSD: 223166198.4690675,
|
||||||
|
tvlUSDChange: -0.3657085465786977,
|
||||||
|
tvlToken0: 90930713.7356909,
|
||||||
|
tvlToken1: 82526.48678530742,
|
||||||
},
|
},
|
||||||
loading: false,
|
loading: false,
|
||||||
|
error: false,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user