read
eth_call a view function. With assert: it becomes a hard gate; without, it's
enrichment for later steps.
- id: gate
read:
contract: USDC
network: base
function: "balanceOf(address)"
args: ["${{ relayers.payout.address }}"]
assert: "${{ output >= trigger.args.value }}"Fields
| Field | Required | Description |
|---|---|---|
contract | ✅ | A contract registry name |
network | ✅ | A declared network |
function | ✅ | Solidity signature, e.g. balanceOf(address) |
args | Arguments — each may be an expression | |
assert | Expression over the decoded output — false fails the step with kind assert_failed | |
on_error | fail | fail | continue — see below |
Output
The decoded return values become steps.<id>.output:
- a single return value is unwrapped:
balanceOf→steps.gate.outputis the balance itself - multiple return values become a map keyed by ABI output names (positional when unnamed)
uint256 outputs stay exact — compare and do math on them directly, see
U256 semantics.
assert — the gate
The assert: expression sees output alongside the full run context:
assert: "${{ output >= trigger.args.value and output > wei('1', 6) }}"A false assert fails the step with kind assert_failed — a deliberate stop, never
retried. The run then follows on_failure.
on_error: continue — soft enrichment
By default a failed read (RPC error, revert, false assert) fails the step. Set
on_error: continue to turn it into soft enrichment instead: the step succeeds with
output: null and the run continues.
- id: price
read:
contract: Oracle
network: ethereum
function: "latestAnswer()"
on_error: continue # nice-to-have, not load-bearing