contracts
A global registry: every contract declared here is usable from any workflow, trigger, or step by name.
rflow_version: 1
name: contract-registry
config:
port: 3940
db_connection: ${DATABASE_URL}
networks:
- name: ethereum
chain_id: 1
rpc: ${ETH_RPC}
- name: base
chain_id: 8453
rpc: ${BASE_RPC}
contracts:
USDC:
abi: ./abis/erc20.json
addresses: # per-network map
ethereum: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
base: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
Treasury:
abi: ./abis/treasury.json
network: ethereum # single-network shorthand
address: "0xDep..."
UniV3Factory: # the factory AnyPool tracks (see below)
abi: ./abis/univ3-factory.json
network: ethereum
address: "0x1F98431c8aD98523631AE4a59f267346ea31F984"
AnyPool:
abi: ./abis/univ3-pool.json
factory: # every child the factory ever deployed
contract: UniV3Factory
event: PoolCreated
network: ethereum
workflows:
treasury-inflow:
trigger:
event: { contract: USDC, name: Transfer, network: ethereum }
steps:
- id: treasury-balance
read:
contract: USDC
network: ethereum
function: "balanceOf(address)"
args: ["${{ contracts.Treasury.address }}"]| Field | Description |
|---|---|
abi | ✅ Path to the ABI json file, relative to the project directory; rflow abi fetch downloads the verified one for you |
addresses | Per-network map: network → address (or a list of addresses) |
network + address | Single-network shorthand; address also accepts a list |
factory | Factory tracking: match every child deployed by a factory |
index_events | Index these events for query: WITHOUT firing any workflow (see below) |
Use exactly one address form (addresses, network/address, or factory);
validation checks this and that every referenced network exists.
index_events — index-only analytics
index_events: indexes a contract's events into Postgres without any
workflow firing. The rows are the historical dataset for
query: steps and the
query trigger:
rflow_version: 1
name: usdc-analytics
config:
port: 3940
db_connection: ${DATABASE_URL}
networks:
- name: ethereum
chain_id: 1
rpc: ${ETH_RPC}
contracts:
USDC:
abi: ./abis/erc20.json
network: ethereum
address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
index_events: [Transfer, Approval]
workflows:
daily-volume:
trigger:
cron:
expression: "0 9 * * *"
steps:
- id: volume
query:
sql: "SELECT COALESCE(SUM(value::numeric), 0) FROM rflow_idx_usdc.transfer"Rows land in rflow_idx_<contract>.<event>
(rflow_idx_usdc.transfer here; run
rflow tables to see the live catalog). Indexing writes
nothing to the run journal: no runs, no claims, no cursors.
Limits:
- Indexing starts at the current head when
rflow startboots the indexer; there is no per-contract backfill knob yet. For deep history, point an event-trigger workflow (which ownsstart_blocksemantics) at the contract instead. index_eventson afactory:-tracked contract is not supported yet;rflow validate(and boot) errors.- Each event name must exist in the contract's ABI (validated); declaring an event some workflow also triggers on is fine but flagged as a warning because the rows are stored twice (once per table-naming family).
Factory tracking
factory: scopes a contract to every child a factory ever deployed, past and
future. The classic use is DEX pools:
rflow_version: 1
name: pool-watch
config:
port: 3940
db_connection: ${DATABASE_URL}
networks:
- name: ethereum
chain_id: 1
rpc: ${ETH_RPC}
contracts:
UniV3Factory:
abi: ./abis/univ3-factory.json
network: ethereum
address: "0x1F98431c8aD98523631AE4a59f267346ea31F984"
AnyPool:
abi: ./abis/univ3-pool.json
factory: { contract: UniV3Factory, event: PoolCreated, network: ethereum }
notifications:
channels:
ops:
console: {}
workflows:
any-pool-swap:
trigger:
event: { contract: AnyPool, name: Swap, network: ethereum }
steps:
- notify:
channel: ops
message: "swap in pool ${{ trigger.address }}"An event trigger on AnyPool fires for a Swap in
any pool, including pools created after rflow started.
| Field | Description |
|---|---|
contract | ✅ Name of the factory contract in this registry |
event | ✅ The deployment event on the factory (e.g. PoolCreated) |
network | ✅ Network to track the factory on |
Using registry entries
- Event triggers:
trigger: { event: { contract: USDC, name: Transfer, ... } } - Read steps:
read: { contract: USDC, function: "balanceOf(address)", ... } - Send steps:
send_transaction: { contract: USDC, function: "transfer(address,uint256)", ... } - Expressions:
${{ contracts.Treasury.address }}
Send steps may also target a raw to: "0x..." address without a registry entry;
the registry is for contracts you reference more than once or need ABIs for.