From 9cd2e6a4e913069f285d8192d1d071ffcc0faa02 Mon Sep 17 00:00:00 2001 From: dyedm1 Date: Wed, 18 Dec 2024 22:51:20 -0500 Subject: [PATCH 1/5] feat: add Panoptic adapter --- package-lock.json | 7 ++ package.json | 1 + projects/panoptic/index.js | 249 +++++++++++++++++++++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 projects/panoptic/index.js diff --git a/package-lock.json b/package-lock.json index 177f1400cc6a..46d5b02e8efd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "graphql-request": "^4.0.0", "hi-base32": "^0.5.1", "js-sha512": "^0.8.0", + "jsbi": "^4.3.0", "limiter": "2.1.0", "miscreant": "^0.3.2", "p-limit": "^3.1.0", @@ -3347,6 +3348,12 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbi": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-4.3.0.tgz", + "integrity": "sha512-SnZNcinB4RIcnEyZqFPdGPVgrg2AcnykiBy0sHVJQKHYeaLUvi3Exj+iaPpLnFVkDPZIV4U0yvgC9/R4uEAZ9g==", + "license": "Apache-2.0" + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", diff --git a/package.json b/package.json index 16a0dbca56c7..95141d08a0fd 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "graphql-request": "^4.0.0", "hi-base32": "^0.5.1", "js-sha512": "^0.8.0", + "jsbi": "^4.3.0", "limiter": "2.1.0", "miscreant": "^0.3.2", "p-limit": "^3.1.0", diff --git a/projects/panoptic/index.js b/projects/panoptic/index.js new file mode 100644 index 000000000000..7ffbb38907e8 --- /dev/null +++ b/projects/panoptic/index.js @@ -0,0 +1,249 @@ +const sdk = require('@defillama/sdk') +const { getLogs } = require('../helper/cache/getLogs') +const JSBI = require('jsbi'); + + +const FACTORY = '0x000000000000010a1DEc6c46371A28A071F8bb01' +const SFPM = '0x0000000000000DEdEDdD16227aA3D836C5753194' +const startBlocks = { + ethereum: 21389983, +} + +const Q96 = BigInt(2) ** BigInt(96) + +function chainTvl(chain) { + return async (api) => { + const START_BLOCK = startBlocks[chain] + const poolDeployedLogs = ( + await getLogs({ + api, + target: FACTORY, + fromBlock: START_BLOCK, + topic: 'PoolDeployed(address,address,address,address)', + }) + ) + + // can contain SFPM pools that don't have options markets yet + const poolInitializedLogs = ( + await getLogs({ + api, + target: SFPM, + fromBlock: START_BLOCK, + topic: 'PoolInitialized(address,uint64,int24,int24)', + }) + ) + + const block = api.block + + const poolData = {} + + for (let log of poolDeployedLogs) + poolData[`0x${log.topics[2].substr(-40)}`.toLowerCase()] = {marketAddress: `0x${log.topics[1].substr(-40)}`.toLowerCase()} + + + for (let log of poolInitializedLogs) { + const V3PoolAddress = `0x${log.topics[1].substr(-40)}`.toLowerCase() + if (!poolData?.[V3PoolAddress]) poolData[V3PoolAddress] = {marketAddress: '0x3327b4D450fbB3a4b780510489C259D85776D559'.toLowerCase()} // random address + } + + const token0Calls = Object.keys(poolData).map((V3Pool) => ({ target: V3Pool })) + const token1Calls = Object.keys(poolData).map((V3Pool) => ({ target: V3Pool })) + + const token0Results = await sdk.api.abi.multiCall({ + abi: "function token0() view returns (address)", + calls: token0Calls, + block, + chain, + }) + + token0Results.output.forEach((call, i) => { + poolData[call.input.target].token0 = call.output + }) + + const token1Results = await sdk.api.abi.multiCall({ + abi: "function token1() view returns (address)", + calls: token1Calls, + block, + chain, + }) + + token1Results.output.forEach((call, i) => { + poolData[call.input.target].token1 = call.output + }) + + // Create balance calls for both tokens of each market + const balanceCalls = [] + + const LiquidityOwnedTokens = [] + + // Iterate through markets array directly + for (let [V3Pool, poolDataEntry] of Object.entries(poolData)) { + const mintLogs = ( + await getLogs({ + api, + target: V3Pool, + fromBlock: START_BLOCK, + extraKey: "mintCache", + eventAbi: `event Mint(address sender,address indexed owner,int24 indexed tickLower,int24 indexed tickUpper,uint128 amount,uint256 amount0,uint256 amount1)`, + topics: ["0x7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde","0x"+"000000000000000000000000"+SFPM.slice(2)] + }) + ) + const burnLogs = ( + await getLogs({ + api, + target: V3Pool, + fromBlock: START_BLOCK, + extraKey: "burnCache", + eventAbi: `event Burn(address indexed owner,int24 indexed tickLower,int24 indexed tickUpper,uint128 amount,uint256 amount0,uint256 amount1)`, + topics: ["0x0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c","0x"+"000000000000000000000000"+SFPM.slice(2)] + }) + ) + + let sfpmOwnedLiquiditiesForMarket = {} + + mintLogs.forEach((log) => { + const key = log.args.tickLower.toString()+"-"+log.args.tickUpper.toString() + sfpmOwnedLiquiditiesForMarket[key] = (sfpmOwnedLiquiditiesForMarket?.[key] ?? 0n) + log.args.amount}) + burnLogs.forEach((log) => sfpmOwnedLiquiditiesForMarket[log.args.tickLower.toString()+"-"+log.args.tickUpper.toString()] -= log.args.amount) + + const sqrtPriceX96 = ( + await sdk.api.abi.call({ + target: V3Pool, + abi: "function slot0() view returns (uint160 sqrtPriceX96, int24 tick, uint16 observationIndex, uint16 observationCardinality, uint16 observationCardinalityNext, uint8 feeProtocol, bool unlocked)", + block, + chain, + }) + ).output.sqrtPriceX96 + + let extraTokens0 = 0n + let extraTokens1 = 0n + + for (let [key, liquidity] of Object.entries(sfpmOwnedLiquiditiesForMarket)) { + const sqrtLower = BigInt(getSqrtRatioAtTick(Number(key.split("-")[0])).toString()) + const sqrtUpper = BigInt(getSqrtRatioAtTick(Number(key.split("-")[1])).toString()) + + const [amount0, amount1] = getAmountsForLiquidity(BigInt(sqrtPriceX96), liquidity, sqrtLower, sqrtUpper) + extraTokens0 += amount0 + extraTokens1 += amount1 + } + + LiquidityOwnedTokens.push(extraTokens0) + LiquidityOwnedTokens.push(extraTokens1) + + balanceCalls.push({ + target: poolDataEntry.token0, + params: poolDataEntry.marketAddress, + }) + balanceCalls.push({ + target: poolDataEntry.token1, + params: poolDataEntry.marketAddress, + }) + } + + const tokenBalances = await sdk.api.abi.multiCall({ + abi: 'erc20:balanceOf', + calls: balanceCalls, + block, + chain, + }) + + // add tokens held in liquidity positions to TVL + tokenBalances.output = tokenBalances.output.map((call, i) => ({...call, output: (BigInt(call.output) + LiquidityOwnedTokens[i]).toString()})) + + let transform = id => id + let balances = {} + + sdk.util.sumMultiBalanceOf(balances, tokenBalances, true, transform) + + return balances + } +} + +function getAmount0ForLiquidity( + sqrtRatioAX96, + sqrtRatioBX96, + liquidity, +) { + if (sqrtRatioAX96 > sqrtRatioBX96) { + const temp = sqrtRatioAX96 + sqrtRatioAX96 = sqrtRatioBX96 + sqrtRatioBX96 = temp + } + + return (liquidity * Q96 * (sqrtRatioBX96 - sqrtRatioAX96)) / sqrtRatioBX96 / sqrtRatioAX96 +} + +function getAmount1ForLiquidity( + sqrtRatioAX96, + sqrtRatioBX96, + liquidity, +) { + if (sqrtRatioAX96 > sqrtRatioBX96) { + const temp = sqrtRatioAX96 + sqrtRatioAX96 = sqrtRatioBX96 + sqrtRatioBX96 = temp + } + + return (liquidity * (sqrtRatioBX96 - sqrtRatioAX96)) / Q96 +} + +function getAmountsForLiquidity( + priceX96, + liquidity, + sqrtRatioAX96, + sqrtRatioBX96, +) { + if (priceX96 <= sqrtRatioAX96) { + return [getAmount0ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity), BigInt(0)] + } else if (priceX96 >= sqrtRatioBX96) { + return [BigInt(0), getAmount1ForLiquidity(sqrtRatioAX96, sqrtRatioBX96, liquidity)] + } else { + return [ + getAmount0ForLiquidity(priceX96, sqrtRatioBX96, liquidity), + getAmount1ForLiquidity(sqrtRatioAX96, priceX96, liquidity), + ] + } +} + +function getSqrtRatioAtTick(tick) { + const MaxUint256 = JSBI.BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'); + const Q32 = JSBI.BigInt('0x100000000'); + const ZERO = JSBI.BigInt(0); + const ONE = JSBI.BigInt(1); + var absTick = tick < 0 ? tick * -1 : tick; + var ratio = (absTick & 0x1) !== 0 ? JSBI.BigInt('0xfffcb933bd6fad37aa2d162d1a594001') : JSBI.BigInt('0x100000000000000000000000000000000'); + if ((absTick & 0x2) !== 0) ratio = mulShift(ratio, '0xfff97272373d413259a46990580e213a'); + if ((absTick & 0x4) !== 0) ratio = mulShift(ratio, '0xfff2e50f5f656932ef12357cf3c7fdcc'); + if ((absTick & 0x8) !== 0) ratio = mulShift(ratio, '0xffe5caca7e10e4e61c3624eaa0941cd0'); + if ((absTick & 0x10) !== 0) ratio = mulShift(ratio, '0xffcb9843d60f6159c9db58835c926644'); + if ((absTick & 0x20) !== 0) ratio = mulShift(ratio, '0xff973b41fa98c081472e6896dfb254c0'); + if ((absTick & 0x40) !== 0) ratio = mulShift(ratio, '0xff2ea16466c96a3843ec78b326b52861'); + if ((absTick & 0x80) !== 0) ratio = mulShift(ratio, '0xfe5dee046a99a2a811c461f1969c3053'); + if ((absTick & 0x100) !== 0) ratio = mulShift(ratio, '0xfcbe86c7900a88aedcffc83b479aa3a4'); + if ((absTick & 0x200) !== 0) ratio = mulShift(ratio, '0xf987a7253ac413176f2b074cf7815e54'); + if ((absTick & 0x400) !== 0) ratio = mulShift(ratio, '0xf3392b0822b70005940c7a398e4b70f3'); + if ((absTick & 0x800) !== 0) ratio = mulShift(ratio, '0xe7159475a2c29b7443b29c7fa6e889d9'); + if ((absTick & 0x1000) !== 0) ratio = mulShift(ratio, '0xd097f3bdfd2022b8845ad8f792aa5825'); + if ((absTick & 0x2000) !== 0) ratio = mulShift(ratio, '0xa9f746462d870fdf8a65dc1f90e061e5'); + if ((absTick & 0x4000) !== 0) ratio = mulShift(ratio, '0x70d869a156d2a1b890bb3df62baf32f7'); + if ((absTick & 0x8000) !== 0) ratio = mulShift(ratio, '0x31be135f97d08fd981231505542fcfa6'); + if ((absTick & 0x10000) !== 0) ratio = mulShift(ratio, '0x9aa508b5b7a84e1c677de54f3e99bc9'); + if ((absTick & 0x20000) !== 0) ratio = mulShift(ratio, '0x5d6af8dedb81196699c329225ee604'); + if ((absTick & 0x40000) !== 0) ratio = mulShift(ratio, '0x2216e584f5fa1ea926041bedfe98'); + if ((absTick & 0x80000) !== 0) ratio = mulShift(ratio, '0x48a170391f7dc42444e8fa2'); + if (tick > 0) ratio = JSBI.divide(MaxUint256, ratio); + // back to Q96 + return JSBI.greaterThan(JSBI.remainder(ratio, Q32), ZERO) ? JSBI.add(JSBI.divide(ratio, Q32), ONE) : JSBI.divide(ratio, Q32); +} + +function mulShift(val, mulBy) { + return JSBI.signedRightShift(JSBI.multiply(val, JSBI.BigInt(mulBy)), JSBI.BigInt(128)); +} + +module.exports = { + ethereum: { + tvl: chainTvl('ethereum'), + methodology: 'This adapter counts tokens held by all PanopticPool contracts created by the PanopticFactory, as well as the token composition of all Uniswap liquidity held by the SemiFungiblePositionManager (which is used by every PanopticPool to manage liquidity).', + start: 1734049391, + }, +} \ No newline at end of file From abc881976000e481bb40dab3d51da9852dce0a43 Mon Sep 17 00:00:00 2001 From: dyedm1 Date: Wed, 18 Dec 2024 23:19:14 -0500 Subject: [PATCH 2/5] fix: jsbi -> native bigint --- package-lock.json | 9 +-------- package.json | 1 - projects/panoptic/index.js | 22 ++++++++++------------ 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index 46d5b02e8efd..03029eeeadfa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,6 @@ "graphql-request": "^4.0.0", "hi-base32": "^0.5.1", "js-sha512": "^0.8.0", - "jsbi": "^4.3.0", "limiter": "2.1.0", "miscreant": "^0.3.2", "p-limit": "^3.1.0", @@ -3348,12 +3347,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbi": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/jsbi/-/jsbi-4.3.0.tgz", - "integrity": "sha512-SnZNcinB4RIcnEyZqFPdGPVgrg2AcnykiBy0sHVJQKHYeaLUvi3Exj+iaPpLnFVkDPZIV4U0yvgC9/R4uEAZ9g==", - "license": "Apache-2.0" - }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -4172,4 +4165,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index 95141d08a0fd..16a0dbca56c7 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,6 @@ "graphql-request": "^4.0.0", "hi-base32": "^0.5.1", "js-sha512": "^0.8.0", - "jsbi": "^4.3.0", "limiter": "2.1.0", "miscreant": "^0.3.2", "p-limit": "^3.1.0", diff --git a/projects/panoptic/index.js b/projects/panoptic/index.js index 7ffbb38907e8..39cc13836365 100644 --- a/projects/panoptic/index.js +++ b/projects/panoptic/index.js @@ -1,7 +1,5 @@ const sdk = require('@defillama/sdk') const { getLogs } = require('../helper/cache/getLogs') -const JSBI = require('jsbi'); - const FACTORY = '0x000000000000010a1DEc6c46371A28A071F8bb01' const SFPM = '0x0000000000000DEdEDdD16227aA3D836C5753194' @@ -119,8 +117,8 @@ function chainTvl(chain) { let extraTokens1 = 0n for (let [key, liquidity] of Object.entries(sfpmOwnedLiquiditiesForMarket)) { - const sqrtLower = BigInt(getSqrtRatioAtTick(Number(key.split("-")[0])).toString()) - const sqrtUpper = BigInt(getSqrtRatioAtTick(Number(key.split("-")[1])).toString()) + const sqrtLower = getSqrtRatioAtTick(Number(key.split("-")[0])) + const sqrtUpper = getSqrtRatioAtTick(Number(key.split("-")[1])) const [amount0, amount1] = getAmountsForLiquidity(BigInt(sqrtPriceX96), liquidity, sqrtLower, sqrtUpper) extraTokens0 += amount0 @@ -206,12 +204,12 @@ function getAmountsForLiquidity( } function getSqrtRatioAtTick(tick) { - const MaxUint256 = JSBI.BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'); - const Q32 = JSBI.BigInt('0x100000000'); - const ZERO = JSBI.BigInt(0); - const ONE = JSBI.BigInt(1); + const MaxUint256 = BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'); + const Q32 = BigInt('0x100000000'); + const ZERO = BigInt(0); + const ONE = BigInt(1); var absTick = tick < 0 ? tick * -1 : tick; - var ratio = (absTick & 0x1) !== 0 ? JSBI.BigInt('0xfffcb933bd6fad37aa2d162d1a594001') : JSBI.BigInt('0x100000000000000000000000000000000'); + var ratio = (absTick & 0x1) !== 0 ? BigInt('0xfffcb933bd6fad37aa2d162d1a594001') : BigInt('0x100000000000000000000000000000000'); if ((absTick & 0x2) !== 0) ratio = mulShift(ratio, '0xfff97272373d413259a46990580e213a'); if ((absTick & 0x4) !== 0) ratio = mulShift(ratio, '0xfff2e50f5f656932ef12357cf3c7fdcc'); if ((absTick & 0x8) !== 0) ratio = mulShift(ratio, '0xffe5caca7e10e4e61c3624eaa0941cd0'); @@ -231,13 +229,13 @@ function getSqrtRatioAtTick(tick) { if ((absTick & 0x20000) !== 0) ratio = mulShift(ratio, '0x5d6af8dedb81196699c329225ee604'); if ((absTick & 0x40000) !== 0) ratio = mulShift(ratio, '0x2216e584f5fa1ea926041bedfe98'); if ((absTick & 0x80000) !== 0) ratio = mulShift(ratio, '0x48a170391f7dc42444e8fa2'); - if (tick > 0) ratio = JSBI.divide(MaxUint256, ratio); + if (tick > 0) ratio = MaxUint256 /ratio; // back to Q96 - return JSBI.greaterThan(JSBI.remainder(ratio, Q32), ZERO) ? JSBI.add(JSBI.divide(ratio, Q32), ONE) : JSBI.divide(ratio, Q32); + return ratio % Q32 > ZERO ? ratio / Q32 + ONE : ratio / Q32; } function mulShift(val, mulBy) { - return JSBI.signedRightShift(JSBI.multiply(val, JSBI.BigInt(mulBy)), JSBI.BigInt(128)); + return (val * BigInt(mulBy)) >> BigInt(128); } module.exports = { From a098d281cb3e0240e4590f18bfa809bc78efb8d8 Mon Sep 17 00:00:00 2001 From: dyed Date: Wed, 18 Dec 2024 23:26:03 -0500 Subject: [PATCH 3/5] Discard changes to package-lock.json --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 03029eeeadfa..177f1400cc6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4165,4 +4165,4 @@ } } } -} \ No newline at end of file +} From 4d7b0e1e8ae5af726d93c24436f0b075a91f1208 Mon Sep 17 00:00:00 2001 From: dyedm1 Date: Thu, 19 Dec 2024 13:17:40 -0500 Subject: [PATCH 4/5] feat: retrieve chunks from subgraph --- projects/panoptic/index.js | 70 ++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/projects/panoptic/index.js b/projects/panoptic/index.js index 39cc13836365..12f0ddddfa89 100644 --- a/projects/panoptic/index.js +++ b/projects/panoptic/index.js @@ -1,5 +1,6 @@ const sdk = require('@defillama/sdk') const { getLogs } = require('../helper/cache/getLogs') +const { cachedGraphQuery } = require("../helper/cache"); const FACTORY = '0x000000000000010a1DEc6c46371A28A071F8bb01' const SFPM = '0x0000000000000DEdEDdD16227aA3D836C5753194' @@ -9,9 +10,27 @@ const startBlocks = { const Q96 = BigInt(2) ** BigInt(96) +const SFPMChunksQuery = ` +query SFPMChunks($V3Pool: String) { + chunks(where: {pool: $V3Pool}) { + netLiquidity + tickLower + tickUpper + } +}` + +const config = { + ethereum: { + graphUrl: 'https://api.goldsky.com/api/public/project_cl9gc21q105380hxuh8ks53k3/subgraphs/panoptic-subgraph-mainnet/1.0.2/gn', + startBlock: 21389983, + safeBlockLimit: 50 + } +} + function chainTvl(chain) { return async (api) => { - const START_BLOCK = startBlocks[chain] + const START_BLOCK = config[chain].startBlock + const poolDeployedLogs = ( await getLogs({ api, @@ -54,9 +73,7 @@ function chainTvl(chain) { chain, }) - token0Results.output.forEach((call, i) => { - poolData[call.input.target].token0 = call.output - }) + token0Results.output.forEach((call) => poolData[call.input.target].token0 = call.output) const token1Results = await sdk.api.abi.multiCall({ abi: "function token1() view returns (address)", @@ -65,9 +82,7 @@ function chainTvl(chain) { chain, }) - token1Results.output.forEach((call, i) => { - poolData[call.input.target].token1 = call.output - }) + token1Results.output.forEach((call) => poolData[call.input.target].token1 = call.output) // Create balance calls for both tokens of each market const balanceCalls = [] @@ -76,34 +91,8 @@ function chainTvl(chain) { // Iterate through markets array directly for (let [V3Pool, poolDataEntry] of Object.entries(poolData)) { - const mintLogs = ( - await getLogs({ - api, - target: V3Pool, - fromBlock: START_BLOCK, - extraKey: "mintCache", - eventAbi: `event Mint(address sender,address indexed owner,int24 indexed tickLower,int24 indexed tickUpper,uint128 amount,uint256 amount0,uint256 amount1)`, - topics: ["0x7a53080ba414158be7ec69b987b5fb7d07dee101fe85488f0853ae16239d0bde","0x"+"000000000000000000000000"+SFPM.slice(2)] - }) - ) - const burnLogs = ( - await getLogs({ - api, - target: V3Pool, - fromBlock: START_BLOCK, - extraKey: "burnCache", - eventAbi: `event Burn(address indexed owner,int24 indexed tickLower,int24 indexed tickUpper,uint128 amount,uint256 amount0,uint256 amount1)`, - topics: ["0x0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c","0x"+"000000000000000000000000"+SFPM.slice(2)] - }) - ) + const chunks = await cachedGraphQuery(`panoptic/sfpm-chunks/${V3Pool}`, config[chain].graphUrl, SFPMChunksQuery, { api, useBlock: true, fetchById: true, safeBlockLimit: config[chain].safeBlockLimit, variables: { V3Pool } }) - let sfpmOwnedLiquiditiesForMarket = {} - - mintLogs.forEach((log) => { - const key = log.args.tickLower.toString()+"-"+log.args.tickUpper.toString() - sfpmOwnedLiquiditiesForMarket[key] = (sfpmOwnedLiquiditiesForMarket?.[key] ?? 0n) + log.args.amount}) - burnLogs.forEach((log) => sfpmOwnedLiquiditiesForMarket[log.args.tickLower.toString()+"-"+log.args.tickUpper.toString()] -= log.args.amount) - const sqrtPriceX96 = ( await sdk.api.abi.call({ target: V3Pool, @@ -116,14 +105,15 @@ function chainTvl(chain) { let extraTokens0 = 0n let extraTokens1 = 0n - for (let [key, liquidity] of Object.entries(sfpmOwnedLiquiditiesForMarket)) { - const sqrtLower = getSqrtRatioAtTick(Number(key.split("-")[0])) - const sqrtUpper = getSqrtRatioAtTick(Number(key.split("-")[1])) + chunks.forEach((chunk) => { + const sqrtLower = getSqrtRatioAtTick(Number(chunk.tickLower)) + const sqrtUpper = getSqrtRatioAtTick(Number(chunk.tickUpper)) + + const [amount0, amount1] = getAmountsForLiquidity(BigInt(sqrtPriceX96), BigInt(chunk.netLiquidity), sqrtLower, sqrtUpper) - const [amount0, amount1] = getAmountsForLiquidity(BigInt(sqrtPriceX96), liquidity, sqrtLower, sqrtUpper) extraTokens0 += amount0 extraTokens1 += amount1 - } + }) LiquidityOwnedTokens.push(extraTokens0) LiquidityOwnedTokens.push(extraTokens1) @@ -242,6 +232,6 @@ module.exports = { ethereum: { tvl: chainTvl('ethereum'), methodology: 'This adapter counts tokens held by all PanopticPool contracts created by the PanopticFactory, as well as the token composition of all Uniswap liquidity held by the SemiFungiblePositionManager (which is used by every PanopticPool to manage liquidity).', - start: 1734049391, + start: 1734049991, }, } \ No newline at end of file From 14905fd07253bcf64bf6779da1b5fcec0016b1d3 Mon Sep 17 00:00:00 2001 From: dyedm1 Date: Thu, 19 Dec 2024 13:26:05 -0500 Subject: [PATCH 5/5] docs: add note about pagination --- projects/panoptic/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/projects/panoptic/index.js b/projects/panoptic/index.js index 12f0ddddfa89..3472baddcfa2 100644 --- a/projects/panoptic/index.js +++ b/projects/panoptic/index.js @@ -12,7 +12,7 @@ const Q96 = BigInt(2) ** BigInt(96) const SFPMChunksQuery = ` query SFPMChunks($V3Pool: String) { - chunks(where: {pool: $V3Pool}) { + chunks(first: 1000, where: {pool: $V3Pool}) { netLiquidity tickLower tickUpper @@ -91,6 +91,7 @@ function chainTvl(chain) { // Iterate through markets array directly for (let [V3Pool, poolDataEntry] of Object.entries(poolData)) { + // @TODO in the unlikely event that we have >1000 unique chunks on a single pool, this query can be paginated so the TVL isn't underestimated const chunks = await cachedGraphQuery(`panoptic/sfpm-chunks/${V3Pool}`, config[chain].graphUrl, SFPMChunksQuery, { api, useBlock: true, fetchById: true, safeBlockLimit: config[chain].safeBlockLimit, variables: { V3Pool } }) const sqrtPriceX96 = (