Skip to content

Commit b5cf837

Browse files
fubhyclaude
andcommitted
core: Support struct field access in declarative calls
Implement full support for named and mixed struct field access in declarative calls within subgraph manifests. This enables patterns like: - event.params.asset.addr (named field access) - event.params.asset.0.name (mixed numeric/named access) - event.params.data.1.user.id (arbitrary nesting depth) ## Key Changes ### Enhanced Field Access Architecture - Unified `StructField(Word, Vec<FieldAccess>)` supporting both numeric indices and property names - Added `FieldAccess` enum with `Index(usize)` and `Name(Word)` variants - Extended parsing to handle arbitrary nesting depth: `event.params.a.b.c.d` ### ABI-Driven Named Field Resolution - Added `StructFieldInfo` to preserve component field names from ABI JSON - Implemented `MappingABI::parse_struct_field_mappings()` for direct ABI JSON parsing - Extended `MappingABI` with `struct_field_mappings` field ### Smart Error Messages - Show available field names when invalid names are used - Provide declarative call context in all error messages - Suggest numeric alternatives when ABI context unavailable ### Integration with Event Processing - Added `*_with_abi()` method overloads accepting ABI context and event names - Modified `from_log_trigger_with_event()` to pass ABI information through call chain - Updated Ethereum data source to provide event context ## Why This Indirection is Necessary The ethabi crate has a significant limitation: when parsing ABI JSON into `ParamType` structures, **tuple field names are completely lost**. While the original ABI JSON contains rich component information like: ```json { "name": "asset", "type": "tuple", "components": [ {"name": "addr", "type": "address"}, {"name": "amount", "type": "uint256"} ] } ``` The ethabi parser converts this to `ParamType::Tuple(vec\![Address, Uint(256)])`, discarding the field names "addr" and "amount" entirely. This makes named field access impossible using ethabi's parsed structures alone. Our solution preserves the original ABI component information by: 1. **Direct ABI JSON parsing** to extract component field names before ethabi processing 2. **Parallel struct field mappings** that map field names to tuple indices 3. **Runtime field resolution** using the preserved component information This indirection is essential because: - **ethabi limitation**: Tuple field names are lost during ABI parsing - **User experience**: Named access like `asset.addr` is much clearer than `asset.0` - **Type safety**: We maintain ethabi's type safety while adding name resolution - **Backward compatibility**: Numeric indices continue to work unchanged ## Test Coverage - Comprehensive end-to-end test with real ABI JSON parsing - Error message validation with available field name suggestions - Mixed numeric/named access pattern testing - Integration testing with declarative call contexts - Reduced test suite from 19 to 16 tests by eliminating redundancy Addresses feedback from PR review and implements the complete named struct field access feature for Graph Node declarative calls. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent b7a5cc3 commit b5cf837

File tree

3 files changed

+480
-202
lines changed

3 files changed

+480
-202
lines changed

chain/ethereum/src/data_source.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -800,11 +800,12 @@ impl DataSource {
800800
"transaction" => format!("{}", &transaction.hash),
801801
});
802802
let handler = event_handler.handler.clone();
803-
let calls = DeclaredCall::from_log_trigger(
803+
let calls = DeclaredCall::from_log_trigger_with_event(
804804
&self.mapping,
805805
&event_handler.calls,
806806
&log,
807807
&params,
808+
Some(&event_handler.event),
808809
)?;
809810
Ok(Some(TriggerWithHandler::<Chain>::new_with_logging_extras(
810811
MappingTrigger::Log {

0 commit comments

Comments
 (0)