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`)
|
||||
|
||||
// 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 {
|
||||
L1,
|
||||
L2,
|
||||
|
@ -2,12 +2,20 @@ import { ChainId } from '@uniswap/sdk-core'
|
||||
import gql from 'graphql-tag'
|
||||
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 { useBlocksFromTimestamps } from './useBlocksFromTimestamps'
|
||||
import { get2DayChange, useDeltaTimestamps } from './utils'
|
||||
|
||||
gql`
|
||||
query PoolData($poolId: [ID!]) {
|
||||
data: pools(where: { id_in: $poolId }, orderBy: totalValueLockedUSD, orderDirection: desc, subgraphError: allow) {
|
||||
query PoolData($poolId: [ID!], $block: Block_height = null) {
|
||||
pools(
|
||||
where: { id_in: $poolId }
|
||||
block: $block
|
||||
orderBy: totalValueLockedUSD
|
||||
orderDirection: desc
|
||||
subgraphError: allow
|
||||
) {
|
||||
id
|
||||
feeTier
|
||||
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 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 {
|
||||
data: data?.data[0],
|
||||
loading,
|
||||
const anyError = Boolean(error || error24 || error48 || blockError || errorWeek)
|
||||
const anyLoading = Boolean(loading || loading24 || loading48 || loadingWeek)
|
||||
|
||||
// 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.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.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] })
|
||||
@ -63,3 +75,34 @@ export const chainToApolloClient: Record<number, ApolloClient<NormalizedCacheObj
|
||||
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({
|
||||
data: undefined,
|
||||
loading: false,
|
||||
error: false,
|
||||
})
|
||||
render(<PoolDetails />)
|
||||
|
||||
@ -77,7 +78,11 @@ describe('PoolDetailsPage', () => {
|
||||
|
||||
// TODO replace with loading skeleton when designed
|
||||
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 />)
|
||||
|
||||
waitFor(() => {
|
||||
|
@ -1,37 +1,47 @@
|
||||
import { Token } from 'graphql/thegraph/__generated__/types-and-hooks'
|
||||
|
||||
export const validParams = { poolAddress: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640', chainName: 'ethereum' }
|
||||
export const validPoolDataResponse = {
|
||||
data: {
|
||||
__typename: 'Pool' as const,
|
||||
id: '0x88e6a0c2ddd26feeb64f039a2c41296fcb3f5640',
|
||||
feeTier: '500',
|
||||
liquidity: '32118065613640312417',
|
||||
sqrtPrice: '1943494374075311739809880994923792',
|
||||
tick: '202163',
|
||||
feeTier: 500,
|
||||
liquidity: parseFloat('26414803986874770777'),
|
||||
sqrtPrice: parseFloat('1977320351696380862605029898750440'),
|
||||
tick: 202508,
|
||||
token0: {
|
||||
__typename: 'Token' as const,
|
||||
id: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
|
||||
symbol: 'USDC',
|
||||
name: 'USD Coin',
|
||||
decimals: '6',
|
||||
derivedETH: '0.000602062055419695968472438533210813',
|
||||
},
|
||||
derivedETH: '0.0006240873011635544626425964678706127',
|
||||
__typename: 'Token',
|
||||
} as Token,
|
||||
token1: {
|
||||
__typename: 'Token' as const,
|
||||
id: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
|
||||
symbol: 'WETH',
|
||||
name: 'Wrapped Ether',
|
||||
decimals: '18',
|
||||
derivedETH: '1',
|
||||
},
|
||||
token0Price: '1661.85294822715829371652214854595',
|
||||
token1Price: '0.0006017379582632664031212782038199158',
|
||||
volumeUSD: '394920157156.0515346899898790592366',
|
||||
volumeToken0: '394894081779.781168',
|
||||
volumeToken1: '190965971.266407832255075308',
|
||||
txCount: '5406827',
|
||||
totalValueLockedToken0: '180078648.881221',
|
||||
totalValueLockedToken1: '142782.017882048454494774',
|
||||
totalValueLockedUSD: '417233634.1468435997761171520463339',
|
||||
__typename: 'Token',
|
||||
} as Token,
|
||||
token0Price: 1605.481,
|
||||
token1Price: 0.000622,
|
||||
volumeUSD: 233379442.64648438,
|
||||
volumeToken0: '397309311915.656392',
|
||||
volumeToken1: '192461624.767400825529358443',
|
||||
txCount: '5456494',
|
||||
totalValueLockedToken0: '190258041.714605',
|
||||
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,
|
||||
error: false,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user