diff --git a/.changeset/quick-turkeys-pay.md b/.changeset/quick-turkeys-pay.md new file mode 100644 index 0000000000000..7bdcafd5b9064 --- /dev/null +++ b/.changeset/quick-turkeys-pay.md @@ -0,0 +1,5 @@ +--- +'@pancakeswap/chains': patch +--- + +add helper for chainname in mainnet diff --git a/apis/farms/.dev.vars b/apis/farms/.dev.vars index ee55e0aab52be..a8823af1f162a 100644 --- a/apis/farms/.dev.vars +++ b/apis/farms/.dev.vars @@ -9,3 +9,5 @@ LINEA_NODE=https://rpc.linea.build BASE_NODE=https://mainnet.base.org OPBNB_NODE=https://opbnb-mainnet-rpc.bnbchain.org OPBNB_TESTNET_NODE=https://opbnb-testnet-rpc.bnbchain.org +EXPLORER_URL=http://localhost:4123 +EXPLORER_API_KEY=API_KEY \ No newline at end of file diff --git a/apis/farms/src/bindings.d.ts b/apis/farms/src/bindings.d.ts index ec18adf6697a0..487ba1b4c19de 100644 --- a/apis/farms/src/bindings.d.ts +++ b/apis/farms/src/bindings.d.ts @@ -15,6 +15,6 @@ declare global { const BASE_NODE: string const OPBNB_NODE: string const OPBNB_TESTNET_NODE: string - const NODE_REAL_SUBGRAPH_API_KEY: string - const THE_GRAPH_API_KEY: string + const EXPLORER_URL: string + const EXPLORER_API_KEY: string } diff --git a/apis/farms/src/provider.ts b/apis/farms/src/provider.ts index da1d4db4d200b..5f1243a639422 100644 --- a/apis/farms/src/provider.ts +++ b/apis/farms/src/provider.ts @@ -25,8 +25,8 @@ const requireCheck = [ BASE_NODE, OPBNB_NODE, OPBNB_TESTNET_NODE, - NODE_REAL_SUBGRAPH_API_KEY, - THE_GRAPH_API_KEY, + EXPLORER_URL, + EXPLORER_API_KEY, ] const base = { diff --git a/apis/farms/src/v3.ts b/apis/farms/src/v3.ts index 9dd0ccede9159..83d7988cbfb80 100644 --- a/apis/farms/src/v3.ts +++ b/apis/farms/src/v3.ts @@ -1,10 +1,9 @@ /* eslint-disable no-param-reassign, no-await-in-loop */ -import { ChainId, getV3Subgraphs } from '@pancakeswap/chains' -import { FarmV3SupportedChainId, masterChefV3Addresses } from '@pancakeswap/farms' +import { ChainId, getMainnetChainNameInKebabCase } from '@pancakeswap/chains' +import { masterChefV3Addresses } from '@pancakeswap/farms' import { ERC20Token } from '@pancakeswap/sdk' import { CurrencyAmount } from '@pancakeswap/swap-sdk-core' import { PositionMath } from '@pancakeswap/v3-sdk' -import { GraphQLClient, gql } from 'graphql-request' import { Request } from 'itty-router' import { error, json } from 'itty-router-extras' import { Address } from 'viem' @@ -17,8 +16,6 @@ export const V3_SUBGRAPH_CLIENTS_CHAIN_IDS = [ ChainId.ETHEREUM, ChainId.GOERLI, ChainId.BSC, - ChainId.BSC_TESTNET, - ChainId.ZKSYNC_TESTNET, ChainId.POLYGON_ZKEVM, ChainId.ZKSYNC, ChainId.ARBITRUM_ONE, @@ -29,16 +26,6 @@ export const V3_SUBGRAPH_CLIENTS_CHAIN_IDS = [ type SupportChainId = (typeof V3_SUBGRAPH_CLIENTS_CHAIN_IDS)[number] -const V3_SUBGRAPHS = getV3Subgraphs({ - noderealApiKey: NODE_REAL_SUBGRAPH_API_KEY, - theGraphApiKey: THE_GRAPH_API_KEY, -}) - -export const V3_SUBGRAPH_CLIENTS = V3_SUBGRAPH_CLIENTS_CHAIN_IDS.reduce((acc, chainId) => { - acc[chainId] = new GraphQLClient(V3_SUBGRAPHS[chainId], { fetch }) - return acc -}, {} as Record, GraphQLClient>) - const zChainId = z.enum(V3_SUBGRAPH_CLIENTS_CHAIN_IDS.map((chainId) => String(chainId)) as [string, ...string[]]) const zAddress = z.string().regex(/^0x[a-fA-F0-9]{40}$/) @@ -250,7 +237,7 @@ const handler_ = async (req: Request, event: FetchEvent) => { const resultTimeout = await Promise.race([ timeout(20), - fetchLiquidityFromSubgraph(chainId, address, masterChefV3Address, tick, sqrtPriceX96), + fetchLiquidityFromExplorer(chainId, address, masterChefV3Address, tick, sqrtPriceX96), ]) if (!resultTimeout) { @@ -319,8 +306,8 @@ const handler_ = async (req: Request, event: FetchEvent) => { } } -async function fetchLiquidityFromSubgraph( - chainId: keyof typeof V3_SUBGRAPH_CLIENTS, +async function fetchLiquidityFromExplorer( + chainId: (typeof V3_SUBGRAPH_CLIENTS_CHAIN_IDS)[number], address: string, masterChefV3Address: string, tick: number, @@ -329,71 +316,54 @@ async function fetchLiquidityFromSubgraph( const updatedAt = new Date().toISOString() let allActivePositions: any[] = [] - const poolTokens = await V3_SUBGRAPH_CLIENTS[chainId].request( - gql` - query pool($poolAddress: String!) { - pool(id: $poolAddress) { - token0 { - id - decimals - } - token1 { - id - decimals - } - } - } - `, - { - poolAddress: address, + const chainName = getMainnetChainNameInKebabCase(chainId) + const pool: { + token0: { + id: Address + decimals: number + } + token1: { + id: Address + decimals: number + } + } = await fetch(`${EXPLORER_URL}/cached/pools/v3/${chainName}/${address}`, { + headers: { + 'x-api-key': EXPLORER_API_KEY, + 'Content-Type': 'application/json', }, - ) - - // eslint-disable-next-line no-inner-declarations - async function fetchPositionByMasterChefId(posId_ = '0') { - const resp = await V3_SUBGRAPH_CLIENTS[chainId].request( - gql` - query tvl($poolAddress: String!, $owner: String!, $posId: String!, $currentTick: String!) { - positions( - where: { pool: $poolAddress, liquidity_gt: "0", owner: $owner, id_gt: $posId } - first: 1000 - orderBy: id - tickLower_: { tickIdx_lte: currentTick } - tickUpper_: { tickIdx_gt: currentTick } - ) { - liquidity - id - tickUpper { - tickIdx - } - tickLower { - tickIdx - } - } - } - `, - { - poolAddress: address, - owner: masterChefV3Address.toLowerCase(), - currentTick: tick.toString(), - posId: posId_, - }, - ) + }).then((res) => { + return res.json() + }) - return resp.positions + if (!pool) { + throw new Error('Pool not found') } - let posId = '0' + let hasNextPage = true + let cursor: string | undefined - // eslint-disable-next-line no-constant-condition - while (true) { + while (hasNextPage) { // eslint-disable-next-line no-await-in-loop - const pos = await fetchPositionByMasterChefId(posId) - allActivePositions = [...allActivePositions, ...pos] - if (pos.length < 1000) { - break - } - posId = pos[pos.length - 1].id + const positions: any = await getPositionByMasterChefId(cursor) + allActivePositions = [...allActivePositions, ...positions.rows] + // eslint-disable-next-line prefer-destructuring + hasNextPage = positions.hasNextPage + // eslint-disable-next-line prefer-destructuring + cursor = positions.endCursor + } + + async function getPositionByMasterChefId(after?: string) { + return fetch( + `${EXPLORER_URL}/cached/pools/positions/v3/${chainName}/${address}?owner=${masterChefV3Address.toLowerCase()}${ + after ? `&after=${after}` : '' + }`, + { + headers: { + 'x-api-key': EXPLORER_API_KEY, + 'Content-Type': 'application/json', + }, + }, + ).then((res) => res.json()) } console.info('fetching farms active liquidity', { @@ -416,20 +386,20 @@ async function fetchLiquidityFromSubgraph( for (const position of allActivePositions.filter( // double check that the position is within the current tick range - (p) => +p.tickLower.tickIdx <= currentTick && +p.tickUpper.tickIdx > currentTick, + (p) => +p.lowerTickIdx <= currentTick && +p.upperTickIdx > currentTick, )) { const token0 = PositionMath.getToken0Amount( currentTick, - +position.tickLower.tickIdx, - +position.tickUpper.tickIdx, + +position.lowerTickIdx, + +position.upperTickIdx, sqrtRatio, BigInt(position.liquidity), ) const token1 = PositionMath.getToken1Amount( currentTick, - +position.tickLower.tickIdx, - +position.tickUpper.tickIdx, + +position.lowerTickIdx, + +position.upperTickIdx, sqrtRatio, BigInt(position.liquidity), ) @@ -438,11 +408,11 @@ async function fetchLiquidityFromSubgraph( } const curr0 = CurrencyAmount.fromRawAmount( - new ERC20Token(+chainId, poolTokens.pool.token0.id, +poolTokens.pool.token0.decimals, '0'), + new ERC20Token(+chainId, pool.token0.id, +pool.token0.decimals, '0'), totalToken0.toString(), ).toExact() const curr1 = CurrencyAmount.fromRawAmount( - new ERC20Token(+chainId, poolTokens.pool.token1.id, +poolTokens.pool.token1.decimals, '1'), + new ERC20Token(+chainId, pool.token1.id, +pool.token1.decimals, '1'), totalToken1.toString(), ).toExact() diff --git a/apis/farms/wrangler.toml b/apis/farms/wrangler.toml index be304cad5dbac..691330653756f 100644 --- a/apis/farms/wrangler.toml +++ b/apis/farms/wrangler.toml @@ -32,6 +32,6 @@ crons = ["0 0 * * *", "*/1 * * * *"] # - ARBITRUM_ONE_NODE # - LINEA_NODE # - BASE_NODE -# - NODE_REAL_SUBGRAPH_API_KEY -# - THE_GRAPH_API_KEY +# - EXPLORER_API_KEY +# - EXPLORER_API_KEY # Run `echo | wrangler secret put ` for each of these diff --git a/packages/chains/src/chainNames.ts b/packages/chains/src/chainNames.ts index 6f7f1c5d84a5f..e08acf1f6958e 100644 --- a/packages/chains/src/chainNames.ts +++ b/packages/chains/src/chainNames.ts @@ -46,6 +46,28 @@ export const chainNamesInKebabCase = { [ChainId.BASE_SEPOLIA]: 'base-sepolia', } as const +export const mainnetChainNamesInKebabCase = { + [ChainId.ETHEREUM]: 'ethereum', + [ChainId.GOERLI]: 'ethereum', + [ChainId.BSC]: 'bsc', + [ChainId.BSC_TESTNET]: 'bsc', + [ChainId.ARBITRUM_ONE]: 'arbitrum', + [ChainId.ARBITRUM_GOERLI]: 'arbitrum', + [ChainId.POLYGON_ZKEVM]: 'polygon-zkevm', + [ChainId.POLYGON_ZKEVM_TESTNET]: 'polygon-zkevm', + [ChainId.ZKSYNC]: 'zksync', + [ChainId.ZKSYNC_TESTNET]: 'zksync', + [ChainId.LINEA]: 'linea', + [ChainId.LINEA_TESTNET]: 'linea', + [ChainId.OPBNB]: 'opbnb', + [ChainId.OPBNB_TESTNET]: 'opbnb', + [ChainId.BASE]: 'base', + [ChainId.BASE_TESTNET]: 'base', + [ChainId.SEPOLIA]: 'ethereum', + [ChainId.ARBITRUM_SEPOLIA]: 'arbitrum', + [ChainId.BASE_SEPOLIA]: 'base', +} as const + export const chainNameToChainId = Object.entries(chainNames).reduce((acc, [chainId, chainName]) => { return { [chainName]: chainId as unknown as ChainId, diff --git a/packages/chains/src/index.test.ts b/packages/chains/src/index.test.ts index 2fe5def0a52b9..3d2e5e9308a85 100644 --- a/packages/chains/src/index.test.ts +++ b/packages/chains/src/index.test.ts @@ -8,10 +8,12 @@ test('exports', () => { "testnetChainIds", "chainNames", "chainNamesInKebabCase", + "mainnetChainNamesInKebabCase", "chainNameToChainId", "defiLlamaChainNames", "getChainName", "getChainNameInKebabCase", + "getMainnetChainNameInKebabCase", "getLlamaChainName", "getChainIdByChainName", "isTestnetChainId", diff --git a/packages/chains/src/utils.ts b/packages/chains/src/utils.ts index 863db0d9bd267..c56c4cc1f4230 100644 --- a/packages/chains/src/utils.ts +++ b/packages/chains/src/utils.ts @@ -1,5 +1,11 @@ import { ChainId, testnetChainIds } from './chainId' -import { chainNameToChainId, chainNames, chainNamesInKebabCase, defiLlamaChainNames } from './chainNames' +import { + chainNameToChainId, + chainNames, + chainNamesInKebabCase, + defiLlamaChainNames, + mainnetChainNamesInKebabCase, +} from './chainNames' export function getChainName(chainId: ChainId) { return chainNames[chainId] @@ -9,6 +15,10 @@ export function getChainNameInKebabCase(chainId: ChainId) { return chainNamesInKebabCase[chainId] } +export function getMainnetChainNameInKebabCase(chainId: keyof typeof mainnetChainNamesInKebabCase) { + return mainnetChainNamesInKebabCase[chainId] +} + export function getLlamaChainName(chainId: ChainId) { return defiLlamaChainNames[chainId] }