Small container that calls permissionless maintenance functions on Bread contracts when they come due.
| Job | Contract | Schedule |
|---|---|---|
distribute-yield |
Yield distributor on Gnosis, 0xeE95A62b749d8a2520E0128D9b3aCa241269024b |
Polled every 30 min |
The contract tracks its own cycle (cycleLength, 518400 blocks, about 30 days) and exposes
resolveYieldDistribution(). The job sends distributeYield() only when the resolver says the
cycle is ready.
Because of this, a missed or failed run is just retried on the next tick, and the contract rejects a second call in the same cycle. Prompt execution still matters: the next cycle is counted from the block of the actual call, so every delay pushes all later distributions back by the same amount.
Each run:
- picks the first reachable RPC from
RPC_URLS - alerts if the keeper balance is below
MIN_BALANCE_XDAI - alerts if the cycle ended more than ~6h ago but the resolver still says not ready
- sends with a gas limit of 130% of the estimate
- treats "another caller distributed first" as success
See .env.example.
| Variable | Required | Purpose |
|---|---|---|
KEEPER_PRIVATE_KEY |
yes | Dedicated wallet that pays gas. It needs no role on any contract, so it should only ever hold gas money (about 1 xDAI lasts years). |
RPC_URLS |
no | Comma-separated RPC endpoints, tried in order. |
DISCORD_WEBHOOK_URL |
no | Gets a message for each successful distribution and for alerts (at most one per alert every 6h). |
HEALTHCHECK_URL |
no | Pinged on every run, with /fail on errors. Use a healthchecks.io check with a 30 min period and about 1h grace, so you hear about it if the container dies. |
MIN_BALANCE_XDAI |
no | Threshold for the low-balance alert. Default 0.2. |
DRY_RUN |
no | 1 does everything except send the transaction. |
Deploy it as a Docker Compose resource built from this repository, with the variables above set as secrets in the platform. It needs no ports, volumes or domain.
Keep it out of any deployment that runs untrusted code or LLM agents, so the key never shares an environment with them.
Dry run against mainnet (read-only):
KEEPER_PRIVATE_KEY=0x... DRY_RUN=1 bash jobs/distribute-yield.shReal send against a local fork:
anvil --fork-url https://rpc.gnosischain.com --port 8547 &
cast rpc anvil_setBalance <keeper-address> 0xDE0B6B3A7640000 --rpc-url http://127.0.0.1:8547
KEEPER_PRIVATE_KEY=0x... RPC_URLS=http://127.0.0.1:8547 bash jobs/distribute-yield.sh- Add
jobs/<name>.sh. - Set
JOB=<name>and sourcelib/common.sh, which providespick_rpc,alert,notify,ping_healthandfail. - Add a line to
crontab.
Prefer polling the contract's own readiness check over counting time in cron.