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

Treasury sweep with approval

Template: treasury-sweep-approval ยท category: treasury ยท risk: money_moving

A cron reads a hot treasury wallet's ERC20 balance; above a threshold the sweep to cold storage is prepared, simulated and parked behind a human approval (rflow approvals ls, rflow approve <id>). Runnable sibling: examples/treasury-ops.

When to use it

  • keep hot-wallet balances low without a human doing the transfer by hand
  • any recurring send where a person must stay in the loop

Generate it

rflow new --template treasury-sweep-approval
# or into an existing project (needs a signer; adds the `treasury` relayer):
rflow add workflow treasury-sweep-approval

Inputs

keytypedefault
project_namestringtreasury-ops
network / chain_id / rpc_env / rpc_urlnetwork / chain_id / env_var / stringethereum / 1 / ETH_RPC / a public RPC
token_address / token_decimalsaddress / intUSDC mainnet / 6
cold_storageaddresszero placeholder โ€” replace it
min_sweep_amounttoken_amount1000
sweep_croncron0 * * * * (hourly)
approval_timeoutduration1h
gas_max_pricestring100 gwei

Required env vars

DATABASE_URL, the RPC env var, RAW_DANGEROUS_MNEMONIC. rflow new fills .env with a freshly generated DEV-ONLY mnemonic โ€” swap in a production signer before real funds ride on this config.

Safety defaults (all generated)

  • pre-flight simulation + assert_sim: ["${{ sim.ok }}"]
  • gas cap: limit_from_simulation + max_price
  • post-approval re-simulation โ€” approve re-prepares + re-simulates, so a wallet drained during the wait reverts and dead-letters instead of firing stale (no recheck: expressions only see the journaled balance read, which cannot change while the run is parked)
  • approval gate via: [cli], on_timeout: fail
  • confirmations: 12 on the network, wait_for: confirmed
  • concurrency.on_conflict: skip โ€” one sweep in flight at a time
  • on_failure: dead_letter

Production checklist

  1. replace the cold_storage placeholder with the real address
  2. replace the raw dev mnemonic with a production signer
  3. add a second approval route (via: [telegram: ops, cli])
  4. dry-run it first: rflow test treasury-sweep-approval --cron-at <tick>