=============== LIBRARY RULES =============== From library maintainers: - Consider to use the bundled cache bootstrap to deliver fast first-load performance ### Fork Testing Setup Source: https://github.com/gzeoneth/gov-tracker/blob/main/CONTRIBUTING.md Instructions for setting up and running fork tests, which utilize Anvil to simulate blockchain states at historical blocks. Requires Foundry installation and archive RPC access. ```bash # Requires Foundry installed (`curl -L https://foundry.paradigm.xyz | bash && foundryup`) # Requires `ARB1_ARCHIVE_RPC` with archive node access yarn test:fork ``` -------------------------------- ### Installing Beta Releases Source: https://github.com/gzeoneth/gov-tracker/blob/main/CONTRIBUTING.md How to install a beta version of the Gov-Tracker package from npm. Beta releases are automatically published on every merge to the `main` branch and have versions like `X.Y.Z-beta.`. ```bash npm install @gzeoneth/gov-tracker@beta ``` -------------------------------- ### Install @gzeoneth/gov-tracker and ethers Source: https://github.com/gzeoneth/gov-tracker/blob/main/README.md Installs the gov-tracker package and a specific version of ethers.js using yarn. This is a prerequisite for using the library in your project. ```bash yarn add @gzeoneth/gov-tracker ethers@^5.8.0 ``` -------------------------------- ### Verifying Package Installation Source: https://github.com/gzeoneth/gov-tracker/blob/main/CONTRIBUTING.md Commands to verify the installed version of the Gov-Tracker package and check its command-line interface help output. ```bash npm view @gzeoneth/gov-tracker npx @gzeoneth/gov-tracker --help ``` -------------------------------- ### Installing Alpha Releases Source: https://github.com/gzeoneth/gov-tracker/blob/main/CONTRIBUTING.md How to install an alpha version of the Gov-Tracker package from npm. Alpha releases are for feature branch testing and have versions like `X.Y.Z-alpha..`. ```bash npm install @gzeoneth/gov-tracker@alpha ``` -------------------------------- ### Initialize Tracker with Custom Cache Adapter Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Demonstrates initializing the gov-tracker with a custom cache adapter, `IndexedDBCache`, which implements the `CacheAdapter` interface. This allows for flexible cache storage solutions. Imports `CacheAdapter` and `createTracker`. ```typescript import { CacheAdapter, createTracker } from "@gzeoneth/gov-tracker"; class IndexedDBCache implements CacheAdapter { async get(key: string): Promise { /* ... */ } async set(key: string, value: T): Promise { /* ... */ } async delete(key: string): Promise { /* ... */ } async clear(): Promise { /* ... */ } async has(key: string): Promise { /* ... */ } async keys(prefix?: string): Promise { /* ... */ } } const tracker = createTracker({ l2Provider, l1Provider, novaProvider, cache: new IndexedDBCache(), }); ``` -------------------------------- ### Clone and Install Dependencies Source: https://github.com/gzeoneth/gov-tracker/blob/main/CONTRIBUTING.md This snippet shows how to clone the Gov-Tracker repository and install its Node.js dependencies using Yarn. ```bash git clone https://github.com/gzeoneth/gov-tracker.git cd gov-tracker yarn install ``` -------------------------------- ### Initialize Tracker with LocalStorageCache (Browser) Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Initializes the gov-tracker for browser environments using `LocalStorageCache` with a custom prefix. Cached stages are automatically restored on page reload. Imports `createTracker` and `LocalStorageCache`. ```typescript import { createTracker, LocalStorageCache } from "@gzeoneth/gov-tracker"; const tracker = createTracker({ l2Provider, l1Provider, novaProvider, cache: new LocalStorageCache("arb-gov:"), // Custom prefix }); // Cached stages restore automatically on page reload const results = await tracker.trackByTxHash(txHash); ``` -------------------------------- ### Execute All Ready Stages with Gov-Tracker Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Iterates through all executable stages found by `findAllExecutableStages` and prepares/sends transactions for them. It handles different chain types for signer selection. Requires `findAllExecutableStages`, `tracker.prepareTransaction`, and signer objects. ```typescript import { findAllExecutableStages } from "@gzeoneth/gov-tracker"; for (const stage of findAllExecutableStages(result.stages)) { const prep = await tracker.prepareTransaction(stage); if (prep.success) { const signer = stage.chain === "ethereum" ? l1Signer : l2Signer; await signer.sendTransaction(prep.prepared); } } ``` -------------------------------- ### Execute Ready Stage of a Proposal Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Finds an executable stage for a given proposal result, prepares the transaction for that stage, and sends it using a signer if preparation is successful. It requires the `result` object from tracking and a `signer`. Imports `findExecutableStage`. ```typescript import { findExecutableStage } from "@gzeoneth/gov-tracker"; const readyStage = findExecutableStage(result.stages); if (readyStage) { const prep = await tracker.prepareTransaction(readyStage); if (prep.success) { const tx = await signer.sendTransaction(prep.prepared); await tx.wait(); } } ``` -------------------------------- ### Gov-Tracker CLI Usage Examples (Bash) Source: https://context7.com/gzeoneth/gov-tracker/llms.txt This section outlines various commands for the Gov-Tracker command-line interface. It covers tracking proposals, inspecting calldata, running discovery, executing stages, managing elections, and using the interactive TUI. Environment variables for RPC endpoints and private keys are also mentioned. ```bash # Track a proposal by transaction hash npx @gzeoneth/gov-tracker track 0x91226f5bfad5d1c0911ed590287734241f6b3101d8b60970911987dfa74fe37e # Track with decoded calldata inspection npx @gzeoneth/gov-tracker track 0x... --inspect # Decode calldata only (no tracking) npx @gzeoneth/gov-tracker track 0x... --inspect-only # Show simulation data for Tenderly/Foundry npx @gzeoneth/gov-tracker track 0x... --show-simulation # Execute ready stages npx @gzeoneth/gov-tracker track 0x... --write --private-key $PRIVATE_KEY # Discover and track all proposals npx @gzeoneth/gov-tracker run # Selective tracking npx @gzeoneth/gov-tracker run --track-core # Constitutional only npx @gzeoneth/gov-tracker run --track-treasury # Non-constitutional only npx @gzeoneth/gov-tracker run --track-elections # Elections only npx @gzeoneth/gov-tracker run --track-timelocks # Direct timelock ops only # Election commands npx @gzeoneth/gov-tracker election # Check election status npx @gzeoneth/gov-tracker election --list # List all elections npx @gzeoneth/gov-tracker election --track 0 # Track specific election npx @gzeoneth/gov-tracker election --track 0 --details -v # With nominees/members # Interactive TUI (requires optional ink/react dependencies) npx @gzeoneth/gov-tracker ui npx @gzeoneth/gov-tracker ui --cache ./my-cache.json # Disable caching npx @gzeoneth/gov-tracker track 0x... --no-cache # Environment variables # ETH_RPC=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY # ARB1_RPC=https://arb-mainnet.g.alchemy.com/v2/YOUR_KEY # NOVA_RPC=https://nova.arbitrum.io/rpc # PRIVATE_KEY=0x... (for execution) # DISABLE_4BYTE_LOOKUP=1 (disable external API lookups) ``` -------------------------------- ### Express API Endpoint for Proposal Tracking Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md An example of an Express.js route that exposes proposal tracking data via a REST API. It takes a transaction hash as a parameter, tracks the proposal using `tracker.trackByTxHash`, and returns key information like completion status, type, and stage details. Handles 'Not Found' errors. ```typescript app.get("/api/proposal/:txHash", async (req, res) => { const results = await tracker.trackByTxHash(req.params.txHash); if (!results.length) return res.status(404).json({ error: "Not found" }); const result = results[0]; res.json({ isComplete: result.isComplete, proposalType: result.proposalType, stages: result.stages.map(s => ({ type: s.type, status: s.status, eta: s.timing?.eta })), }); }); ``` -------------------------------- ### Initialize Tracker with Bundled Cache (Node.js) Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Initializes the gov-tracker with a bundled cache file. It demonstrates two options: copying the bundled cache to a local file for persistence or using the bundled cache directly in read-only mode. Imports `createTracker` and `getBundledCachePath`. ```typescript import * as fs from "fs"; import { createTracker, getBundledCachePath } from "@gzeoneth/gov-tracker"; // Option 1: Copy bundled cache to your app's cache location (recommended) const bundledPath = getBundledCachePath(); const appCachePath = "./my-app-cache.json"; if (bundledPath && !fs.existsSync(appCachePath)) { fs.copyFileSync(bundledPath, appCachePath); console.log("Initialized cache from bundled data"); } const tracker = createTracker({ l2Provider, l1Provider, novaProvider, cachePath: appCachePath, }); // Option 2: Use bundled cache directly (read-only, new proposals won't persist) const tracker = createTracker({ l2Provider, l1Provider, novaProvider, cachePath: getBundledCachePath(), }); ``` -------------------------------- ### Initialize Tracker with Bundled Cache (Bundlers) Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Initializes the gov-tracker using a `LocalStorageCache` populated with bundled cache data for bundlers like webpack, vite, and Next.js. It includes logic to populate the cache if it hasn't been done already. Imports `createTracker` and `LocalStorageCache`. ```typescript import { createTracker, LocalStorageCache } from "@gzeoneth/gov-tracker"; import bundledCache from "@gzeoneth/gov-tracker/bundled-cache.json"; // Initialize localStorage cache with bundled data const cache = new LocalStorageCache("arb-gov:"); // Populate cache (only needed once, check if already done) if (!(await cache.has("tx:0x91226f5bfad5d1c0911ed590287734241f6b3101d8b60970911987dfa74fe37e"))) { for (const [key, checkpoint] of Object.entries(bundledCache)) { await cache.set(key, checkpoint); } console.log(`Initialized cache with ${Object.keys(bundledCache).length} entries`); } const tracker = createTracker({ l2Provider, l1Provider, novaProvider, cache, }); ``` -------------------------------- ### Configure Custom Chunk Sizes in Gov-Tracker Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Shows how to customize chunk sizes for L1 and L2 providers, as well as the delay between chunks, when creating a Gov-Tracker instance. This is particularly useful for environments with strict rate limits on RPC endpoints. It uses predefined constants from `@gzeoneth/gov-tracker`. ```typescript import { CHUNK_SIZES } from "@gzeoneth/gov-tracker"; const tracker = createTracker({ l2Provider, l1Provider, novaProvider, chunkingConfig: { l1ChunkSize: CHUNK_SIZES.L1 / 5, // Smaller for rate-limited RPCs l2ChunkSize: CHUNK_SIZES.L2 / 10, delayBetweenChunks: 200, }, }); ``` -------------------------------- ### Quick Start: Track Arbitrum DAO Governance Proposals with TypeScript Source: https://github.com/gzeoneth/gov-tracker/blob/main/README.md Demonstrates how to use the gov-tracker library in TypeScript to track governance proposals. It shows how to initialize the tracker with different network providers, track proposals by transaction hash or governor address, and execute ready stages. ```typescript import { ethers } from "ethers"; import { createTracker, findExecutableStage, ADDRESSES } from "@gzeoneth/gov-tracker"; // Use StaticJsonRpcProvider for better performance const tracker = createTracker({ l2Provider: new ethers.providers.StaticJsonRpcProvider(process.env.ARB1_RPC), l1Provider: new ethers.providers.StaticJsonRpcProvider(process.env.ETH_RPC), novaProvider: new ethers.providers.StaticJsonRpcProvider(process.env.NOVA_RPC), cachePath: "./gov-tracker-cache.json", }); // Track from transaction hash const results = await tracker.trackByTxHash("0x..."); for (const stage of results[0].stages) { console.log(`${stage.type}: ${stage.status}`); } // Or track from governor const result = await tracker.trackFromGovernor(ADDRESSES.CONSTITUTIONAL_GOVERNOR, proposalId); // Execute ready stages const readyStage = findExecutableStage(results[0].stages); if (readyStage) { const prep = await tracker.prepareTransaction(readyStage); if (prep.success) { await signer.sendTransaction(prep.prepared); } } ``` -------------------------------- ### CLI: Track Arbitrum DAO Governance Proposals Source: https://github.com/gzeoneth/gov-tracker/blob/main/README.md Provides command-line examples for tracking Arbitrum DAO governance proposals using the gov-tracker CLI. It covers basic tracking, decoding calldata, inspecting proposals, and executing ready stages with private key authentication. ```bash # Track a proposal npx @gzeoneth/gov-tracker track 0x... # Track AND decode calldata npx @gzeoneth/gov-tracker track 0x... -i # Decode calldata only (no tracking) npx @gzeoneth/gov-tracker track 0x... --inspect-only # Show simulation data npx @gzeoneth/gov-tracker track 0x... --show-simulation # Execute ready stages npx @gzeoneth/gov-tracker track 0x... -w --private-key $PRIVATE_KEY # Discover and track all proposals npx @gzeoneth/gov-tracker run # Selective tracking (only track specific types) npx @gzeoneth/gov-tracker run --track-core # Constitutional proposals only npx @gzeoneth/gov-tracker run --track-treasury # Non-constitutional proposals only npx @gzeoneth/gov-tracker run --track-elections # Election governors only npx @gzeoneth/gov-tracker run --track-timelocks # Direct timelock operations only # Track with elections enabled in run loop npx @gzeoneth/gov-tracker run --loop --election # Disable caching npx @gzeoneth/gov-tracker track 0x... --no-cache # Track election creation tx (auto-switches to election view) npx @gzeoneth/gov-tracker track 0x82a0baf3... ``` -------------------------------- ### CLI: Interactive TUI for Browsing Proposals Source: https://github.com/gzeoneth/gov-tracker/blob/main/README.md Shows how to launch the interactive terminal user interface (TUI) for browsing cached governance proposals. It includes examples for using the default cache and a custom cache file, along with a description of its features and navigation keys. ```bash # Browse proposals (uses bundled cache, no RPC required) npx @gzeoneth/gov-tracker ui # Use custom cache file npx @gzeoneth/gov-tracker ui --cache ./my-cache.json ``` -------------------------------- ### Discord/Telegram Notifications for Incomplete Checkpoints Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Sets up a recurring interval to check for incomplete checkpoints using `tracker.queryIncompleteCheckpoints`. If incomplete checkpoints are found and require action, it identifies the next executable stage and sends a notification. This enables real-time alerts for governance actions. ```typescript async function checkAndNotify() { const incomplete = await tracker.queryIncompleteCheckpoints(); for (const { checkpoint } of incomplete) { const result = await tracker.trackFromCheckpoint(checkpoint); if (needsAction(result)) { const stage = findExecutableStage(result.stages); await sendNotification(`Stage ${stage?.type} ready on ${stage?.chain}`); } } } setInterval(checkAndNotify, 5 * 60 * 1000); ``` -------------------------------- ### Calculate Governance Timing and Use Constants (TypeScript) Source: https://context7.com/gzeoneth/gov-tracker/llms.txt This snippet demonstrates how to use the Gov-tracker SDK to calculate Estimated Time of Arrivals (ETAs) for governance stages and remaining time until those ETAs. It also shows how to access and log timing constants like timelock delays and challenge periods. Ensure the '@gzeoneth/gov-tracker' package is installed. ```typescript import { calculateEta, calculateExpectedEta, calculateRemainingSeconds, invalidateBlockInfoCache, TIMING, GOVERNANCE_STAGE_DURATION_DAYS, } from "@gzeoneth/gov-tracker"; // Calculate ETA for a future block const eta = await calculateEta(targetBlockNumber, l2Provider); console.log(`ETA: ${new Date(eta * 1000).toISOString()}`); // Calculate remaining time until ETA const secondsRemaining = calculateRemainingSeconds(eta); console.log(`Time remaining: ${Math.floor(secondsRemaining / 3600)} hours`); // Reference timing constants console.log(`L2 Constitutional delay: ${TIMING.L2_CONSTITUTIONAL_TIMELOCK_DELAY_SECONDS / 86400} days`); console.log(`Challenge period: ${TIMING.CHALLENGE_PERIOD_BLOCKS_L1} L1 blocks`); console.log(`Total constitutional duration: ~${GOVERNANCE_STAGE_DURATION_DAYS.TOTAL_ONCHAIN_CONSTITUTIONAL} days`); // Invalidate block info cache at start of monitoring loops invalidateBlockInfoCache(); ``` -------------------------------- ### Discover and Monitor Proposals and Timelock Operations Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Discovers all proposals and timelock operations from default targets up to the current block number. It then iterates through discovered proposals, tracks them by hash, and checks if action is needed. It also re-checks incomplete items from the cache. Imports `buildDefaultTargets` and `needsAction`. ```typescript import { buildDefaultTargets, needsAction } from "@gzeoneth/gov-tracker"; const currentBlock = await l2Provider.getBlockNumber(); const { proposals, timelockOps } = await tracker.discoverAll( buildDefaultTargets(), currentBlock ); // Track discovered items for (const p of proposals) { const results = await tracker.trackByTxHash(p.creationTxHash); if (needsAction(results[0])) { console.log(`Action needed: ${p.proposalId.slice(0, 10)}...`); } } // Re-check incomplete items from cache const incomplete = await tracker.queryIncompleteCheckpoints({ maxAgeDays: 60 }); for (const { checkpoint } of incomplete) { await tracker.trackFromCheckpoint(checkpoint); } ``` -------------------------------- ### Prepare Election Transactions (A→B→C) in TypeScript Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/API.md This snippet demonstrates the three-step process for managing an election lifecycle using the GovTracker library. It covers creating a nominee election, triggering the member election, and executing the member election to install new council members. It relies on the ProposalStageTracker and various preparation functions from the '@gzeoneth/gov-tracker' package. ```typescript import { ProposalStageTracker, prepareElectionCreation, prepareMemberElectionTrigger, prepareMemberElectionExecution, checkElectionStatus, } from "@gzeoneth/gov-tracker"; const tracker = new ProposalStageTracker({ l2Provider, l1Provider }); // Step A: Create nominee election (when conditions match) const status = await checkElectionStatus(l2Provider, l1Provider); if (status.canCreateElection) { const { transaction } = prepareElectionCreation(status); await signer.sendTransaction(transaction); } // Step B: Execute nominee election → creates member election const election = await tracker.trackElection(0); if (election.canProceedToMemberPhase) { const tx = await prepareMemberElectionTrigger(election, l2Provider); if (tx) await signer.sendTransaction(tx); } // Step C: Execute member election → installs new council members if (election.canExecuteMember) { const tx = await prepareMemberElectionExecution(election, l2Provider); if (tx) await signer.sendTransaction(tx); } ``` -------------------------------- ### Arbitrum Address Aliasing for L1→L2 Messages (TypeScript) Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Demonstrates how to use the Arbitrum SDK to calculate the aliased address for an L1 address, which is necessary for simulating L1 to L2 messages. The aliased address is then used as the `from` field in a simulation object. Requires the `Address` class from the Arbitrum SDK. ```typescript import { Address } from "@arbitrum/sdk/dist/lib/dataEntities/address"; // Calculate alias for any L1 address const l1Address = "0xE6841D92B0C345144506576eC13ECf5103aC7f49"; // L1 Timelock const aliasedAddress = new Address(l1Address).applyAlias().value; console.log(aliasedAddress); // 0xf6951Cd6... // Use in simulation const simulation = { networkId: "42161", // Arb1 from: aliasedAddress, // Aliased address as msg.sender to: upgradeExecutorAddress, input: executeCalldata, value: "0", }; ``` -------------------------------- ### Monitor Elections in Background (TypeScript) Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md This TypeScript code snippet demonstrates how to monitor blockchain elections in the background using the @gzeoneth/gov-tracker library. It checks for new election opportunities and actionable election phases, sending notifications to Slack. It requires L2 and L1 providers and is set to run every 5 minutes. ```typescript import { ProposalStageTracker, checkElectionStatus } from "@gzeoneth/gov-tracker"; const tracker = new ProposalStageTracker({ l2Provider, l1Provider }); async function monitorElections() { // Check for new election opportunity const status = await checkElectionStatus(l2Provider, l1Provider); if (status.canCreateElection) { await notifySlack(`Election #${status.electionCount} can be created!`); } // Check for actionable elections const elections = await tracker.trackAllElections(); for (const election of elections) { if (election.canProceedToMemberPhase) { await notifySlack(`Election #${election.electionIndex}: Ready to trigger member phase`); } if (election.canExecuteMember) { await notifySlack(`Election #${election.electionIndex}: Ready to execute member election`); } } } // Run every 5 minutes setInterval(monitorElections, 5 * 60 * 1000); ``` -------------------------------- ### Get Cache Statistics Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Retrieves and logs statistics about the number of complete and total proposals and timelocks stored in the cache. This provides insight into the cache's current state. ```typescript const stats = await tracker.getStats(); console.log(`Proposals: ${stats.proposals.complete}/${stats.proposals.total} complete`); console.log(`Timelocks: ${stats.timelocks.complete}/${stats.timelocks.total} complete`); ``` -------------------------------- ### Execute Election Actions with Gov Tracker Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Provides functions to manage the election lifecycle, including preparing and sending transactions for creating new elections, triggering member elections after vetting, and executing member elections to install new council members. ```typescript import { ProposalStageTracker, checkElectionStatus, prepareElectionCreation, prepareMemberElectionTrigger, prepareMemberElectionExecution, } from "@gzeoneth/gov-tracker"; const tracker = new ProposalStageTracker({ l2Provider, l1Provider }); // Step 1: Create new election (when time has elapsed) const status = await checkElectionStatus(l2Provider, l1Provider); if (status.canCreateElection) { const { transaction, electionIndex } = prepareElectionCreation(status); console.log(`Creating election #${electionIndex}`); const tx = await signer.sendTransaction(transaction); await tx.wait(); } // Step 2: Track and advance election phases const election = await tracker.trackElection(0); // Trigger member election (after vetting period) if (election.canProceedToMemberPhase) { const prepared = await prepareMemberElectionTrigger(election, l2Provider); if (prepared) { const tx = await signer.sendTransaction(prepared); await tx.wait(); console.log("Member election triggered"); } } // Execute member election (install new council members) if (election.canExecuteMember) { const prepared = await prepareMemberElectionExecution(election, l2Provider); if (prepared) { const tx = await signer.sendTransaction(prepared); await tx.wait(); console.log("New Security Council members installed"); } } ``` -------------------------------- ### Set Environment Variables for RPC and Private Key (Bash) Source: https://github.com/gzeoneth/gov-tracker/blob/main/README.md Configures environment variables for Ethereum RPC endpoints (e.g., Mainnet, Arbitrum One, Nova) and a private key for transaction signing. Essential for production use. ```bash ETH_RPC=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY ARB1_RPC=https://arb-mainnet.g.alchemy.com/v2/YOUR_KEY NOVA_RPC=https://nova.arbitrum.io/rpc PRIVATE_KEY=0x... # For execution ``` -------------------------------- ### Concurrent Operations with a Simple pLimit Function Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Implements a basic concurrency limiter function `pLimit` that restricts the number of concurrently running asynchronous operations. This is useful for managing API rate limits or preventing resource exhaustion. The example shows how to use it with `Promise.all` to track multiple proposals concurrently. ```typescript // Simple concurrency limiter (built into CLI, or implement your own) function pLimit(concurrency: number) { const queue: (() => void)[] = []; let active = 0; const next = () => { active--; if (queue.length > 0) queue.shift()!(); }; return (fn: () => Promise): Promise => new Promise((resolve, reject) => { const run = async () => { active++; try { resolve(await fn()); } catch (e) { reject(e); } finally { next(); } }; if (active < concurrency) run(); else queue.push(run); }); } const limit = pLimit(4); // Max 4 concurrent operations const results = await Promise.all( proposals.map(p => limit(() => tracker.trackByTxHash(p.creationTxHash))) ); ``` -------------------------------- ### Full Election Lifecycle Execution with Gov-Tracker Source: https://context7.com/gzeoneth/gov-tracker/llms.txt Orchestrates the complete lifecycle of a Security Council election, from creation through member installation. It involves checking election status, preparing nominee election creation, triggering the member election after vetting, and finally executing the member election to install new council members. Requires L2 and L1 providers, and a signer for transaction execution. ```typescript import { createTracker, checkElectionStatus, prepareElectionCreation, prepareMemberElectionTrigger, prepareMemberElectionExecution, } from "@gzeoneth/gov-tracker"; const tracker = createTracker({ l2Provider, l1Provider }); // Step A: Create nominee election (when conditions match) const status = await checkElectionStatus(l2Provider, l1Provider); if (status.canCreateElection) { const { transaction, electionIndex } = prepareElectionCreation(status); console.log(`Creating election #${electionIndex}`); const tx = await signer.sendTransaction(transaction); await tx.wait(); console.log(`Election created: ${tx.hash}`); } // Step B: Trigger member election (after vetting period) const election = await tracker.trackElection(0); if (election.canProceedToMemberPhase) { const prepared = await prepareMemberElectionTrigger(election, l2Provider); if (prepared) { const tx = await signer.sendTransaction(prepared); await tx.wait(); console.log(`Member election triggered: ${tx.hash}`); } } // Step C: Execute member election (install new council members) if (election.canExecuteMember) { const prepared = await prepareMemberElectionExecution(election, l2Provider); if (prepared) { const tx = await signer.sendTransaction(prepared); await tx.wait(); console.log(`Council members installed: ${tx.hash}`); } } ``` -------------------------------- ### Initialize ProposalStageTracker with Providers and Caching (TypeScript) Source: https://context7.com/gzeoneth/gov-tracker/llms.txt Demonstrates how to create a ProposalStageTracker instance using L1, L2, and optional Nova providers. It shows configuration for file-based caching in Node.js and localStorage caching in browser environments, along with chunking and progress callback options. ```typescript import { ethers } from "ethers"; import { createTracker, ADDRESSES } from "@gzeoneth/gov-tracker"; // Create tracker with providers and caching const tracker = createTracker({ l2Provider: new ethers.providers.StaticJsonRpcProvider(process.env.ARB1_RPC), l1Provider: new ethers.providers.StaticJsonRpcProvider(process.env.ETH_RPC), novaProvider: new ethers.providers.StaticJsonRpcProvider(process.env.NOVA_RPC), cachePath: "./gov-tracker-cache.json", // File-based cache for Node.js chunkingConfig: { l1ChunkSize: 10_000, // Blocks per chunk for L1 log searches l2ChunkSize: 10_000_000, // Blocks per chunk for L2 log searches delayBetweenChunks: 100, // ms delay between chunk queries }, onProgress: (progress) => { console.log(`Stage ${progress.stage}: ${progress.status}`); }, }); // For browser environments, use LocalStorageCache import { LocalStorageCache } from "@gzeoneth/gov-tracker"; const browserTracker = createTracker({ l2Provider, l1Provider, cache: new LocalStorageCache("arb-gov:"), // Custom prefix for localStorage keys }); ``` -------------------------------- ### Tracking Methods Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/API.md Provides various methods to track governance proposals and operations using different identifiers and starting points. ```APIDOC ## Tracking Methods ### Description Provides various methods to track governance proposals and operations using different identifiers and starting points. ### Methods - **`trackByTxHash(txHash)`** - Description: Track by transaction hash (auto-detects type, includes election status). - Returns: An array of tracked results. - **`trackFromGovernor(address, proposalId)`** - Description: Track a governor proposal by address and proposal ID. - Returns: Tracked proposal data. - **`trackFromTimelock(address, { operationId })`** - Description: Track a timelock operation by address and operation ID. - Returns: Tracked timelock operation data. - **`trackFromCheckpoint(checkpoint)`** - Description: Resume tracking from a cached checkpoint. - Returns: Tracked data from the checkpoint. - **`trackElection(electionIndex)`** - Description: Track an election by its index. - Returns: Election proposal status. ### Request Example ```typescript const results = await tracker.trackByTxHash("0x..."); const result = results[0]; console.log(result.stages, result.isComplete, result.proposalType); // Election proposals automatically include election lifecycle status if (result.isElection && result.electionStatus) { console.log(result.electionStatus.phase); console.log(result.electionStatus.cohort); } // Or track election directly by index const election = await tracker.trackElection(0); console.log(election.phase, election.nomineeProposalId); ``` ### Response Example ```typescript // For trackByTxHash: // [ { stages: [...], isComplete: boolean, proposalType: string, isElection: boolean, electionStatus?: { phase: string, cohort: number } } ] // For trackElection: // { phase: string, nomineeProposalId: string, ... } ``` ``` -------------------------------- ### Election Execution Lifecycle Source: https://context7.com/gzeoneth/gov-tracker/llms.txt Execute the full lifecycle of a Security Council election, from creation through member installation, using a series of preparation and execution steps. ```APIDOC ## Election Execution - Full Lifecycle ### Description Execute all phases of an election from creation through member installation. ### Methods - `checkElectionStatus(l2Provider, l1Provider)`: Checks the current status of elections. - `prepareElectionCreation(status)`: Prepares the transaction to create a new election. - `trackElection(index)`: Tracks a specific election by its index. - `prepareMemberElectionTrigger(election, l2Provider)`: Prepares the transaction to trigger the member election phase. - `prepareMemberElectionExecution(election, l2Provider)`: Prepares the transaction to execute the member election and install new council members. ### Request Example ```typescript import { createTracker, checkElectionStatus, prepareElectionCreation, prepareMemberElectionTrigger, prepareMemberElectionExecution, } from "@gzeoneth/gov-tracker"; const tracker = createTracker({ l2Provider, l1Provider }); // Step A: Create nominee election (when conditions match) const status = await checkElectionStatus(l2Provider, l1Provider); if (status.canCreateElection) { const { transaction, electionIndex } = prepareElectionCreation(status); console.log(`Creating election #${electionIndex}`); const tx = await signer.sendTransaction(transaction); await tx.wait(); console.log(`Election created: ${tx.hash}`); } // Step B: Trigger member election (after vetting period) const election = await tracker.trackElection(0); if (election.canProceedToMemberPhase) { const prepared = await prepareMemberElectionTrigger(election, l2Provider); if (prepared) { const tx = await signer.sendTransaction(prepared); await tx.wait(); console.log(`Member election triggered: ${tx.hash}`); } } // Step C: Execute member election (install new council members) if (election.canExecuteMember) { const prepared = await prepareMemberElectionExecution(election, l2Provider); if (prepared) { const tx = await signer.sendTransaction(prepared); await tx.wait(); console.log(`Council members installed: ${tx.hash}`); } } ``` ### Response Example ```json { "transactionHash": "0x...", "electionIndex": 0, "message": "Election created successfully." } ``` ``` -------------------------------- ### Cache Methods Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/API.md Provides methods for interacting with the tracker's cache, including listing, retrieving, and querying checkpoints, as well as getting statistics. ```APIDOC ## Cache Methods ### Description Provides methods for interacting with the tracker's cache, including listing, retrieving, and querying checkpoints, as well as getting statistics. ### Methods - **`listCheckpointKeys()`** - Description: Lists all available checkpoint keys in the cache. - Returns: An array of checkpoint keys. - **`getCheckpoint(key)`** - Description: Retrieves a specific checkpoint from the cache using its key. - Returns: The checkpoint data. - **`getAllCheckpoints()`** - Description: Retrieves all checkpoints from the cache. - Returns: An array of all checkpoint data. - **`queryIncompleteCheckpoints(opts)`** - Description: Finds items in the cache that require re-tracking, filtering out superseded Security Council operations. - Parameters: - **opts.maxAgeDays** (number) - Optional - Maximum age of checkpoints in days (default: 60). - **opts.maxErrorCount** (number) - Optional - Maximum error count for checkpoints (default: 5). - Returns: An array of incomplete checkpoint data. - **`getStats()`** - Description: Retrieves statistics about the cache usage. - Returns: Cache statistics object. - **`getHighestScNonce()`** - Description: Gets the highest Security Council nonce from incomplete checkpoints. - Returns: The highest SC nonce or null if none found. ### Request Example ```typescript const incomplete = await tracker.queryIncompleteCheckpoints({ maxAgeDays: 60, maxErrorCount: 5, }); const highestNonce = await tracker.getHighestScNonce(); if (highestNonce) { console.log(`Highest SC nonce: ${highestNonce.toString()}`); } ``` ### Response Example ```typescript // For queryIncompleteCheckpoints: // [ { checkpointData1 }, { checkpointData2 }, ... ] // For getHighestScNonce: // "12345678901234567890" (as a string representing BigInt) ``` ``` -------------------------------- ### Get Highest Security Council Nonce Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/API.md Retrieves the highest nonce from incomplete Security Council checkpoints. This is useful for understanding the latest state of SC operations. ```typescript // Query highest SC nonce directly const highestNonce = await tracker.getHighestScNonce(); if (highestNonce) { console.log(`Highest SC nonce: ${highestNonce.toString()}`); } ``` -------------------------------- ### Track All Elections Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Fetches a list of all elections, including completed ones, and provides their current phase and nominee count. It also allows filtering to retrieve only active elections. ```APIDOC ## Track All Elections ### Description Fetches a list of all elections, including completed ones, and provides their current phase and nominee count. It also allows filtering to retrieve only active elections. ### Method GET (Implied, as it's a retrieval operation) ### Endpoint `/elections/all` (Hypothetical endpoint for tracking all elections) ### Parameters #### Query Parameters - **l2Provider** (object) - Required - The L2 provider instance. - **l1Provider** (object) - Required - The L1 provider instance. ### Response #### Success Response (200) - **allElections** (array) - An array of election objects. - **electionIndex** (number) - The index of the election. - **phase** (string) - The current phase of the election (e.g., "NOMINEE_VOTING", "COMPLETED"). - **cohort** (number) - The cohort of the election. - **compliantNomineeCount** (number) - The number of compliant nominees. #### Response Example ```json [ { "electionIndex": 0, "phase": "COMPLETED", "cohort": 0, "compliantNomineeCount": 6 }, { "electionIndex": 1, "phase": "NOMINEE_VOTING", "cohort": 1, "compliantNomineeCount": 4 } ] ``` ``` -------------------------------- ### Create Election or Transition Phase (CLI) Source: https://github.com/gzeoneth/gov-tracker/blob/main/README.md Used to create a new election or trigger a phase transition for an existing election. Requires a private key for execution and specifies a private election. ```bash npx @gzeoneth/gov-tracker election --track 0 -w --private-key $PRIVATE_KEY ``` -------------------------------- ### Track All Elections with Gov Tracker Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Utilizes ProposalStageTracker to monitor all elections, including those that have been completed. It iterates through all elections to log their index and current phase, and filters for active elections. ```typescript import { ProposalStageTracker } from "@gzeoneth/gov-tracker"; const tracker = new ProposalStageTracker({ l2Provider, l1Provider }); // Track all elections (including completed) const allElections = await tracker.trackAllElections(); for (const election of allElections) { console.log(`Election #${election.electionIndex}: ${election.phase}`); console.log(` Cohort: ${election.cohort === 0 ? "First" : "Second"}`); console.log(` Nominees: ${election.compliantNomineeCount}/6`); } // Filter to active elections only const activeElections = allElections.filter(e => e.phase !== "COMPLETED"); ``` -------------------------------- ### Track by Transaction Hash Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Tracks a specific transaction by its hash and logs details about the proposal type, current state, and stages with their statuses and timings. It requires the `txHash` as input. ```typescript const results = await tracker.trackByTxHash(txHash); const result = results[0]; console.log(`Type: ${result.proposalType}, State: ${result.currentState}`); for (const stage of result.stages) { console.log(`${stage.type}: ${stage.status}`); if (stage.timing?.eta) console.log(` ETA: ${new Date(stage.timing.eta * 1000)}`); } ``` -------------------------------- ### Environment Variables for Gov Tracker Tests Source: https://github.com/gzeoneth/gov-tracker/blob/main/CLAUDE.md This snippet details the required environment variables for running integration and fork tests. It includes RPC endpoints for Ethereum mainnet, Arbitrum One, and Arbitrum Nova, as well as a private key for write mode. It is crucial to never commit the .env file or private keys. ```bash ETH_RPC=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY ARB1_ARCHIVE_RPC=https://arb-mainnet.g.alchemy.com/v2/YOUR_KEY ARB1_RPC=https://arb-mainnet.g.alchemy.com/v2/YOUR_KEY NOVA_RPC=https://nova.arbitrum.io/rpc PRIVATE_KEY=0x... # Only for --write mode ``` -------------------------------- ### Prepare Foundry Simulation Data (TypeScript) Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/EXAMPLES.md Prepares simulation data for Foundry's `cast` command by decoding transaction calldata and extracting simulation details. It then prints `cast call` commands to the console, including target address, input data, sender, value, and RPC URL based on the network ID. Requires functions from the gov-tracker SDK. ```typescript import { decodeCalldata, extractAllSimulationsFromDecoded } from "@gzeoneth/gov-tracker"; async function prepareFoundrySimulation(txHash: string) { const results = await tracker.trackByTxHash(txHash); const stage = results[0].stages[0]; const { calldatas, targets } = stage.data; for (let i = 0; i < calldatas.length; i++) { const decoded = await decodeCalldata(calldatas[i], targets[i], 0, "arb1"); const sims = extractAllSimulationsFromDecoded(decoded, "arb1"); for (const sim of sims) { const { from, to, input, value, networkId } = sim.simulation; const rpc = networkId === "1" ? process.env.ETH_RPC : process.env.ARB1_RPC; console.log(`# Simulate: ${sim.label}`); console.log(`cast call ${to} \`); console.log(` ${input} \`); console.log(` --from ${from} \`); console.log(` --value ${value || 0} \`); console.log(` --rpc-url ${rpc}`); console.log(); } } } ``` -------------------------------- ### Get Address Label (TypeScript) Source: https://github.com/gzeoneth/gov-tracker/blob/main/docs/API.md Retrieves a human-readable label for known governance contract addresses on a specific chain. It requires the address and chain context as input and returns the label string. ```typescript import { getAddressLabel } from "@gzeoneth/gov-tracker"; // Get human-readable label for known governance contracts const label = getAddressLabel("0xf07DeD...", "arb1"); // Returns: "Core Governor" ```