Skip to content

Commit 5ea86f5

Browse files
fubhyclaude
andcommitted
core: Implement struct field access in declarative calls (spec v1.4.0)
Adds named field access support for struct parameters in declarative calls (e.g., event.params.asset.addr). Field names are resolved to indices at parse time using ABI context for improved performance and user experience. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 966c26b commit 5ea86f5

File tree

5 files changed

+496
-428
lines changed

5 files changed

+496
-428
lines changed

chain/ethereum/src/data_source.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,6 @@ impl DataSource {
805805
&event_handler.calls,
806806
&log,
807807
&params,
808-
Some(&event_handler.event),
809808
)?;
810809
Ok(Some(TriggerWithHandler::<Chain>::new_with_logging_extras(
811810
MappingTrigger::Log {

docs/subgraph-manifest.md

Lines changed: 7 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ The `mapping` field may be one of the following supported mapping manifests:
9898

9999
### 1.5.3 Declaring calls
100100

101-
_Available from spec version 1.2.0_
101+
_Available from spec version 1.2.0. Struct field access available from spec version 1.4.0_
102102

103103
Declared calls are performed in parallel before the handler is run and can
104104
greatly speed up syncing. Mappings access the call results simply by using
@@ -122,76 +122,12 @@ Each call is of the form `<ABI>[<address>].<function>(<args>)`:
122122

123123
The `Expr` can be one of the following:
124124

125-
| Expression | Description | Example |
126-
| --- | --- | --- |
127-
| **event.address** | The address of the contract that emitted the event | `event.address` |
128-
| **event.params.&lt;name&gt;** | A simple parameter from the event | `event.params.token` |
129-
| **event.params.&lt;name&gt;.&lt;index&gt;** | A field from a struct parameter by numeric index | `event.params.asset.0` |
130-
| **event.params.&lt;name&gt;.&lt;fieldName&gt;** | A field from a struct parameter by field name | `event.params.asset.addr` |
131-
| **Nested struct access** | Arbitrary nesting depth with mixed access patterns | `event.params.data.1.user.id` |
132-
133-
#### Struct Field Access
134-
135-
When event parameters contain struct types (tuples in ABI), you can access individual fields using either numeric indices or field names:
136-
137-
**Numeric Access (Traditional):**
138-
```yaml
139-
calls:
140-
tokenAddress: ERC20[event.params.asset.0].name() # First field
141-
tokenAmount: ERC20[event.params.asset.1].decimals() # Second field
142-
```
143-
144-
**Named Access (Recommended):**
145-
```yaml
146-
calls:
147-
tokenAddress: ERC20[event.params.asset.addr].name() # By field name
148-
tokenAmount: ERC20[event.params.asset.amount].decimals() # By field name
149-
```
150-
151-
**Mixed Access Patterns:**
152-
```yaml
153-
calls:
154-
# Access first transfer, then recipient field by name
155-
recipient: Token[event.params.transfers.0.recipient].balanceOf()
156-
157-
# Deep nesting with mixed numeric and named access
158-
innerValue: Contract[event.params.data.1.user.addr].someFunction()
159-
```
160-
161-
#### Struct Field Access Examples
162-
163-
Given an event with this ABI structure:
164-
```json
165-
{
166-
"name": "AssetTransfer",
167-
"type": "event",
168-
"inputs": [
169-
{
170-
"name": "asset",
171-
"type": "tuple",
172-
"components": [
173-
{"name": "addr", "type": "address"},
174-
{"name": "amount", "type": "uint256"},
175-
{"name": "active", "type": "bool"}
176-
]
177-
}
178-
]
179-
}
180-
```
181-
182-
You can access fields in multiple ways:
183-
```yaml
184-
calls:
185-
# Named field access (clearest and recommended)
186-
tokenContract: ERC20[event.params.asset.addr].name()
187-
tokenDecimals: ERC20[event.params.asset.addr].decimals()
188-
189-
# Numeric field access (backward compatible)
190-
tokenContract: ERC20[event.params.asset.0].name()
191-
192-
# Mixed access for complex nested structures
193-
nestedField: Contract[event.params.data.0.inner.fieldName].process()
194-
```
125+
| Expression | Description |
126+
| --- | --- |
127+
| **event.address** | The address of the contract that emitted the event |
128+
| **event.params.&lt;name&gt;** | A simple parameter from the event |
129+
| **event.params.&lt;name&gt;.&lt;index&gt;** | A field from a struct parameter by numeric index |
130+
| **event.params.&lt;name&gt;.&lt;fieldName&gt;** | A field from a struct parameter by field name (spec version 1.4.0+) |
195131

196132

197133
## 1.6 Path

graph/src/data/subgraph/api_version.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,11 @@ pub const SPEC_VERSION_1_2_0: Version = Version::new(1, 2, 0);
6060
// represents the write order across all entity types in the subgraph.
6161
pub const SPEC_VERSION_1_3_0: Version = Version::new(1, 3, 0);
6262

63+
// Enables struct field access in declarative calls
64+
pub const SPEC_VERSION_1_4_0: Version = Version::new(1, 4, 0);
65+
6366
// The latest spec version available
64-
pub const LATEST_VERSION: &Version = &SPEC_VERSION_1_3_0;
67+
pub const LATEST_VERSION: &Version = &SPEC_VERSION_1_4_0;
6568

6669
pub const MIN_SPEC_VERSION: Version = Version::new(0, 0, 2);
6770

0 commit comments

Comments
 (0)