Skip to content

Commit

Permalink
feat: v3 liquidity explorer (#9936)
Browse files Browse the repository at this point in the history
<!--
Before opening a pull request, please read the [contributing
guidelines](https://github.com/pancakeswap/pancake-frontend/blob/develop/CONTRIBUTING.md)
first
-->

<!-- start pr-codex -->

---

## PR-Codex overview
The focus of this PR is to refactor the `usePoolAvgInfo` and
`useAllV3TicksQuery` hooks to use a centralized API client for fetching
data efficiently.

### Detailed summary
- Refactored hooks to use `explorerApiClient` for fetching data
- Removed unnecessary GraphQL requests
- Improved error handling and data fetching efficiency

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your
question}`

<!-- end pr-codex -->
  • Loading branch information
0xjojoex authored Jun 11, 2024
1 parent 21fffbe commit 84d9170
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 32 deletions.
54 changes: 25 additions & 29 deletions apps/web/src/hooks/usePoolAvgInfo.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
/* eslint-disable no-console */
import { ChainId } from '@pancakeswap/chains'
import { gql } from 'graphql-request'
import { useQuery } from '@tanstack/react-query'

import { v3Clients } from 'utils/graphql'
import { chainIdToExplorerInfoChainName, explorerApiClient } from 'state/info/api/client'

export interface UsePoolAvgInfoParams {
numberOfDays?: number
address?: string
chainId?: ChainId
enabled?: boolean
Expand Down Expand Up @@ -34,40 +32,38 @@ const defaultInfo: Info = {
feeUSD: 0,
}

export function usePoolAvgInfo({ address = '', numberOfDays = 7, chainId, enabled = true }: UsePoolAvgInfoParams) {
export function usePoolAvgInfo({ address = '', chainId, enabled = true }: UsePoolAvgInfoParams) {
const { data } = useQuery({
queryKey: ['poolAvgInfo', address, chainId],

queryFn: async () => {
if (!chainId) return undefined
const client = v3Clients[chainId]
if (!client) {
queryFn: async ({ signal }) => {
if (!chainId) throw new Error('Chain ID not found')
if (!address) throw new Error('Address not found')

const chainName = chainIdToExplorerInfoChainName[chainId]
if (!chainName) {
throw new Error('Chain name not found')
}

const resp = await explorerApiClient.GET('/cached/pools/v3/{chainName}/{address}', {
signal,
params: {
path: {
address,
chainName,
},
},
})

if (!resp.data) {
console.log('[Failed] Trading volume', address, chainId)
return defaultInfo
}

const query = gql`
query getVolume($days: Int!, $address: String!) {
poolDayDatas(first: $days, orderBy: date, orderDirection: desc, where: { pool: $address }) {
volumeUSD
tvlUSD
feesUSD
protocolFeesUSD
}
}
`
const { poolDayDatas } = await client.request(query, {
days: numberOfDays,
address: address.toLowerCase(),
})
const volumes = poolDayDatas.map((d: { volumeUSD: string }) => Number(d.volumeUSD))
const feeUSDs = poolDayDatas.map(
(d: { feesUSD: string; protocolFeesUSD: string }) => Number(d.feesUSD) - Number(d.protocolFeesUSD),
)
return {
volumeUSD: averageArray(volumes),
tvlUSD: parseFloat(poolDayDatas[0]?.tvlUSD) || 0,
feeUSD: averageArray(feeUSDs),
volumeUSD: +resp.data.volumeUSD7d / 7,
tvlUSD: +resp.data.tvlUSD,
feeUSD: (+resp.data.feeUSD7d - +resp.data.protocolFeeUSD7d) / 7,
}
},

Expand Down
71 changes: 68 additions & 3 deletions apps/web/src/hooks/v3/useAllV3TicksQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { useQuery } from '@tanstack/react-query'
import { gql } from 'graphql-request'
import { useActiveChainId } from 'hooks/useActiveChainId'
import { useMemo } from 'react'
import { chainIdToExplorerInfoChainName, explorerApiClient } from 'state/info/api/client'
import { v3Clients } from 'utils/graphql'

export type AllV3TicksQuery = {
Expand All @@ -21,9 +22,9 @@ export default function useAllV3TicksQuery(poolAddress: string | undefined, inte
const { chainId } = useActiveChainId()
const { data, isLoading, error } = useQuery({
queryKey: [`useAllV3TicksQuery-${poolAddress}-${chainId}`],
queryFn: async () => {
queryFn: async ({ signal }) => {
if (!chainId || !poolAddress) return undefined
return getPoolTicks(chainId, poolAddress)
return getPoolTicks(chainId, poolAddress, undefined, signal)
},
enabled: Boolean(poolAddress && chainId && v3Clients[chainId] && enabled),
refetchInterval: interval,
Expand All @@ -42,7 +43,71 @@ export default function useAllV3TicksQuery(poolAddress: string | undefined, inte
)
}

export async function getPoolTicks(chainId: number, poolAddress: string, blockNumber?: string): Promise<Ticks> {
export async function getPoolTicks(
chainId: number,
poolAddress: string,
_blockNumber?: string,
signal?: AbortSignal,
): Promise<Ticks> {
const chainName = chainIdToExplorerInfoChainName[chainId]
if (!chainName) {
return []
}

let max = 10
let after: string | undefined
const allTicks: Ticks = []

// eslint-disable-next-line no-constant-condition
while (true) {
if (max <= 0) {
break
}
if (!after && max < 10) {
break
}
max--

// eslint-disable-next-line no-await-in-loop
const resp = await explorerApiClient.GET('/cached/pools/ticks/v3/{chainName}/{pool}', {
signal,
params: {
path: {
chainName,
pool: poolAddress.toLowerCase(),
},
query: {
after,
},
},
})

if (!resp.data) {
break
}
if (resp.data.rows.length === 0) {
break
}
if (resp.data.hasNextPage && resp.data.endCursor) {
after = resp.data.endCursor
} else {
after = undefined
}

allTicks.push(
...resp.data.rows.map((tick) => {
return {
tick: tick.tickIdx.toString(),
liquidityNet: tick.liquidityNet,
liquidityGross: tick.liquidityGross,
}
}),
)
}

return allTicks
}
export async function getPoolTicksOld(chainId: number, poolAddress: string, blockNumber?: string): Promise<Ticks> {
const PAGE_SIZE = 1000
let allTicks: any[] = []
let lastTick = TickMath.MIN_TICK - 1
Expand Down

0 comments on commit 84d9170

Please sign in to comment.