From a4a3a85fdc736880e69b7b88ed98aa270579493b Mon Sep 17 00:00:00 2001 From: openhands Date: Fri, 27 Feb 2026 05:47:51 +0000 Subject: [PATCH] fix: Ponder: fix mintNextHourProjected divisor, dead param, dead code (#308) --- kraiken-lib/package-lock.json | 17 +++++++++++++++-- kraiken-lib/src/subgraph.ts | 14 -------------- services/ponder/package-lock.json | 8 ++++---- services/ponder/src/helpers/stats.ts | 10 +++++----- services/ponder/src/lm.ts | 2 +- services/ponder/tests/stats.test.ts | 12 ++++++------ 6 files changed, 31 insertions(+), 32 deletions(-) diff --git a/kraiken-lib/package-lock.json b/kraiken-lib/package-lock.json index 58c0c9e..2c47f7c 100644 --- a/kraiken-lib/package-lock.json +++ b/kraiken-lib/package-lock.json @@ -226,6 +226,7 @@ "integrity": "sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.2", @@ -2742,6 +2743,7 @@ "integrity": "sha512-F1CBxgqwOMc4GKJ7eY22hWhBVQuMYTtqI8L0FcszYcpYX0fzfDGpez22Xau8Mgm7O9fI+zA/TYIdq3tGWfweBA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.13.0" } @@ -2802,6 +2804,7 @@ "integrity": "sha512-TGf22kon8KW+DeKaUmOibKWktRY8b2NSAZNdtWh798COm1NWx8+xJ6iFBtk3IvLdv6+LGLJLRlyhrhEDZWargQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.45.0", "@typescript-eslint/types": "8.45.0", @@ -3413,6 +3416,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3737,6 +3741,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001587", "electron-to-chromium": "^1.4.668", @@ -4525,6 +4530,7 @@ "integrity": "sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -5222,6 +5228,7 @@ "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", "license": "MIT", + "peer": true, "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -5304,8 +5311,9 @@ "version": "5.16.0", "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.16.0.tgz", "integrity": "sha512-Ju2RCU2dQMgSKtArPbEtsK5gNLnsQyTNIo/T7cZNp96niC1x0KdJNZV0TIoilceBPQwfb5itrGl8pkFeOUMl4A==", - "dev": true, + "devOptional": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -7212,6 +7220,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -8146,8 +8155,9 @@ "version": "5.4.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -8354,6 +8364,7 @@ "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -8452,6 +8463,7 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", @@ -8667,6 +8679,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", "license": "MIT", + "peer": true, "engines": { "node": ">=10.0.0" }, diff --git a/kraiken-lib/src/subgraph.ts b/kraiken-lib/src/subgraph.ts index f8c418b..fe7fe23 100644 --- a/kraiken-lib/src/subgraph.ts +++ b/kraiken-lib/src/subgraph.ts @@ -1,10 +1,4 @@ export function bytesToUint256LittleEndian(bytes: Uint8Array): bigint { - // console.log(hexString); - // const cleanHexString = hexString.startsWith('0x') ? hexString.substring(2) : hexString; - // const bytes = new Uint8Array(Math.ceil(cleanHexString.length / 2)); - // for (let i = 0, j = 0; i < cleanHexString.length; i += 2, j++) { - // bytes[j] = parseInt(cleanHexString.slice(i, i + 2), 16); - // } let value: bigint = 0n; for (let i = bytes.length - 1; i >= 0; i--) { @@ -20,12 +14,4 @@ export function uint256ToBytesLittleEndian(value: bigint): Uint8Array { bytes[i] = Number((value >> (8n * BigInt(i))) & 0xffn); } return bytes; - // let hexString = '0x'; - - // for (let i = 0; i < bytes.length; i++) { - // // Convert each byte to a hexadecimal string and pad with zero if needed - // hexString += bytes[i].toString(16).padStart(2, '0'); - // } - - // return hexString; } diff --git a/services/ponder/package-lock.json b/services/ponder/package-lock.json index 62fdf02..57f6040 100644 --- a/services/ponder/package-lock.json +++ b/services/ponder/package-lock.json @@ -45,17 +45,17 @@ "@graphql-codegen/typescript": "^4.0.6", "@graphql-codegen/typescript-operations": "^4.2.0", "@graphql-typed-document-node/core": "^3.2.0", - "@types/jest": "^29.5.12", "@types/node": "^24.6.0", "@typescript-eslint/eslint-plugin": "^8.45.0", "@typescript-eslint/parser": "^8.45.0", + "@vitest/coverage-v8": "^3.0.0", "eslint": "^9.36.0", "husky": "^9.1.7", - "jest": "^29.7.0", "lint-staged": "^16.2.3", + "picomatch": "^4.0.3", "prettier": "^3.6.2", - "ts-jest": "^29.1.2", - "typescript": "^5.4.3" + "typescript": "^5.4.3", + "vitest": "^3.0.0" } }, "node_modules/@adraffy/ens-normalize": { diff --git a/services/ponder/src/helpers/stats.ts b/services/ponder/src/helpers/stats.ts index dd60132..7d9bff9 100644 --- a/services/ponder/src/helpers/stats.ts +++ b/services/ponder/src/helpers/stats.ts @@ -92,11 +92,11 @@ function computeProjections(ringBuffer: bigint[], pointer: number, timestamp: bi const project = (current: bigint, previous: bigint, weekly: bigint) => { if (elapsedSeconds === 0n) { - return weekly / 7n; + return weekly / 168n; } const projectedTotal = (current * BigInt(SECONDS_IN_HOUR)) / elapsedSeconds; const medium = (previous + projectedTotal) / 2n; - return medium > 0n ? medium : weekly / 7n; + return medium > 0n ? medium : weekly / 168n; }; const mintProjection = project(ringBuffer[currentBase + 1], ringBuffer[previousBase + 1], metrics.mintedWeek); @@ -259,8 +259,8 @@ export async function updateHourlyData(context: StatsContext, timestamp: bigint) ethReserveLastWeek: metrics.ethReserveLatest > 0n ? metrics.ethReserveLatest - metrics.ethReserve7dAgo : 0n, netSupplyChangeDay: metrics.mintedDay - metrics.burnedDay, netSupplyChangeWeek: metrics.mintedWeek - metrics.burnedWeek, - mintNextHourProjected: metrics.mintedWeek / 7n, - burnNextHourProjected: metrics.burnedWeek / 7n, + mintNextHourProjected: metrics.mintedWeek / 168n, + burnNextHourProjected: metrics.burnedWeek / 168n, }); } else { const metrics = computeMetrics(ringBuffer, pointer); @@ -325,7 +325,7 @@ export async function refreshOutstandingStake(context: StatsContext) { * Record ETH reserve snapshot in ring buffer slot 0. * Called from lm.ts on Recentered events (where we know the pool's ETH balance). */ -export async function recordEthReserveSnapshot(context: StatsContext, timestamp: bigint, ethBalance: bigint) { +export async function recordEthReserveSnapshot(context: StatsContext, ethBalance: bigint) { const statsData = await context.db.find(stats, { id: STATS_ID }); if (!statsData) return; diff --git a/services/ponder/src/lm.ts b/services/ponder/src/lm.ts index 327f17d..904c76c 100644 --- a/services/ponder/src/lm.ts +++ b/services/ponder/src/lm.ts @@ -189,7 +189,7 @@ async function updateReserveStats( vwapTick: number | bigint ) { // Record ETH reserve in ring buffer for hourly time-series - await recordEthReserveSnapshot(context, event.block.timestamp, ethBalance); + await recordEthReserveSnapshot(context, ethBalance); // Compute 7d growth from ring buffer (slot 0 = ethReserve snapshots) const statsData = await context.db.find(stats, { id: STATS_ID }); diff --git a/services/ponder/tests/stats.test.ts b/services/ponder/tests/stats.test.ts index 4efa3dd..58c81fa 100644 --- a/services/ponder/tests/stats.test.ts +++ b/services/ponder/tests/stats.test.ts @@ -291,14 +291,14 @@ describe('updateHourlyData', () => { // Filled slots: i=2..49 from pointer=7 (48 slots × 10n minted / 5n burned). // mintedLastDay: i<24 → i=2..23 = 22 slots × 10n = 220n // mintedLastWeek: 48 × 10n = 480n - // mintNextHourProjected = mintedWeek / 7n = 480n / 7n = 68n (BigInt truncation) - // burnNextHourProjected = burnedWeek / 7n = 240n / 7n = 34n + // mintNextHourProjected = mintedWeek / 168n = 480n / 168n = 2n (BigInt truncation) + // burnNextHourProjected = burnedWeek / 168n = 240n / 168n = 1n expect(setArg.mintedLastWeek).toBe(480n); expect(setArg.mintedLastDay).toBe(220n); expect(setArg.burnedLastWeek).toBe(240n); expect(setArg.burnedLastDay).toBe(110n); - expect(setArg.mintNextHourProjected).toBe(68n); - expect(setArg.burnNextHourProjected).toBe(34n); + expect(setArg.mintNextHourProjected).toBe(2n); + expect(setArg.burnNextHourProjected).toBe(1n); expect(setArg.netSupplyChangeDay).toBe(110n); expect(setArg.netSupplyChangeWeek).toBe(240n); }); @@ -399,7 +399,7 @@ describe('updateHourlyData', () => { describe('recordEthReserveSnapshot', () => { it('returns early when no stats row exists', async () => { const ctx = createMockContext(null); - await recordEthReserveSnapshot(ctx, 1000n, 500n); + await recordEthReserveSnapshot(ctx, 500n); expect((ctx as unknown as { db: { update: ReturnType } }).db.update).not.toHaveBeenCalled(); }); @@ -409,7 +409,7 @@ describe('recordEthReserveSnapshot', () => { const ctx = createMockContext(row); const ethBalance = 12345678n; - await recordEthReserveSnapshot(ctx, 1000n, ethBalance); + await recordEthReserveSnapshot(ctx, ethBalance); const dbMock = ctx as unknown as { db: { update: ReturnType } }; const setArg = (dbMock.db.update as ReturnType).mock.results[0].value.set.mock.calls[0][0];