Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Block trigger

Fire a workflow every N blocks on a network: keeper duties, per-block checks, periodic onchain maintenance that should track chain time rather than wall time.

rflow_version: 1
name: keeper
 
config:
  port: 3947
  db_connection: ${DATABASE_URL}
 
networks:
  - name: ethereum
    chain_id: 1
    rpc: ${ETH_RPC}
 
signer:
  raw:
    mnemonic: ${RAW_DANGEROUS_MNEMONIC}
 
relayers:
  keeper:
    networks: [ethereum]
 
contracts:
  Keeper:
    abi: ./abis/keeper.json
    addresses:
      ethereum: "0x000000000000000000000000000000000000dEaD"
 
workflows:
  keeper:
    trigger: 
      block: 
        every: 10            # every 10th block 
        network: ethereum
    steps:
      - id: upkeep
        read:
          contract: Keeper
          network: ethereum
          function: "checkUpkeep()"
          assert: "${{ output }}"
      - id: perform
        send_transaction:
          network: ethereum
          relayer: keeper
          contract: Keeper
          function: "performUpkeep()"
FieldRequiredDescription
every✅Fire every N blocks (>= 1, validated). 1 fires every block
network✅A declared network

The trigger context

PathDescription
trigger.args.block_numberThe block that fired
trigger.args.networkThe network name

Semantics

  • One poll per network — workflows sharing a network share the head poll (~2s interval); every newly observed block number b with b % every == 0 fires.
  • Exactly-once — the claim key is derived from the block number (block:{network}:{number}), so poll overlap and restarts are duplicates, never double fires.
  • Catch-up is capped — the first poll after boot only anchors the head (no historical firing). After an RPC outage, every block in the observed gap is considered, capped at the newest 100 blocks with a warning: a long outage on a fast chain does not replay thousands of runs.

For "every block, act on the events in it", prefer an event trigger, which decodes and filters for you. For "poll a value until it crosses a line", prefer a read trigger. It is edge-triggered.