From c33bdbaad5c88c076cbb3f7b86d7d53d74da69fa Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 26 Feb 2026 22:45:40 +0000 Subject: [PATCH] fix: address review feedback on fetch-events.ts (#315) - Replace hardcoded Infura API key with INFURA_API_KEY env var; fail fast with a helpful message if unset and no --rpc-url is given - Add onchain/script/backtesting/.gitignore (cache/) instead of relying on the opaque root pattern; remove force-tracked cache/.gitkeep (mkdirSync creates the directory at runtime) - Document resume constraint: reliable only when both --start-block and --end-block are explicit, or --output is set - Fix batch-number display: derive batchNum inside the loop from the actual `from` block so it stays correct when resumeFromBlock isn't BATCH_SIZE-aligned - Guard log.logIndex === null consistently with blockNumber/transactionHash - console.warn on decode errors instead of silently discarding them Co-Authored-By: Claude Sonnet 4.6 --- onchain/script/backtesting/.gitignore | 2 + onchain/script/backtesting/cache/.gitkeep | 0 onchain/script/backtesting/fetch-events.ts | 43 ++++++++++++++++------ 3 files changed, 34 insertions(+), 11 deletions(-) create mode 100644 onchain/script/backtesting/.gitignore delete mode 100644 onchain/script/backtesting/cache/.gitkeep diff --git a/onchain/script/backtesting/.gitignore b/onchain/script/backtesting/.gitignore new file mode 100644 index 0000000..7663573 --- /dev/null +++ b/onchain/script/backtesting/.gitignore @@ -0,0 +1,2 @@ +# Cache files generated by fetch-events.ts at runtime — do not commit +cache/ diff --git a/onchain/script/backtesting/cache/.gitkeep b/onchain/script/backtesting/cache/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/onchain/script/backtesting/fetch-events.ts b/onchain/script/backtesting/fetch-events.ts index 1e00001..e770871 100644 --- a/onchain/script/backtesting/fetch-events.ts +++ b/onchain/script/backtesting/fetch-events.ts @@ -7,6 +7,13 @@ * npx tsx fetch-events.ts --pool 0x0d59... --days 7 * npx tsx fetch-events.ts --pool 0x0d59... --start-block 12345678 --end-block 12989078 * npx tsx fetch-events.ts --pool 0x0d59... --days 7 --output /tmp/events.jsonl + * + * Requires the INFURA_API_KEY environment variable unless --rpc-url is given. + * + * NOTE: Resume (re-run with the same flags) only works reliably when both + * --start-block and --end-block are provided, or when --output is explicit. + * Without --end-block the output filename embeds the runtime latestBlock, + * which changes on subsequent runs and creates a new file instead of resuming. */ import { createPublicClient, http, parseAbi, decodeEventLog } from "viem"; @@ -20,8 +27,19 @@ import { fileURLToPath } from "url"; // Constants // --------------------------------------------------------------------------- -const DEFAULT_INFURA_URL = - "https://base-mainnet.infura.io/v3/409c42ecaa4e405bb5735faac0f7aec2"; +/** Build the default RPC URL from the INFURA_API_KEY environment variable. */ +function buildDefaultRpcUrl(): string { + const key = process.env.INFURA_API_KEY; + if (!key) { + console.error( + "Error: INFURA_API_KEY environment variable is not set.\n" + + " Set it with: export INFURA_API_KEY=\n" + + " or pass --rpc-url to use a different RPC endpoint." + ); + process.exit(1); + } + return `https://base-mainnet.infura.io/v3/${key}`; +} /** Base mainnet produces ~1 block every 2 seconds → ~43 200 blocks/day. */ const BASE_BLOCKS_PER_DAY = 43_200; @@ -88,7 +106,7 @@ function parseArgs(): Args { startBlock: startBlockRaw !== undefined ? parseInt(startBlockRaw, 10) : null, endBlock: endBlockRaw !== undefined ? parseInt(endBlockRaw, 10) : null, output: getFlag("--output") ?? null, - rpcUrl: getFlag("--rpc-url") ?? DEFAULT_INFURA_URL, + rpcUrl: getFlag("--rpc-url") ?? buildDefaultRpcUrl(), }; } @@ -208,15 +226,14 @@ async function main(): Promise { // Fetch in batches // ------------------------------------------------------------------ const totalBatches = Math.ceil((endBlock - startBlock + 1) / BATCH_SIZE); - // Batch index that corresponds to resumeFromBlock (1-based for display) - const startBatchNum = - Math.floor((resumeFromBlock - startBlock) / BATCH_SIZE) + 1; let totalEvents = 0; - let batchNum = startBatchNum; for (let from = resumeFromBlock; from <= endBlock; from += BATCH_SIZE) { const to = Math.min(from + BATCH_SIZE - 1, endBlock); + // Derive batch number from actual `from` position so it stays correct + // even when resumeFromBlock is not aligned to a BATCH_SIZE boundary. + const batchNum = Math.floor((from - startBlock) / BATCH_SIZE) + 1; process.stdout.write(`Fetching blocks ${from}-${to}... `); @@ -256,7 +273,7 @@ async function main(): Promise { let batchEvents = 0; for (const log of logs) { - if (log.blockNumber === null || log.transactionHash === null) continue; + if (log.blockNumber === null || log.transactionHash === null || log.logIndex === null) continue; try { const decoded = decodeEventLog({ @@ -276,13 +293,17 @@ async function main(): Promise { appendFileSync(outputPath, JSON.stringify(entry) + "\n"); batchEvents++; totalEvents++; - } catch { - // Skip any log we cannot decode (shouldn't happen for our known pool) + } catch (err) { + // Decode failure is unexpected for a filtered-by-address+topic0 log; + // warn so any ABI drift is visible rather than silently discarded. + console.warn( + `Warning: could not decode log tx=${log.transactionHash} logIndex=${log.logIndex}:`, + err instanceof Error ? err.message : err + ); } } console.log(`${batchEvents} events (${batchNum}/${totalBatches} batches)`); - batchNum++; // Polite inter-batch delay (skip after last batch) if (from + BATCH_SIZE <= endBlock) {