Read trigger
Poll a view function on an interval and fire when a condition is met β health
factors, utilization, oracle staleness, anything an eth_call can see.
workflows:
high-utilization:
trigger:
read:
contract: LendingPool
network: ethereum
function: "getUtilization()"
every: 1m
condition: "${{ output > wei('0.95', 18) }}"
mode: threshold # threshold (default) | changed
steps:
- id: alert
notify:
channel: ops
message: "utilization crossed 95%: ${{ format_units(trigger.args.output, 18) }}"| Field | Required | Description |
|---|---|---|
contract | β | A contract registry name |
network | β | A declared network |
function | β | Solidity signature, e.g. getUtilization() |
args | Arguments β each may be an expression | |
every | β | Poll interval, e.g. 1m |
condition | Firing condition over the decoded value β omitted, every poll fires | |
mode | threshold | threshold | changed β see below |
The decoded value is available to the condition: expression as output (alias
result), decoded exactly like a read: step.
Firing modes β edge-triggered, never spam
threshold(default) β fire when the condition is true and it was false on the previous poll: a falseβtrue crossing. A condition that stays true fires once, not every minute.changedβ fire when the decoded value differs from the previous poll's (the first observation only records a baseline).
The previous poll's state is persisted per workflow
(rflow.read_trigger_state), so a restart mid-"true" does not re-fire a
threshold trigger.
The trigger context
| Path | Description |
|---|---|
trigger.args.output / trigger.args.value | The decoded read value at fire time |
trigger.read.function, trigger.read.network | What was polled |
trigger.read.observed_at | Observation timestamp (ISO) |
Exactly-once
Each fire claims read:{workflow}:{poll instant} β one run per polling instant,
and the persisted edge state carries the dedupe across restarts.