Add envio data command for querying raw blockchain data#1254
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds an ChangesData Query Subcommand
Sequence Diagram(s)sequenceDiagram
participant User as CLI
participant Clap as ClapParser
participant Executor as Executor::data
participant Hypersync as hypersync_client
participant TOON as toon::render
User->>Clap: invoke `envio data` (fields, --chain, --where)
Clap->>Executor: CommandType::Data(DataArgs)
Executor->>Executor: resolve chain, parse selection, parse where
Executor->>Hypersync: build client & send Query
Hypersync-->>Executor: ArrowResponse (+ paging info)
Executor->>TOON: render_arrow_response(selection, response)
TOON-->>Executor: formatted TOON output
Executor->>User: print stdout/stderr and paging hints
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
packages/cli/src/data/mapping.rs (2)
269-279: ⚡ Quick winReplace
containsassertions with full-value assertions/snapshots.Line 271, Line 272, and Line 278 use
contains, which weakens test specificity and violates the test-assertion rule. Assert the full vector value (or snapshot it) instead.Suggested approach
#[test] fn valid_names_use_camel_case() { let names = valid_indexer_names(Section::Block); - assert!(names.contains(&"gasLimit".to_string()), "{names:?}"); - assert!(names.contains(&"baseFeePerGas".to_string()), "{names:?}"); + insta::assert_debug_snapshot!(names); } #[test] fn valid_names_include_src_address() { let names = valid_indexer_names(Section::Log); - assert!(names.contains(&"srcAddress".to_string()), "{names:?}"); + insta::assert_debug_snapshot!(names); }As per coding guidelines:
**/*.rs: Never usecontainsin test assertions — assert the full expected value. Useassert_eq!orinsta::assert_snapshot!for error messages.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/src/data/mapping.rs` around lines 269 - 279, The tests valid_names_use_camel_case and valid_names_include_src_address call valid_indexer_names(Section::Block) and valid_indexer_names(Section::Log) and then use contains(...) which is disallowed; replace those contains assertions with full-value assertions by either asserting the exact Vec<String> returned (using assert_eq!(names, expected_vec)) or by snapshotting the entire value with insta::assert_snapshot! (or insta::assert_debug_snapshot!) so the test verifies the complete ordering and content rather than a subset; update the test bodies for functions valid_names_use_camel_case and valid_names_include_src_address to construct the expected full vector (or snapshot) and compare it to names.
178-260: ⚡ Quick winUse one assertion per test case by asserting the combined expected value.
Several tests (e.g., Line 180 onward) use multiple assertions in a single test body. Consolidate each case into one assertion over a tuple/aggregate result to keep failures atomic and align with repo test policy.
Suggested pattern
#[test] fn lookup_camel_case() { - assert!(matches!( - lookup(Section::Block, "gasLimit"), - Some(TypedField::Block(BlockField::GasLimit)) - )); - assert!(matches!( - lookup(Section::Transaction, "transactionIndex"), - Some(TypedField::Transaction(TransactionField::TransactionIndex)) - )); + assert!(matches!( + ( + lookup(Section::Block, "gasLimit"), + lookup(Section::Transaction, "transactionIndex"), + ), + ( + Some(TypedField::Block(BlockField::GasLimit)), + Some(TypedField::Transaction(TransactionField::TransactionIndex)) + ) + )); }As per coding guidelines:
**/*.rs: Always use single assert to check the whole value instead of multiple asserts for every field.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/src/data/mapping.rs` around lines 178 - 260, Tests like lookup_camel_case, lookup_snake_case, lookup_all_lowercase, lookup_uppercase_mixed, lookup_src_address_alias, lookup_address_directly, and lookup_topic_fields use multiple assert! calls; change each test to use a single assertion that checks the combined result (e.g., build a tuple or aggregate of the lookup(...) return values) and compare it once to the expected tuple of TypedField variants (referencing lookup, TypedField, BlockField, TransactionField, LogField, and the specific test names to find the cases).packages/cli/src/data/where_filter.rs (1)
296-303: ⚡ Quick winUse one full-value assertion per test case.
These tests split related expectations across multiple assertions; combine them into one assertion per case.
As per coding guidelines "
**/*.rs: Always use single assert to check the whole value instead of multiple asserts for every field".Also applies to: 374-377
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/src/data/where_filter.rs` around lines 296 - 303, The tests currently use multiple assert_eq calls to check different fields of the same value (e.g., assert_eq((f.from_block, f.to_block_exclusive), (...)) and assert_eq((f.log_filters.len(), f.log_filters[0].indexer_name.as_str()), (...))) — change each case to a single full-value assertion that compares the entire expected struct/tuple to the actual (for example compare a constructed expected WhereFilter or a full tuple representing all relevant fields to f), and do the same for the other occurrence around lines 374-377 so each test uses one assert per case.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/src/executor/data.rs`:
- Around line 54-58: Don't coerce response.archive_height to 0; keep it as an
Option and only render or use it when present. Replace the let archive_height =
response.archive_height.unwrap_or(0) with an Option binding (e.g., let
archive_height_opt = response.archive_height), change the rendering to call
toon::render_archive_height only when archive_height_opt.is_some() (or map to
i64 via archive_height_opt.map(|h| h as i64)), and update the
pagination/exhaustion checks to rely on archive_height_opt being Some rather
than comparing against 0; reference response.archive_height, archive_height_opt,
selection.known_height, and toon::render_archive_height when making the changes.
---
Nitpick comments:
In `@packages/cli/src/data/mapping.rs`:
- Around line 269-279: The tests valid_names_use_camel_case and
valid_names_include_src_address call valid_indexer_names(Section::Block) and
valid_indexer_names(Section::Log) and then use contains(...) which is
disallowed; replace those contains assertions with full-value assertions by
either asserting the exact Vec<String> returned (using assert_eq!(names,
expected_vec)) or by snapshotting the entire value with insta::assert_snapshot!
(or insta::assert_debug_snapshot!) so the test verifies the complete ordering
and content rather than a subset; update the test bodies for functions
valid_names_use_camel_case and valid_names_include_src_address to construct the
expected full vector (or snapshot) and compare it to names.
- Around line 178-260: Tests like lookup_camel_case, lookup_snake_case,
lookup_all_lowercase, lookup_uppercase_mixed, lookup_src_address_alias,
lookup_address_directly, and lookup_topic_fields use multiple assert! calls;
change each test to use a single assertion that checks the combined result
(e.g., build a tuple or aggregate of the lookup(...) return values) and compare
it once to the expected tuple of TypedField variants (referencing lookup,
TypedField, BlockField, TransactionField, LogField, and the specific test names
to find the cases).
In `@packages/cli/src/data/where_filter.rs`:
- Around line 296-303: The tests currently use multiple assert_eq calls to check
different fields of the same value (e.g., assert_eq((f.from_block,
f.to_block_exclusive), (...)) and assert_eq((f.log_filters.len(),
f.log_filters[0].indexer_name.as_str()), (...))) — change each case to a single
full-value assertion that compares the entire expected struct/tuple to the
actual (for example compare a constructed expected WhereFilter or a full tuple
representing all relevant fields to f), and do the same for the other occurrence
around lines 374-377 so each test uses one assert per case.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 32a26654-a124-437f-b047-4b860f9bf677
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (19)
CLAUDE.mdpackages/cli/Cargo.tomlpackages/cli/CommandLineHelp.mdpackages/cli/examples/script.rspackages/cli/src/cli_args/clap_definitions.rspackages/cli/src/data/chain.rspackages/cli/src/data/field_selection.rspackages/cli/src/data/mapping.rspackages/cli/src/data/mod.rspackages/cli/src/data/toon.rspackages/cli/src/data/where_filter.rspackages/cli/src/executor/data.rspackages/cli/src/executor/mod.rspackages/cli/src/hypersync_source/query.rspackages/cli/src/lib.rspackages/cli/src/template_dirs.rspackages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.mdpackages/cli/templates/static/shared/.claude/skills/indexer-testing/SKILL.mdpackages/cli/tests/data_integration.rs
💤 Files with no reviewable changes (1)
- packages/cli/templates/static/shared/.claude/skills/indexer-testing/SKILL.md
| let archive_height = response.archive_height.unwrap_or(0); | ||
|
|
||
| if selection.known_height { | ||
| out.push_str(&toon::render_archive_height(archive_height as i64)); | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="packages/cli/src/executor/data.rs"
echo "=== File header ==="
ls -la "$FILE" 2>/dev/null || true
echo
echo "=== Lines 1-140 (for context) ==="
sed -n '1,140p' "$FILE" | nl -ba | sed -n '1,140p'
echo
echo "=== Search: archive_height in file ==="
rg -n "archive_height" "$FILE" || true
echo
echo "=== Search: exhausted / to_block_exclusive / next_block ==="
rg -n "(exhausted|to_block_exclusive|next_block)" "$FILE" || trueRepository: enviodev/hyperindex
Length of output: 263
🏁 Script executed:
#!/bin/bash
set -euo pipefail
FILE="packages/cli/src/executor/data.rs"
echo "=== File header ==="
ls -la "$FILE" 2>/dev/null || true
echo
echo "=== Lines 1-220 (for context) ==="
# Use cat -n for line numbers (nl may not exist)
cat -n "$FILE" | sed -n '1,220p'
echo
echo "=== Search: archive_height in file ==="
rg -n "archive_height" "$FILE" || true
echo
echo "=== Search: exhausted / to_block_exclusive / next_block ==="
rg -n "(exhausted|to_block_exclusive|next_block)" "$FILE" || trueRepository: enviodev/hyperindex
Length of output: 7515
Don’t coerce missing archive_height to 0 for pagination/exhaustion decisions.
let archive_height = response.archive_height.unwrap_or(0);
if selection.known_height {
out.push_str(&toon::render_archive_height(archive_height as i64));
}
unwrap_or(0) makes exhausted always true when response.archive_height is absent (next_block >= 0), breaking pagination (67-68), and can also emit misleading knownHeight=0 when selection.known_height is set (56-58).
Suggested fix
- let archive_height = response.archive_height.unwrap_or(0);
+ let archive_height = response.archive_height;
if selection.known_height {
- out.push_str(&toon::render_archive_height(archive_height as i64));
+ if let Some(h) = archive_height {
+ out.push_str(&toon::render_archive_height(h as i64));
+ }
}
@@
- eprintln!("archive_height: {archive_height}");
+ match archive_height {
+ Some(h) => eprintln!("archive_height: {h}"),
+ None => eprintln!("archive_height: <unknown>"),
+ }
- let exhausted = matches!(filter.to_block_exclusive, Some(end) if next_block >= end)
- || next_block >= archive_height;
+ let exhausted = matches!(filter.to_block_exclusive, Some(end) if next_block >= end)
+ || archive_height.is_some_and(|h| next_block >= h);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/src/executor/data.rs` around lines 54 - 58, Don't coerce
response.archive_height to 0; keep it as an Option and only render or use it
when present. Replace the let archive_height =
response.archive_height.unwrap_or(0) with an Option binding (e.g., let
archive_height_opt = response.archive_height), change the rendering to call
toon::render_archive_height only when archive_height_opt.is_some() (or map to
i64 via archive_height_opt.map(|h| h as i64)), and update the
pagination/exhaustion checks to rely on archive_height_opt being Some rather
than comparing against 0; reference response.archive_height, archive_height_opt,
selection.known_height, and toon::render_archive_height when making the changes.
df506dc to
3d4cde5
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
packages/cli/src/data/field_selection.rs (1)
173-176: ⚡ Quick winStrengthen these tests to assert full parsed values, not just count.
At Line 175 and Line 181, length-only assertions can miss incorrect section/field resolution. Please assert the full expected parsed output.
Proposed test tightening
#[test] fn accepts_all_lowercase() { let sel = Selection::parse(&["block.gaslimit".into(), "log.blocknumber".into()]).unwrap(); - assert_eq!(sel.columns.len(), 2); + let cols: Vec<(Section, &str)> = sel + .columns + .iter() + .map(|c| (c.section, c.indexer_name.as_str())) + .collect(); + assert_eq!( + (cols, sel.known_height), + ( + vec![(Section::Block, "gaslimit"), (Section::Log, "blocknumber")], + false, + ), + ); } #[test] fn accepts_uppercase() { let sel = Selection::parse(&["block.GAS_LIMIT".into(), "log.TOPIC0".into()]).unwrap(); - assert_eq!(sel.columns.len(), 2); + let cols: Vec<(Section, &str)> = sel + .columns + .iter() + .map(|c| (c.section, c.indexer_name.as_str())) + .collect(); + assert_eq!( + (cols, sel.known_height), + ( + vec![(Section::Block, "GAS_LIMIT"), (Section::Log, "TOPIC0")], + false, + ), + ); }As per coding guidelines,
**/*.rs: “Always use single assert to check the whole value instead of multiple asserts for every field”.Also applies to: 179-182
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/src/data/field_selection.rs` around lines 173 - 176, The test accepts_all_lowercase currently only checks sel.columns.len(); instead assert the full parsed output from Selection::parse for the inputs "block.gaslimit" and "log.blocknumber" — e.g., compare sel.columns to the expected vector of parsed section/field pairs (("block","gaslimit"), ("log","blocknumber")) or the equivalent Column/Selection struct literal so the exact names and ordering are validated; do the same tightening for the other test around lines 179-182 to assert full parsed values instead of just length.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/CommandLineHelp.md`:
- Line 404: Replace the inconsistent level-6 headings (e.g., the literal string
"###### **Arguments:**" and the other similar occurrences noted) with the next
expected heading level (for example "### **Arguments:**") so the document uses a
consistent, valid heading hierarchy and fixes markdownlint MD001; update each
matching heading instance (the ones around the sections flagged) to the correct
level.
- Around line 412-414: The inline example for the --where flag is not fenced and
triggers markdownlint MD037; wrap the snippet starting with --where='{ block: {
number: { _gte: 1000, _lte: 2000 } }, log: { srcAddress: "0xa0b8..." }, }' in
a fenced code block (use ```bash before and ``` after) so the example is
rendered as a code block and fixes the lint error and readability issues.
In `@packages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.md`:
- Around line 15-17: The fenced code block in SKILL.md that contains the command
example "envio data <field>... --chain=<id|name> [--where='<json5>']" is missing
a language tag; update the opening fence so it reads ```bash to satisfy MD040
and match other examples, i.e., add the bash language identifier to the fenced
code block in the file.
---
Nitpick comments:
In `@packages/cli/src/data/field_selection.rs`:
- Around line 173-176: The test accepts_all_lowercase currently only checks
sel.columns.len(); instead assert the full parsed output from Selection::parse
for the inputs "block.gaslimit" and "log.blocknumber" — e.g., compare
sel.columns to the expected vector of parsed section/field pairs
(("block","gaslimit"), ("log","blocknumber")) or the equivalent Column/Selection
struct literal so the exact names and ordering are validated; do the same
tightening for the other test around lines 179-182 to assert full parsed values
instead of just length.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a9408b13-bf78-423a-8a3e-7cfa7a1a691c
⛔ Files ignored due to path filters (2)
Cargo.lockis excluded by!**/*.lockpackages/cli/src/cli_args/snapshots/envio__cli_args__clap_definitions__test__envio_help_snapshot.snapis excluded by!**/*.snap
📒 Files selected for processing (18)
CLAUDE.mdpackages/cli/Cargo.tomlpackages/cli/CommandLineHelp.mdpackages/cli/examples/script.rspackages/cli/src/cli_args/clap_definitions.rspackages/cli/src/data/chain.rspackages/cli/src/data/field_selection.rspackages/cli/src/data/mapping.rspackages/cli/src/data/mod.rspackages/cli/src/data/toon.rspackages/cli/src/data/where_filter.rspackages/cli/src/executor/data.rspackages/cli/src/executor/mod.rspackages/cli/src/lib.rspackages/cli/src/template_dirs.rspackages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.mdpackages/cli/templates/static/shared/.claude/skills/indexer-testing/SKILL.mdpackages/cli/tests/data_integration.rs
✅ Files skipped from review due to trivial changes (4)
- packages/cli/src/data/mod.rs
- packages/cli/src/lib.rs
- packages/cli/templates/static/shared/.claude/skills/indexer-testing/SKILL.md
- CLAUDE.md
🚧 Files skipped from review as they are similar to previous changes (11)
- packages/cli/Cargo.toml
- packages/cli/src/template_dirs.rs
- packages/cli/examples/script.rs
- packages/cli/src/executor/mod.rs
- packages/cli/src/data/chain.rs
- packages/cli/src/cli_args/clap_definitions.rs
- packages/cli/src/executor/data.rs
- packages/cli/tests/data_integration.rs
- packages/cli/src/data/mapping.rs
- packages/cli/src/data/toon.rs
- packages/cli/src/data/where_filter.rs
|
|
||
| **Usage:** `envio data [OPTIONS] --chain <CHAIN> [FIELD]...` | ||
|
|
||
| ###### **Arguments:** |
There was a problem hiding this comment.
Use consistent heading increments in new sections.
These ###### headings skip levels and trigger markdownlint MD001. Please change them to the next expected level (e.g., ###) to keep heading structure valid.
Also applies to: 443-443, 456-456, 468-468
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 404-404: Heading levels should only increment by one level at a time
Expected: h3; Actual: h6
(MD001, heading-increment)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/CommandLineHelp.md` at line 404, Replace the inconsistent
level-6 headings (e.g., the literal string "###### **Arguments:**" and the other
similar occurrences noted) with the next expected heading level (for example
"### **Arguments:**") so the document uses a consistent, valid heading hierarchy
and fixes markdownlint MD001; update each matching heading instance (the ones
around the sections flagged) to the correct level.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/cli/CommandLineHelp.md`:
- Line 396: The fenced code block is on a single line causing MD038; fix the
markdown by placing the opening ```text and closing ``` on their own lines and
move the command content between them, splitting long command arguments onto
separate indented lines (e.g., break after each backslash) so the command shown
(envio data block.number log.srcAddress log.transactionHash \ --chain=base \
--where='...') is on multiple lines between the fences.
- Line 400: The code fence and its content are on the same line for the example
with the command "envio data knownHeight --chain=arbitrum-one"; update the
markdown so the opening ```text and closing ``` are each on their own lines and
the command appears on the line(s) between them (i.e., change the single-line
"```text envio data knownHeight --chain=arbitrum-one ```" to a proper fenced
block with ```text on its own line, the command on the next line, and ``` on the
following line).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 88ea746a-1ac1-4d5c-b5bd-fc40b4928eb9
📒 Files selected for processing (2)
packages/cli/CommandLineHelp.mdpackages/cli/src/cli_args/clap_definitions.rs
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/cli/src/cli_args/clap_definitions.rs
|
|
||
| Current archive height: | ||
|
|
||
| ```text envio data knownHeight --chain=arbitrum-one ``` |
There was a problem hiding this comment.
Fix code fence formatting—content must be on separate lines.
Same issue as line 396: the fence and content are on one line.
📝 Proposed fix
-```text envio data knownHeight --chain=arbitrum-one ```
+```text
+envio data knownHeight --chain=arbitrum-one
+```📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ```text envio data knownHeight --chain=arbitrum-one ``` |
🧰 Tools
🪛 markdownlint-cli2 (0.22.1)
[warning] 400-400: Spaces inside code span elements
(MD038, no-space-in-code)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/cli/CommandLineHelp.md` at line 400, The code fence and its content
are on the same line for the example with the command "envio data knownHeight
--chain=arbitrum-one"; update the markdown so the opening ```text and closing
``` are each on their own lines and the command appears on the line(s) between
them (i.e., change the single-line "```text envio data knownHeight
--chain=arbitrum-one ```" to a proper fenced block with ```text on its own line,
the command on the next line, and ``` on the following line).
Wraps the HyperSync `/query` REST endpoint behind a CLI that uses the same indexer-style `where` syntax as event filters and prints results in TOON tabular form. Field selectors are indexer-side camelCase (`block.number`, `log.srcAddress`, `transaction.transactionIndex`, `receipt.contractId`) mapped to HS snake_case via a per-chain table derived from `HyperSyncJsonApi.res` and `HyperFuelClient.res`. Supports `--chain=<id|name>` for EVM chains and the special values `fuel` / `fuel-testnet`; Solana errors with a friendly hint. `--where` accepts YAML (default) or JSON, with `_gte/_gt/_lte/_lt` on the block range collapsed into HS `from_block`/`to_block`. The `knownHeight` pseudo-field hits `/height` directly when used alone, or appends the archive height to a `/query` response when mixed with real fields. After the data, prints `archive_height` + `next_block` and a ready-to-run pagination hint to stderr so stdout stays pipeable. Replaces the curl-based "Finding Block Ranges with HyperSync" recipe in the indexer-testing skill with a pointer to a new `envio-data` skill. Integration tests under `--features integration_tests` hit live HyperSync (Base + Fuel testnet) end-to-end.
The where parser is now JSON5 — JSON-style braces with relaxed grammar
(unquoted keys, single quotes, trailing commas, `//` comments) — so
typical filters read like:
--where='{
block: { number: { _gte: 1000, _lte: 2000 } },
log: { srcAddress: "0xabc" },
}'
The pagination hint is also emitted as a one-line JSON5 object so it
can be pasted straight back into --where. User-facing copy
(`envio data --help`, the envio-data skill, indexer-testing's block-
range section) now describes the feature as "blockchain data" rather
than naming the HyperSync backend.
Replace raw reqwest HTTP calls with the hypersync_client Rust crate for
EVM chains. The native client handles retries, rate limiting, payload-
too-large auto-splitting, and binary serialization — all free.
- mapping.rs: TypedField enum maps indexer names to net_types field
enums (BlockField/TransactionField/LogField). Adds new EVM fields
(blobGasUsed, l1Fee, yParity, etc.) from the crate's full enum set.
- field_selection.rs: build_net_field_selection() returns typed
net_types::FieldSelection (BTreeSet) for the native client path.
- where_filter.rs: build_net_query() returns net_types::Query via the
builder API with LogFilter/TransactionFilter.
- toon.rs: render_query_response() accepts typed QueryResponse and
extracts values from simple_types structs using Hex::encode_hex().
- executor/data.rs: split into run_evm() (native client) and run_fuel()
(reqwest fallback). User agent is envio-data/{version}.
Fuel chains remain on the reqwest + JSON path since hypersync_client is
EVM-only.
287 unit tests + 4 live integration tests pass.
Drop ChainKind enum and all Fuel/receipt/input/output code paths from the data module. Fuel/fuel-testnet now errors with "not supported yet" like Solana. This removes ~1000 lines: the FUEL_FIELDS mapping table, the reqwest-based JSON query path (build_query_body, render_response, fetch_height, post_query), and the Section::Receipt/Input/Output variants. Integration tests rewritten as end-to-end CLI invocations via `cargo run --example script -- data ...` instead of calling internal APIs. Tests cover: height query, block+log query, no-where pagination, missing token error, unknown chain, solana hint, unknown field.
- Replace hs_name string with typed field enum directly: FieldEntry.field is now TypedField (non-optional), Column.hs_name and FieldFilter.hs_name removed — all dead code since the native client path uses typed enums. - Add backtick fences around CLI examples in --help. - Simplify FIELD help text (remove implementation details about /height). - Add FIXME for Solana-specific field names in Selection::parse. - Remove "Advanced: Finding Block Ranges" from indexer-testing skill. - Revert test-indexer user agent logic from Main.res (keeping the ~userAgent plumbing in place for future use).
mapping.rs: Replace the 460-line hand-written FieldEntry table with ~40 lines that derive field lookups from strum's EnumString (camelCase → snake_case → from_str) and EnumIter (valid-names hint). Only alias: srcAddress → address. toon.rs: Replace 200 lines of per-field match arms (block_field_to_string, tx_field_to_string, log_field_to_string) with a generic Arrow column renderer. Uses get_arrow() instead of get() — columns are accessed by name from RecordBatch, and a single cell_to_string handles all 4 Arrow types (UInt64, UInt8, Boolean, Binary→hex). Bump strum to 0.27 to match hypersync-net-types. Add arrow 57 as a direct dep (already transitively present via hypersync-client). Net: -489 lines.
…rAgent threading - Replace all assert!(err.contains(...)) with insta::assert_snapshot! for exact error message coverage across chain, field_selection, and where_filter tests. - Load ENVIO_API_TOKEN from .env file (via dotenvy) when the env var is not set, matching the runtime behavior. - Update missing-token error wording to match the runtime's message. - Remove Setup section from envio-data skill (the CLI prompts when the token is missing). - Revert ~userAgent threading from all ReScript files (ChainManager, ChainFetcher, EvmChain, HyperSyncSource, HyperSyncClient, Main) back to main — keeping it for future use.
Normalize user input by lowercasing and stripping underscores, then match against enum variants (whose strum Display names get the same normalization). All of these now resolve to the same field: block.gasLimit block.gas_limit block.GASLIMIT block.GAS_LIMIT The approach uses strum EnumIter for exhaustiveness — any new variant added upstream is automatically discoverable without manual mapping. Output uses the user's original input verbatim (TOON column headers, error messages). Help text uses camelCase matching the indexer. Also stores the resolved TypedField in FieldFilter so build_net_query matches on the typed enum instead of string comparison — fixing the case where --where used non-canonical casing.
- Integration tests: replace all contains() checks with assert_eq! on the full error message. Extract error via "Caused by:" parsing, stopping at "Stack backtrace:". - envio-data skill: cut from 87 to 47 lines. Removed setup section, output details, and verbose tips. Added knownHeight and case- insensitivity to description for better skill pickup. - Clap help: moved TOON output line to its own paragraph so the one-liner in `envio --help` stays short. - CLAUDE.md: added rule "Never use contains in test assertions".
- Quantity fields (gasLimit, timestamp, value, etc.) now render as decimal instead of hex. Added ColumnFormat enum (Decimal/Hex) to TypedField, classified per the hypersync schema. Binary columns use ruint::U256 for big-endian → decimal conversion. - normalize_to_list now collects values from all operators (_eq, _in) instead of returning on the first match. - Removed 4 duplicate error-case integration tests (already covered by unit test snapshots). Kept 3 network-dependent end-to-end tests. - Added case-insensitive block range test for --where.
All assertion messages now include `{out}` which prints both stdout
and stderr via Display impl, so failures are immediately debuggable.
- query test: exact assert_eq on full stdout — 14 lines of deterministic
data from ETH mainnet block 20000000 (11 USDT Transfer events).
Verifies TOON format, decimal gasUsed, hex addresses, log indices.
- height test: asserts stdout structure (height[1]{value}: header +
parseable number) and stderr message format.
- no_where test: asserts exact stdout (blocks[0]{number}:) and stderr
structure (archive_height + next_block present).
Stderr contains live archive_height so it's checked structurally, not
by exact value.
- render_height/render_archive_height now emit `knownHeight[1]{value}:`
matching the positional field name the user typed.
- All integration tests assert the full stderr content via a
stderr_template() helper that replaces live numbers with <N>,
so the exact message structure is verified while tolerating
changing archive_height/next_block values.
- Use AsRefStr `as_ref()` instead of `to_string()` for field-enum comparisons (clippy::unnecessary_to_owned). - Replace single-arm match with `if` for the srcAddress alias (clippy::single_match).
Rustdoc tried to compile the example shell commands inside the `Data` variant's doc comment as Rust, failing CI's `cargo test --no-default-features`. Use ```text fences so they're rendered as code without compilation.
1d7010a to
7f5bf0b
Compare
Triple-backtick fences become single-line code blocks in the generated help.md (clap-markdown collapses doc-comment lines), triggering MD038. Inline single-backtick code spans render correctly as plain text in the help and avoid both MD038 and rustdoc's doctest parsing.
There was a problem hiding this comment.
♻️ Duplicate comments (4)
packages/cli/CommandLineHelp.md (3)
404-404:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUse consistent heading increments.
The
###### **Arguments:**heading skips levels and triggers markdownlint MD001. This pattern appears throughout the file but should use###to maintain proper heading hierarchy.📝 Proposed fix
-###### **Arguments:** +### **Arguments:**🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/CommandLineHelp.md` at line 404, Multiple headings like "###### **Arguments:**" use inconsistent heading levels and trigger markdownlint MD001; replace those instances with a consistent level (e.g., "### **Arguments:**") across CommandLineHelp.md so headings follow proper hierarchy, and scan the file for other repeated "######" headings (such as any "###### **Options:**" or similar) to normalize them to the chosen level to maintain consistent increments.
412-414:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winFormat the
--whereexample as a fenced code block.The inline
--whereexample triggers markdownlint MD037 and reduces readability. Wrapping it in a fenced code block will fix the linting issue and improve presentation.📝 Proposed fix
-* `--where <WHERE_FILTER>` — Filter in indexer `where` form, as JSON5 — JSON-style braces with relaxed syntax: unquoted keys, single quotes, trailing commas, and `//` comments are all accepted. Example: - - --where='{ block: { number: { _gte: 1000, _lte: 2000 } }, log: { srcAddress: "0xa0b8..." }, }' +* `--where <WHERE_FILTER>` — Filter in indexer `where` form, as JSON5 — JSON-style braces with relaxed syntax: unquoted keys, single quotes, trailing commas, and `//` comments are all accepted. Example: + ```bash + --where='{ block: { number: { _gte: 1000, _lte: 2000 } }, log: { srcAddress: "0xa0b8..." } }' + ```🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/CommandLineHelp.md` around lines 412 - 414, Wrap the inline --where example in a fenced code block (use triple backticks and specify bash) so the example becomes a standalone code block; locate the line containing "--where='{ block: { number: { _gte: 1000, _lte: 2000 } }, log: { srcAddress: "0xa0b8..." }, }'" and surround it with ```bash and ``` to satisfy markdownlint MD037 and improve readability.
396-396:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winFix code fence formatting—content must be on separate lines.
Both example code blocks have the opening fence, command text, and closing fence on a single line, triggering markdownlint MD038 and causing incorrect rendering.
📝 Proposed fix
-```text envio data block.number log.srcAddress log.transactionHash \ --chain=base \ --where='{ block: { number: { _gte: 0 } }, log: { srcAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" }, }' ``` +```text +envio data block.number log.srcAddress log.transactionHash \ + --chain=base \ + --where='{ block: { number: { _gte: 0 } }, log: { srcAddress: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" }, }' +```-```text envio data knownHeight --chain=arbitrum-one ``` +```text +envio data knownHeight --chain=arbitrum-one +```Also applies to: 400-400
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/cli/CommandLineHelp.md` at line 396, The code fence lines in CommandLineHelp.md currently place the opening fence, content, and closing fence on one line (triggering MD038); split each problematic inline fence into a proper multi-line fenced code block by moving the command text onto its own lines between ```text and ```, e.g., update the example block containing "envio data block.number log.srcAddress log.transactionHash \ --chain=base \ --where=..." and the block with "envio data knownHeight --chain=arbitrum-one" so the fence markers are on their own lines and the command lines (including backslash continuations) sit between them, preserving indentation and trailing backslashes as shown in the proposed fix.packages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.md (1)
15-17:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd language tag to fenced code block.
The command synopsis fence is missing a language identifier, triggering markdownlint MD040. Use
bashfor consistency with other command examples.📝 Proposed fix
-``` +```bash envio data <field>... --chain=<id|name> [--where='<json5>']</details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.In
@packages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.md
around lines 15 - 17, The fenced code block showing the command synopsis "envio
data ... --chain=<id|name> [--where='']" is missing a language
tag; update that fenced block to include the bash language identifier (i.e.,
changetobash) so markdownlint MD040 is satisfied and it matches other
command examples.</details> </blockquote></details> </blockquote></details> <details> <summary>🤖 Prompt for all review comments with AI agents</summary>Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.Duplicate comments:
In@packages/cli/CommandLineHelp.md:
- Line 404: Multiple headings like "###### Arguments:" use inconsistent
heading levels and trigger markdownlint MD001; replace those instances with a
consistent level (e.g., "### Arguments:") across CommandLineHelp.md so
headings follow proper hierarchy, and scan the file for other repeated "######"
headings (such as any "###### Options:" or similar) to normalize them to the
chosen level to maintain consistent increments.- Around line 412-414: Wrap the inline --where example in a fenced code block
(use triple backticks and specify bash) so the example becomes a standalone code
block; locate the line containing "--where='{ block: { number: { _gte: 1000,
_lte: 2000 } }, log: { srcAddress: "0xa0b8..." }, }'" and surround it with
bash andto satisfy markdownlint MD037 and improve readability.- Line 396: The code fence lines in CommandLineHelp.md currently place the
opening fence, content, and closing fence on one line (triggering MD038); split
each problematic inline fence into a proper multi-line fenced code block by
moving the command text onto its own lines betweentext and, e.g., update
the example block containing "envio data block.number log.srcAddress
log.transactionHash \ --chain=base \ --where=..." and the block with "envio data
knownHeight --chain=arbitrum-one" so the fence markers are on their own lines
and the command lines (including backslash continuations) sit between them,
preserving indentation and trailing backslashes as shown in the proposed fix.In
@packages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.md:
- Around line 15-17: The fenced code block showing the command synopsis "envio
data ... --chain=<id|name> [--where='']" is missing a language
tag; update that fenced block to include the bash language identifier (i.e.,
changetobash) so markdownlint MD040 is satisfied and it matches other
command examples.</details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: Organization UI **Review profile**: CHILL **Plan**: Pro **Run ID**: `376b17d9-2f36-4d06-975f-96fd9bf192db` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 1d7010ad4e6a557e0881bb41d88a4f6d0baee478 and 7f5bf0b7026f74cfeaeac1a9e1e091710b228d98. </details> <details> <summary>⛔ Files ignored due to path filters (2)</summary> * `Cargo.lock` is excluded by `!**/*.lock` * `packages/cli/src/cli_args/snapshots/envio__cli_args__clap_definitions__test__envio_help_snapshot.snap` is excluded by `!**/*.snap` </details> <details> <summary>📒 Files selected for processing (18)</summary> * `CLAUDE.md` * `packages/cli/Cargo.toml` * `packages/cli/CommandLineHelp.md` * `packages/cli/examples/script.rs` * `packages/cli/src/cli_args/clap_definitions.rs` * `packages/cli/src/data/chain.rs` * `packages/cli/src/data/field_selection.rs` * `packages/cli/src/data/mapping.rs` * `packages/cli/src/data/mod.rs` * `packages/cli/src/data/toon.rs` * `packages/cli/src/data/where_filter.rs` * `packages/cli/src/executor/data.rs` * `packages/cli/src/executor/mod.rs` * `packages/cli/src/lib.rs` * `packages/cli/src/template_dirs.rs` * `packages/cli/templates/static/shared/.claude/skills/envio-data/SKILL.md` * `packages/cli/templates/static/shared/.claude/skills/indexer-testing/SKILL.md` * `packages/cli/tests/data_integration.rs` </details> <details> <summary>💤 Files with no reviewable changes (1)</summary> * packages/cli/templates/static/shared/.claude/skills/indexer-testing/SKILL.md </details> <details> <summary>✅ Files skipped from review due to trivial changes (2)</summary> * packages/cli/src/lib.rs * packages/cli/src/data/mod.rs </details> <details> <summary>🚧 Files skipped from review as they are similar to previous changes (13)</summary> * CLAUDE.md * packages/cli/src/executor/mod.rs * packages/cli/src/data/field_selection.rs * packages/cli/examples/script.rs * packages/cli/src/template_dirs.rs * packages/cli/Cargo.toml * packages/cli/src/data/chain.rs * packages/cli/src/cli_args/clap_definitions.rs * packages/cli/src/data/toon.rs * packages/cli/tests/data_integration.rs * packages/cli/src/data/mapping.rs * packages/cli/src/executor/data.rs * packages/cli/src/data/where_filter.rs </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
- Spell every BlockField/TransactionField/LogField variant so the compiler flags new variants instead of silently defaulting to Hex. - Drop the archive_height/next_block stderr lines and the "Done — next_block ..." message; only print a pagination hint when the query is not exhausted. - Rephrase the pagination hint to explain it shows the next query. https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
- Drop the chain-height aside from the normal next-page hint and reword it as "run the following command". - When next_block reaches archive_height, emit a dedicated message explaining we hit the chain head and that rerunning the same command later picks up newly available data. - Range-exhausted pagination stays silent. https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
TOON scalars use 'key: value', not a single-row table — drop the
[1]{value} table form for both render_height and render_archive_height.
https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
Note that all block/log/transaction fields are supported, and that the where syntax accepts the full operator set (_eq, _in, _gte, _lte, _gt, _lt) — replace the standalone operators table with a one-liner. https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
- Drop the H1 intro that duplicated the frontmatter description; keep only the "do NOT web-search" emphasis as a standalone note. - Replace "etc." with explicit "any EVM block/log/transaction field". - Add an indexer-testing tip pointing at the envio-data skill for block range lookups. https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
- Drop the dead `indexer_name: String` field on both `Column` and `FieldFilter`; derive the user-facing name via a new `TypedField::camel_name()` helper, so the canonical camelCase is echoed back in TOON headers, pagination hints, and error messages regardless of the case the user typed. - Delete `render_archive_height` (verbatim copy of `render_height`) and change `render_height` to take `u64`, matching the upstream types and removing the `as i64` casts at call sites. - Factor the log/transaction filter setup into `apply_log_filter` and `apply_tx_filter` so the two halves of `build_net_query` no longer duplicate the `filter_values_as_strs` + `.as_str()` plumbing. - Collapse the Solana/Fuel "not supported yet" branches in `chain::resolve` into a single match keyed on the chain family name. - Replace the three booleans driving pagination output with a `PaginationState` enum and a single `match`, so the dispatch is exhaustive. - Fold the empty-string token guard into `resolve_api_token`'s return filter instead of trimming after `ok_or_else`. - Replace the hand-rolled digit walker in `stderr_template()` with a one-line regex (the crate already depends on `regex`). - Tighten `data::*` module visibility to `pub(crate)` — none of these types cross the NAPI boundary. - Drop the stale `// FIXME: EVM-specific` comment that violated the "don't narrate" convention. - Promote `render_table` to take `&[impl AsRef<str>]` so callers can pass `Vec<String>` without a transient `Vec<&str>` allocation. - Replace `_ => String::new()` in `cell_to_string` with an `unreachable!` — the column set is bounded, silently dropping unexpected arrow types would only mask bugs. - Fix the `--where` documentation in the envio-data SKILL to reflect the actual filterable surface (block.number ranges, log addr/topic0-3, tx from/to/sighash) instead of claiming every field supports every operator. All 313 unit tests still pass; clippy is clean with `-D warnings`. https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
The `hypersync-health-check` CI job runs `cargo test` with a feature flag intended only for pinging public hypersync endpoints. When the new `envio data` integration tests were added they reused the same flag, so the health-check job ended up running them too — and a flaky "page from genesis" assertion broke the job on every push. - Rename the existing `integration_tests` feature to `hypersync_health` so its scope is obvious from the name; update the gated module in `hypersync_endpoints.rs` and the CI workflow. - Add a new `data_integration_tests` feature gating `tests/data_integration.rs`, so the data tests are runnable on their own (`cargo test --features data_integration_tests`) without being pulled into the health check. https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
- Drop the `data_integration_tests` feature gate from `tests/data_integration.rs` so the tests are picked up by `cargo test --no-default-features` (the cargo-test CI job). - Add a `skip_without_token()` helper so each test silently skips when `ENVIO_API_TOKEN` is absent — keeps local `cargo test` and fork-PR builds green while still exercising the suite anywhere the secret is available (workflow-level env var). - Reinstate `integration_tests` as a compat alias for `hypersync_health` so the base-branch workflow (still on main until this PR lands) continues to find the feature it asks for. Drop after main picks up the renamed step. - Replace the flaky "page from genesis" test with a deterministic filter (`block 18_000_000..=19_000_000`, USDT logs) that always exceeds one hypersync batch and therefore always hits the `MorePages` branch. - Tighten the digit-replacing template regex to `\b\d+\b` so digits embedded in hex addresses keep their literal characters while standalone integers (block numbers, chain id) become `<N>`. - Echo back the user's `--chain=` input in the pagination hint by storing the normalized user string in `Chain.display` instead of the resolved chain id. https://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
) * feat(cli): filter `envio data` by any field Extend the `envio data` `--where` filter to accept any block, transaction, or log field. Set-membership filters on fields Hypersync can filter (log address/topics, transaction from/to/sighash/hash/contractAddress) are pushed to the server. Everything else — other fields, and all `_gt`/`_gte`/`_lt`/`_lte` comparisons (numeric only; rejected on hex fields) — is evaluated client-side over the Arrow response. Client filters apply per-section, so related rows in other sections may remain. * feat(cli): push transaction status/type and block hash/miner server-side Extend the server-filterable set in `envio data --where` to the remaining fields with a Hypersync builder: transaction `status` (single value) and `type`, and block `hash`/`miner` (via `where_blocks`). Multi-value `status` falls back to client-side since the server takes a single value. `TypedField::server_filterable` stays the single source of truth for which fields route server-side; each filter type's builder dispatch enforces that invariant. * docs(cli): compact --where help text * refactor(cli): drive --where field handling from a FieldSpec registry Replace the scattered `server_filterable` predicate, alias lookup, and per-section builder matches with a single per-field config: each field resolves to a `FieldSpec { aliases, value_kind, server }`. - `value_kind` (Numeric/Hex/Bool) drives client parse, compare, and render, and makes comparison support explicit (numeric only). - `server: Option<ServerFilter>` is the single source of truth for server-side routing; one tag-driven apply per filter type dispatches it. - aliases move into the spec; lookup matches name or any alias. Collapses the three section-specific server-filter vectors into one `server_filters` list. Behavior-preserving. * test(cli): end-to-end client-side --where filtering; tighten help + skill - Add an integration test driving the full pipeline (parse --where → classify → compute_masks → render): numeric range, `_in`, and a big-endian binary numeric comparison across two sections. - Make the --where help text terser. - Update the envio-data skill: any field is filterable, with numeric comparison ops; refresh examples. --------- Co-authored-by: Claude <noreply@anthropic.com>
* Fix envio data returning empty for filter-less block/log/transaction selections HyperSync only returns rows that match a selection, so a query like `envio data block.hash --chain=base` produced an empty response: no log/transaction/block selection meant nothing to return. Add an unfiltered selection for every entity the user requests fields for, and set include_all_blocks when block fields are wanted but no filter scopes the blocks. Bare queries now stream from block zero. * Support _eq/_in and shorthand for block.number in envio data block.number now accepts the same forms as other fields: a scalar or `_eq` pins a single block, and an array or `_in` scans [min, max] then drops the leftover blocks client-side. Comparison operators keep their existing range semantics. The pagination hint folds a carried-forward set back into the number range so reruns keep filtering the same blocks. * Use block.number shorthand in block-only integration test --------- Co-authored-by: Claude <noreply@anthropic.com>
…ts, auto-paginate sparse results (#1280) - TOON headers now echo the field name exactly as typed (block.NUMBER -> NUMBER) - next-page hint for a block.number set carries only the unfetched values as _in - automatically fetch following pages while fewer than 100 rows are available Co-authored-by: Claude <noreply@anthropic.com>
Introduces a new
envio dataCLI command that enables querying raw blockchain data (blocks, logs, transactions) on EVM chains using the samewherefilter syntax as indexer definitions.Summary
Users can now query blockchain data directly via the CLI without web-searching or manual API calls:
envio data block.number log.srcAddress --chain=base \ --where='{ block: { number: { _gte: 1000 } }, log: { srcAddress: "0xabc" } }'The command supports:
_gte,_gt,_lte,_ltoperatorsknownHeightfield to query current archive heightKey Changes
New modules under
packages/cli/src/data/:mapping.rs: Field name normalization and type mapping (Block/Transaction/Log fields)field_selection.rs: Parses positional field arguments with validationwhere_filter.rs: Parses JSON5--wherefilters and builds HyperSync querieschain.rs: Resolves chain names/IDs to HyperSync endpointstoon.rs: Renders Arrow response data in TOON (token-oriented) tabular formatNew executor module (
packages/cli/src/executor/data.rs):Integration tests (
packages/cli/tests/data_integration.rs):integration_testsfeature)CLI integration:
Data(DataArgs)variant toCommandTypeenumDataArgsstruct withfields,--chain,--whereargumentsDocumentation:
.claude/skills/envio-data/SKILL.mdCommandLineHelp.mdwith new commandImplementation Details
_lte: 2000→to_block_exclusive: 2001)tableName[rowCount]{col1,col2}: row1,row2,...0xprefix; large numbers use decimal representationENVIO_API_TOKENenv var or.envfilehttps://claude.ai/code/session_01FfD3LmqB1n5DJ5KX1dmDjA
Summary by CodeRabbit
New Features
envio dataCLI to query EVM chain blocks/transactions/logs with selectable fields, chain resolution, JSON5-like--wherefilters (relaxed syntax), TOON tabular output, and known/archive height support (Solana not supported yet).Documentation
envio data; added guidance to use full-value test assertions (avoidcontains).Tests
Chores