Skip to content

feat: fetch token holders with etherscan api [skip-line-limit]#929

Merged
ctrlc03 merged 9 commits into
devfrom
feat/fetch-events-from-etherscan
Nov 5, 2025
Merged

feat: fetch token holders with etherscan api [skip-line-limit]#929
ctrlc03 merged 9 commits into
devfrom
feat/fetch-events-from-etherscan

Conversation

@ctrlc03

@ctrlc03 ctrlc03 commented Oct 29, 2025

Copy link
Copy Markdown
Collaborator

fix #909

Summary by CodeRabbit

  • New Features

    • Integrated Etherscan-backed token holder discovery with voting-power verification and orchestration.
  • Refactor

    • Replaced Bitquery provider with Etherscan across the server example; updated config and module exports accordingly.
    • Updated test/local network handling and mocks to align with the new provider; removed legacy provider code.
  • Documentation

    • Updated example environment and README to reference the Etherscan API key.
  • Tests

    • Added unit/integration tests for the Etherscan path; removed Bitquery-specific tests.

@vercel

vercel Bot commented Oct 29, 2025

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

2 Skipped Deployments
Project Deployment Preview Comments Updated (UTC)
crisp Skipped Skipped Nov 5, 2025 4:18pm
enclave-docs Skipped Skipped Nov 5, 2025 4:18pm

@coderabbitai

coderabbitai Bot commented Oct 29, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Replaced Bitquery-based token-holder provider with an Etherscan+RPC implementation, renamed config/env key, updated module exports and indexer usage, removed Bitquery module and tests, added Etherscan module with log retrieval, voter discovery, and voting-power verification; plus minor formatting/import reorderings.

Changes

Cohort / File(s) Change Summary
Configuration
examples/CRISP/server/.env.example, examples/CRISP/server/src/config.rs
Renamed env key BITQUERY_API_KEYETHERSCAN_API_KEY and Config field bitquery_api_keyetherscan_api_key.
Provider removed
examples/CRISP/server/src/server/token_holders/bitquery.rs
Removed Bitquery module (types, GraphQL client, parsing, mocks, tests).
Provider added
examples/CRISP/server/src/server/token_holders/etherscan.rs
Added Etherscan module: EtherscanClient, log/transfer/delegate types, log retrieval pagination/rate limiting, balance computation, RPC-based voting-power verification, helpers, mocks and tests.
Module exports
examples/CRISP/server/src/server/token_holders/mod.rs
Replaced pub mod bitquery; / pub use bitquery::*; with pub mod etherscan; / pub use etherscan::*;.
Indexer integration
examples/CRISP/server/src/server/indexer.rs
Switched BitqueryClientEtherscanClient; call updated to get_token_holders_with_voting_power(...); chain-ID gating changed (removed 11155111); added U256 import; adjusted error mapping/log messages.
Import adjustments
examples/CRISP/server/src/server/token_holders/hashes.rs
Updated TokenHolder import to super::etherscan::TokenHolder.
Module ordering
examples/CRISP/server/src/lib.rs
Moved pub mod config earlier (declaration order only).
Docs / README
examples/CRISP/Readme.md
Replaced BITQUERY_API_KEY references with ETHERSCAN_API_KEY in docs/examples.
Formatting & small edits
examples/CRISP/server/src/server/program_server_request.rs, .../repo.rs, .../routes/voting.rs
Minor formatting and import reorderings; no behavioral changes.

Sequence Diagram(s)

sequenceDiagram
    participant Indexer
    participant EtherscanClient
    participant EtherscanAPI as Etherscan API
    participant RPC

    rect rgb(220,235,255)
    note over Indexer,EtherscanClient: New flow: Etherscan + RPC voting-power verification
    end

    Indexer->>EtherscanClient: get_token_holders_with_voting_power(token, snapshot_block, rpc_url, threshold)
    EtherscanClient->>EtherscanAPI: get_deployment_block(token)
    EtherscanAPI-->>EtherscanClient: deployment_block
    EtherscanClient->>EtherscanAPI: get_transfer_logs(token, from, to) (paginated)
    EtherscanAPI-->>EtherscanClient: transfer_logs
    EtherscanClient->>EtherscanAPI: get_delegate_votes_changed_logs(token, from, to) (paginated)
    EtherscanAPI-->>EtherscanClient: delegation_logs
    EtherscanClient->>EtherscanClient: compute potential voters (from logs)
    loop per potential voter
        EtherscanClient->>RPC: getPastVotes(token, voter, block)
        RPC-->>EtherscanClient: voting_power
    end
    rect rgb(220,245,220)
    note over EtherscanClient: filter by threshold → TokenHolder list
    end
    EtherscanClient-->>Indexer: Vec<TokenHolder>
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Files needing extra attention:
    • examples/CRISP/server/src/server/token_holders/etherscan.rs — dense parsing, pagination, RPC interactions, and many tests.
    • examples/CRISP/server/src/server/indexer.rs — updated call site, imports, error handling, and chain-id gating.
    • examples/CRISP/server/src/config.rs & .env.example — ensure env loading matches renamed key.

Possibly related PRs

Suggested reviewers

  • cedoor
  • hmzakhalid

Poem

🐰 I hopped through logs and topics wide,

Etherscan showed where tokens hide.
I counted transfers, traced each sway,
RPC whispers who can vote today.
Tiny paws, big census—hip hooray!

Pre-merge checks and finishing touches

✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: replacing Bitquery with Etherscan API for fetching token holders in CRISP, which is the primary objective of the changeset.
Linked Issues check ✅ Passed The PR successfully implements all objectives from issue #909: retrieves transfer logs via Etherscan API, retrieves delegate change logs via Etherscan API, and calls getVotesAt via direct RPC with voting power verification logic.
Out of Scope Changes check ✅ Passed All changes are directly related to replacing Bitquery with Etherscan API. Minor scope items include reordering imports and moving module declarations, which support the primary objective and are not out-of-scope.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/fetch-events-from-etherscan

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ctrlc03 ctrlc03 force-pushed the feat/fetch-events-from-etherscan branch from 739bb23 to 04543bd Compare October 29, 2025 10:35
@vercel vercel Bot temporarily deployed to Preview – enclave-docs October 29, 2025 10:35 Inactive
@vercel vercel Bot temporarily deployed to Preview – crisp October 29, 2025 10:35 Inactive
@ctrlc03 ctrlc03 linked an issue Oct 29, 2025 that may be closed by this pull request
@ctrlc03 ctrlc03 force-pushed the feat/fetch-events-from-etherscan branch from 04543bd to c47a976 Compare November 5, 2025 10:32
@vercel vercel Bot temporarily deployed to Preview – crisp November 5, 2025 10:32 Inactive
@vercel vercel Bot temporarily deployed to Preview – enclave-docs November 5, 2025 10:32 Inactive
@vercel vercel Bot temporarily deployed to Preview – enclave-docs November 5, 2025 10:53 Inactive
@vercel vercel Bot temporarily deployed to Preview – crisp November 5, 2025 10:53 Inactive
@ctrlc03 ctrlc03 changed the title feat: fetch token holders with etherscan api feat: fetch token holders with etherscan api [skip-line-check] Nov 5, 2025
@ctrlc03 ctrlc03 marked this pull request as ready for review November 5, 2025 11:07
@ctrlc03 ctrlc03 requested a review from cedoor November 5, 2025 11:07

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
examples/CRISP/server/src/server/repo.rs (1)

202-205: Consider removing unused methods if not part of the public API.

The pipeline flagged set_ciphertext_output and is_finished as unused. If these methods are not part of an intentional public API or planned for future use, consider removing them to reduce maintenance burden.

Also applies to: 244-247

examples/CRISP/server/src/server/indexer.rs (1)

96-96: Document or extract the magic number constant.

The hardcoded value 9 lacks context. Consider extracting it to a named constant with documentation explaining its purpose (e.g., DECIMALS, MAX_RETRIES, PAGE_SIZE, etc.).

Apply this diff to improve clarity:

+/// Number of decimal places for token balance precision
+const TOKEN_DECIMALS: u8 = 9;
+
 pub async fn register_e3_requested(
     mut indexer: EnclaveIndexer<impl DataStore>,
 ) -> Result<EnclaveIndexer<impl DataStore>> {
     // ... existing code ...
                     etherscan_client
                         .get_token_holders_with_voting_power(
                             token_address,
-                            9,
+                            TOKEN_DECIMALS,
                             &CONFIG.http_rpc_url,
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 63ee5c3 and e145a38.

📒 Files selected for processing (11)
  • examples/CRISP/server/.env.example (1 hunks)
  • examples/CRISP/server/src/config.rs (1 hunks)
  • examples/CRISP/server/src/lib.rs (1 hunks)
  • examples/CRISP/server/src/server/indexer.rs (4 hunks)
  • examples/CRISP/server/src/server/program_server_request.rs (1 hunks)
  • examples/CRISP/server/src/server/repo.rs (2 hunks)
  • examples/CRISP/server/src/server/routes/voting.rs (1 hunks)
  • examples/CRISP/server/src/server/token_holders/bitquery.rs (0 hunks)
  • examples/CRISP/server/src/server/token_holders/etherscan.rs (1 hunks)
  • examples/CRISP/server/src/server/token_holders/hashes.rs (1 hunks)
  • examples/CRISP/server/src/server/token_holders/mod.rs (1 hunks)
💤 Files with no reviewable changes (1)
  • examples/CRISP/server/src/server/token_holders/bitquery.rs
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2024-09-26T03:11:29.311Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: packages/ciphernode/sortition/src/distance.rs:1-1
Timestamp: 2024-09-26T03:11:29.311Z
Learning: In `packages/ciphernode/core/src/events.rs`, the import statements use the correct and updated `alloy::primitives` module.

Applied to files:

  • examples/CRISP/server/src/server/token_holders/mod.rs
  • examples/CRISP/server/src/server/token_holders/hashes.rs
  • examples/CRISP/server/src/lib.rs
  • examples/CRISP/server/src/server/routes/voting.rs
  • examples/CRISP/server/src/server/indexer.rs
📚 Learning: 2025-08-25T10:28:56.174Z
Learnt from: ctrlc03
Repo: gnosisguild/enclave PR: 657
File: Cargo.toml:32-34
Timestamp: 2025-08-25T10:28:56.174Z
Learning: The examples/CRISP directory has its own Cargo.toml workspace configuration with members like "server", "wasm-crypto", "program/core", "program/client", etc. The root workspace intentionally excludes "examples/CRISP/server", "examples/CRISP/program", and "examples/CRISP/wasm-crypto" to prevent double workspace membership, which is the correct approach for self-contained example workspaces.

Applied to files:

  • examples/CRISP/server/src/lib.rs
📚 Learning: 2024-10-29T01:03:50.414Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/config/src/app_config.rs:21-26
Timestamp: 2024-10-29T01:03:50.414Z
Learning: In `packages/ciphernode/config/src/app_config.rs`, the `rpc_url` field in the `ChainConfig` struct is not considered sensitive and does not need to be encrypted.

Applied to files:

  • examples/CRISP/server/src/config.rs
📚 Learning: 2024-11-05T06:48:58.177Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/config/src/app_config.rs:13-21
Timestamp: 2024-11-05T06:48:58.177Z
Learning: In the `packages/ciphernode/config/src/app_config.rs` file, for the `Contract` enum, the team prefers to use `String` type for `address` fields, relying on parsing to handle validation, instead of using the `Address` type.

Applied to files:

  • examples/CRISP/server/src/config.rs
  • examples/CRISP/server/src/server/routes/voting.rs
  • examples/CRISP/server/src/server/indexer.rs
📚 Learning: 2024-10-22T03:42:14.057Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/router/src/context.rs:94-97
Timestamp: 2024-10-22T03:42:14.057Z
Learning: In `packages/ciphernode/router/src/context.rs`, avoid adding complexity for batching checkpoint operations in code; rely on the database's batching capabilities instead.

Applied to files:

  • examples/CRISP/server/src/server/routes/voting.rs
📚 Learning: 2024-10-16T09:51:10.038Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/router/src/committee_meta.rs:43-43
Timestamp: 2024-10-16T09:51:10.038Z
Learning: In `packages/ciphernode/router/src/committee_meta.rs`, avoid suggesting making the `on_event` method in `CommitteMetaFeature` asynchronous or adding error handling for the `write` operation to the data store.

Applied to files:

  • examples/CRISP/server/src/server/routes/voting.rs
🧬 Code graph analysis (1)
examples/CRISP/server/src/server/indexer.rs (1)
examples/CRISP/server/src/server/token_holders/etherscan.rs (2)
  • get_mock_token_holders (526-569)
  • new (95-101)
🪛 dotenv-linter (4.0.0)
examples/CRISP/server/.env.example

[warning] 10-10: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)

🪛 GitHub Actions: ci
examples/CRISP/server/src/server/repo.rs

[warning] 202-202: methods set_ciphertext_output and is_finished are never used

examples/CRISP/server/src/server/token_holders/etherscan.rs

[warning] 7-7: unused import: crate::server::CONFIG


[warning] 309-309: associated function extract_addresses is never used

🪛 Gitleaks (8.28.0)
examples/CRISP/server/src/server/token_holders/etherscan.rs

[high] 782-782: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 795-795: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 810-810: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 827-827: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🔇 Additional comments (7)
examples/CRISP/server/src/server/repo.rs (2)

94-98: LGTM! Formatting improvement.

The multi-line parameter formatting with trailing comma is idiomatic Rust style and improves readability.


261-261: LGTM! Minor whitespace cleanup.

The removal of the extra blank line improves consistency.

examples/CRISP/server/src/server/token_holders/hashes.rs (1)

14-14: LGTM: Import path correctly updated.

The import path change aligns with the module reorganization from bitquery to etherscan.

examples/CRISP/server/src/lib.rs (1)

7-9: LGTM: Module reordering is acceptable.

The pub mod config declaration has been moved but remains public with no functional changes.

examples/CRISP/server/src/server/token_holders/mod.rs (1)

7-11: LGTM: Module reorganization correctly implemented.

The module exports have been properly updated from bitquery to etherscan, aligning with the PR objectives to replace the Bitquery integration.

examples/CRISP/server/src/server/indexer.rs (2)

7-7: LGTM: Imports updated for Etherscan integration.

The import changes correctly reflect the migration from BitqueryClient to EtherscanClient and the addition of U256 for balance threshold handling.

Also applies to: 17-17


78-78: Verify Sepolia testnet (chain ID 11155111) removal from mock data condition.

The chain ID check now excludes Sepolia (11155111), meaning it will use the real Etherscan API instead of mocked data. Please confirm:

  1. This change is intentional
  2. The Etherscan API key has appropriate access for Sepolia testnet
  3. The API rate limits are sufficient for your testing needs on Sepolia

Comment thread examples/CRISP/server/src/server/indexer.rs Outdated
Comment thread examples/CRISP/server/src/server/token_holders/etherscan.rs
Comment thread examples/CRISP/server/src/server/token_holders/etherscan.rs Outdated
@vercel vercel Bot temporarily deployed to Preview – enclave-docs November 5, 2025 11:16 Inactive
@vercel vercel Bot temporarily deployed to Preview – crisp November 5, 2025 11:16 Inactive
Comment thread examples/CRISP/server/src/server/token_holders/etherscan.rs Outdated
@ctrlc03 ctrlc03 requested a review from cedoor November 5, 2025 13:32
@ctrlc03 ctrlc03 force-pushed the feat/fetch-events-from-etherscan branch from 76fe2a6 to 5c58f30 Compare November 5, 2025 13:32
@vercel vercel Bot temporarily deployed to Preview – enclave-docs November 5, 2025 13:32 Inactive
@vercel vercel Bot temporarily deployed to Preview – crisp November 5, 2025 13:32 Inactive
@ctrlc03 ctrlc03 changed the title feat: fetch token holders with etherscan api [skip-line-check] feat: fetch token holders with etherscan api skip-line-limit] Nov 5, 2025
@ctrlc03 ctrlc03 changed the title feat: fetch token holders with etherscan api skip-line-limit] feat: fetch token holders with etherscan api [skip-line-limit] Nov 5, 2025
@vercel vercel Bot temporarily deployed to Preview – enclave-docs November 5, 2025 14:06 Inactive
@vercel vercel Bot temporarily deployed to Preview – crisp November 5, 2025 14:06 Inactive
@ctrlc03 ctrlc03 self-assigned this Nov 5, 2025
@ctrlc03 ctrlc03 enabled auto-merge (squash) November 5, 2025 15:53
@ctrlc03 ctrlc03 force-pushed the feat/fetch-events-from-etherscan branch from 6a9f48c to 02b6073 Compare November 5, 2025 16:18
@vercel vercel Bot temporarily deployed to Preview – enclave-docs November 5, 2025 16:18 Inactive
@vercel vercel Bot temporarily deployed to Preview – crisp November 5, 2025 16:18 Inactive

@cedoor cedoor left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK 👍🏽

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
examples/CRISP/server/.env.example (1)

10-10: Consider removing quotes for consistency with dotenv conventions.

The empty string value typically doesn't require quotes in .env files. While this works correctly, removing them would align with common dotenv conventions.

Apply this diff:

-ETHERSCAN_API_KEY=""
+ETHERSCAN_API_KEY=
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5c58f30 and 02b6073.

📒 Files selected for processing (12)
  • examples/CRISP/Readme.md (2 hunks)
  • examples/CRISP/server/.env.example (1 hunks)
  • examples/CRISP/server/src/config.rs (1 hunks)
  • examples/CRISP/server/src/lib.rs (1 hunks)
  • examples/CRISP/server/src/server/indexer.rs (4 hunks)
  • examples/CRISP/server/src/server/program_server_request.rs (1 hunks)
  • examples/CRISP/server/src/server/repo.rs (2 hunks)
  • examples/CRISP/server/src/server/routes/voting.rs (1 hunks)
  • examples/CRISP/server/src/server/token_holders/bitquery.rs (0 hunks)
  • examples/CRISP/server/src/server/token_holders/etherscan.rs (1 hunks)
  • examples/CRISP/server/src/server/token_holders/hashes.rs (1 hunks)
  • examples/CRISP/server/src/server/token_holders/mod.rs (1 hunks)
💤 Files with no reviewable changes (1)
  • examples/CRISP/server/src/server/token_holders/bitquery.rs
🚧 Files skipped from review as they are similar to previous changes (6)
  • examples/CRISP/server/src/server/repo.rs
  • examples/CRISP/Readme.md
  • examples/CRISP/server/src/server/routes/voting.rs
  • examples/CRISP/server/src/server/token_holders/hashes.rs
  • examples/CRISP/server/src/lib.rs
  • examples/CRISP/server/src/config.rs
🧰 Additional context used
🧠 Learnings (7)
📚 Learning: 2024-09-26T03:11:29.311Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 107
File: packages/ciphernode/sortition/src/distance.rs:1-1
Timestamp: 2024-09-26T03:11:29.311Z
Learning: In `packages/ciphernode/core/src/events.rs`, the import statements use the correct and updated `alloy::primitives` module.

Applied to files:

  • examples/CRISP/server/src/server/token_holders/mod.rs
  • examples/CRISP/server/src/server/indexer.rs
📚 Learning: 2024-11-05T06:48:58.177Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/config/src/app_config.rs:13-21
Timestamp: 2024-11-05T06:48:58.177Z
Learning: In the `packages/ciphernode/config/src/app_config.rs` file, for the `Contract` enum, the team prefers to use `String` type for `address` fields, relying on parsing to handle validation, instead of using the `Address` type.

Applied to files:

  • examples/CRISP/server/src/server/indexer.rs
📚 Learning: 2024-10-10T23:24:43.341Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 143
File: packages/ciphernode/sortition/src/sortition.rs:4-9
Timestamp: 2024-10-10T23:24:43.341Z
Learning: In the `Sortition` module (`packages/ciphernode/sortition/src/sortition.rs`), errors are sent to the event bus using `self.bus.err`, which handles logging and printing. Therefore, explicit use of the `tracing` crate for logging errors may not be necessary in this context.

Applied to files:

  • examples/CRISP/server/src/server/token_holders/etherscan.rs
📚 Learning: 2024-10-28T12:00:09.010Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/enclave/src/commands/wallet/set.rs:17-23
Timestamp: 2024-10-28T12:00:09.010Z
Learning: In the `enclave` package of the `ciphernode` project, prefer using `println!` over logging macros like `error!` from the `tracing` crate for error output in CLI commands.

Applied to files:

  • examples/CRISP/server/src/server/token_holders/etherscan.rs
📚 Learning: 2024-10-28T10:45:29.100Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 156
File: packages/ciphernode/cipher/src/cipher.rs:164-164
Timestamp: 2024-10-28T10:45:29.100Z
Learning: In test code, it's acceptable to use `.unwrap()` instead of propagating errors with the `?` operator in Rust.

Applied to files:

  • examples/CRISP/server/src/server/token_holders/etherscan.rs
📚 Learning: 2024-10-16T09:52:53.807Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 145
File: packages/ciphernode/data/src/data_store.rs:74-75
Timestamp: 2024-10-16T09:52:53.807Z
Learning: In this project, the actor model handles potential errors internally, so methods like `checkpoint` in the `Checkpoint` trait do not need to explicitly handle or propagate errors.

Applied to files:

  • examples/CRISP/server/src/server/token_holders/etherscan.rs
📚 Learning: 2024-11-05T06:49:46.285Z
Learnt from: ryardley
Repo: gnosisguild/enclave PR: 173
File: packages/ciphernode/enclave_node/src/datastore.rs:14-16
Timestamp: 2024-11-05T06:49:46.285Z
Learning: In `packages/ciphernode/enclave_node/src/datastore.rs`, for internal functions like `get_in_mem_store`, adding extensive documentation and error handling may not be necessary if they are not client-facing.

Applied to files:

  • examples/CRISP/server/src/server/token_holders/etherscan.rs
🧬 Code graph analysis (1)
examples/CRISP/server/src/server/indexer.rs (1)
examples/CRISP/server/src/server/token_holders/etherscan.rs (2)
  • get_mock_token_holders (553-596)
  • new (95-101)
🪛 dotenv-linter (4.0.0)
examples/CRISP/server/.env.example

[warning] 10-10: [QuoteCharacter] The value has quote characters (', ")

(QuoteCharacter)

🪛 Gitleaks (8.28.0)
examples/CRISP/server/src/server/token_holders/etherscan.rs

[high] 807-807: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 820-820: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 835-835: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 852-852: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: integration_prebuild
  • GitHub Check: test_contracts
  • GitHub Check: build_sdk
  • GitHub Check: build_e3_support_dev
  • GitHub Check: build_enclave_cli
  • GitHub Check: rust_unit
  • GitHub Check: test_net
  • GitHub Check: rust_integration
🔇 Additional comments (16)
examples/CRISP/server/src/server/program_server_request.rs (1)

30-30: LGTM!

The function signature reformatting improves readability without changing functionality.

examples/CRISP/server/src/server/token_holders/mod.rs (1)

7-11: LGTM!

The module swap from bitquery to etherscan cleanly reflects the PR's migration objective.

examples/CRISP/server/src/server/indexer.rs (3)

7-7: LGTM!

Import updates correctly reflect the migration from Bitquery to Etherscan, and the addition of U256 supports the threshold conversion logic.

Also applies to: 17-17


78-78: LGTM!

Removing Sepolia (11155111) from the mock data condition is appropriate, as it's a real testnet where the Etherscan API should be used.


91-108: LGTM! Critical issue from previous review resolved.

The error handling has been properly updated to propagate parse failures instead of silently defaulting to U256::ZERO. The new implementation:

  • Uses map_err to convert parse errors into descriptive error messages
  • Prevents bypassing the balance threshold requirement on parse failures
  • Aligns with the Etherscan-based data provider
examples/CRISP/server/src/server/token_holders/etherscan.rs (11)

1-91: LGTM!

The imports, type definitions, and contract interface are well-structured. The use of eyre for error handling aligns with the previous review feedback.


93-101: LGTM!

The constructor is straightforward and correctly initializes the client with the necessary parameters.


103-142: LGTM!

The deployment block fetching logic properly handles both hex and decimal formats with appropriate error context.


144-208: LGTM! Previous error handling concern addressed.

The error handling now properly distinguishes between "No records found" (which short-circuits pagination) and other failures (which propagate errors). The pagination logic and rate limiting are well-implemented.


210-275: LGTM!

The delegation log fetching follows the same robust error handling pattern as transfer logs, properly distinguishing between "No records found" and actual errors.


277-316: LGTM!

The potential voter identification logic correctly combines token holders and delegates while properly filtering out zero addresses.


318-349: LGTM! Threshold comparison correctly uses >=.

The voting power verification properly uses >= for the threshold comparison, ensuring addresses with votes equal to the threshold are included as documented. The error handling gracefully logs failures without stopping the entire operation.


351-483: LGTM!

The helper methods are well-implemented with appropriate error handling. Notable good practices:

  • Using saturating arithmetic for balance updates to prevent overflow/underflow
  • Sorting logs by block number before processing for correct chronological order
  • Proper filtering of zero addresses throughout

484-550: LGTM!

The orchestrator method is well-structured with clear step-by-step flow and comprehensive logging for observability. Error handling with context makes debugging easier.


552-596: LGTM!

The mock data function provides useful test data without requiring real API calls, making local development easier.


598-868: LGTM!

The test suite provides good coverage:

  • Unit tests validate helper functions (parsing, extraction, balance computation)
  • Integration tests are properly marked with #[ignore] to prevent accidental runs without API keys
  • The static analysis warnings about API key exposure are false positives—the tests use CONFIG which loads from environment variables

@ctrlc03 ctrlc03 merged commit 41abd8e into dev Nov 5, 2025
24 checks passed
@ctrlc03 ctrlc03 deleted the feat/fetch-events-from-etherscan branch November 5, 2025 16:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Replace bitquery with etherscan api for CRISP census

2 participants