LIP-118 · Arbitrum One · shared reward caller
Your orchestrator keys stay cold.
Your rewards get called. Every round.
Point your reward caller to
0x2F5901C6D8EB0181FA4f2b75EAAd0344a916fdDE
One setRewardCaller transaction from your orchestrator wallet — via the
go-livepeer CLI or any signer — then the key goes back to cold storage.
Full instructions ↓
livepeer.bot runs LivepeerRewardCaller — one immutable contract that makes the
daily reward() call for every Livepeer orchestrator who points
setRewardCaller at it. Subscribe once, put the key back in cold storage, done.
93 tests green, including a mainnet-fork suite run against the live LIP-118 deployment on Arbitrum One · two independent audits, all findings addressed · source & tests on GitHub
01 · The problem
The last hot key
Livepeer pays orchestrators through a reward() call that must land once per round —
roughly every 21 hours, forever. Before LIP-118 that call had to come from the orchestrator key
itself, so the key that controls your stake sat hot on a server around the clock for one routine
transaction a day.
LIP-118 fixes this:
setRewardCaller(addr) delegates exactly the reward call — nothing else — to an address
you choose. livepeer.bot is that address, shared by everyone: one contract, one keeper, every
subscriber's reward called each round, no coordination required.
02 · How it works
Three steps, one of them yours
Subscribe once
From your orchestrator key, one transaction on the BondingManager. Then the key goes back to cold storage — it is not needed again.
setRewardCaller(<contract>)Anyone sweeps, every round
A keeper bot (we run one), a cron job, or a stranger calls the contract. It initializes the round if needed, walks the active pool, and attempts reward for every subscriber not yet rewarded.
rewardAll(15, 0)Protocol mints, exactly as if you called
The BondingManager computes your reward, commission, and delegator shares itself — amounts are fixed at round initialization. Repeats every ~21 h.
RewardCallSucceeded ✓your cold key → setRewardCaller (once) → livepeer.bot contract → rewardForTranscoderWithHint (every round) → BondingManager mints your LPT
Repeated or concurrent calls are harmless: the protocol's own lastRewardRound makes every
sweep idempotent, already-rewarded orchestrators are skipped, and one failing orchestrator is isolated
in try/catch — it never blocks the rest.
03 · Trust model
Built to be boring
This is the section that should decide it. Everything below is verifiable in ~400 lines of Solidity.
Immutable, unowned
No owner. No admin. No pause switch. No upgrade hook. The code you audit today is the code that runs forever.
Zero storage, zero funds
The contract keeps no mutable state and never holds LPT or ETH. There is nothing to drain, freeze, or misconfigure.
Delegation grants one power
LIP-118 lets this contract call reward for you — nothing else. Your commission, your delegators' shares, and the amounts are computed by the protocol and fixed at round start. The caller cannot move a single wei.
You keep control
Your own reward() self-call keeps working — delegation adds a caller, it never locks you out. Opt out any time with setRewardCaller(address(0)).
Bounded worst case
The worst possible failure is a missed reward call — never loss of stake or funds. And your self-call remains as the backstop for exactly that case.
No forced upgrades
If a v2 is ever wanted, it will be a new address that you deliberately re-point to. There is no mechanism by which anyone can migrate you.
0xbe19…0Bd2, protocol commit
ccc82f43) · two independent automated audits, every finding fixed or answered on record
(reports & responses)
· read the
source & tests
· verified source on
Arbiscan
and Blockscout
04 · Join
One transaction from your orchestrator key
Call setRewardCaller on the Livepeer BondingManager
(0x35Bcf3c30594191d53231E4FF333E8A770453e40 on Arbitrum One), pointing it at this
contract. With Foundry's cast and a Ledger:
cast send 0x35Bcf3c30594191d53231E4FF333E8A770453e40 \
"setRewardCaller(address)" 0x2F5901C6D8EB0181FA4f2b75EAAd0344a916fdDE \
--rpc-url https://arb1.arbitrum.io/rpc --ledger
Not a cast user? Any signer works — open the BondingManager's
write-contract page on the explorer
(or use a Safe) and call setRewardCaller with the contract address. Then put your key
back in the freezer.
Change your mind later? Opt out the same way, any time:
cast send 0x35Bcf3c30594191d53231E4FF333E8A770453e40 \
"setRewardCaller(address)" 0x0000000000000000000000000000000000000000 \
--rpc-url https://arb1.arbitrum.io/rpc --ledger
05 · Keep it running
Anyone can trigger it. Anyone can fund it.
The sweep is permissionless and idempotent — there is no keeper monopoly and no way to trigger it "wrong". If our bot ever disappears, one command keeps every subscriber paid:
# once per round (~21 h), from any funded wallet
cast send 0x2F5901C6D8EB0181FA4f2b75EAAd0344a916fdDE "rewardAll(uint256,uint256)" 15 0 \
--gas-limit 25000000 --rpc-url https://arb1.arbitrum.io/rpc
Use the hardcoded 25M gas limit — plain eth_estimateGas does not account for the contract's
≥2.5M per-attempt safety floor. If the sweep is truncated (complete == false), call again;
repeat calls are harmless. The full keeper recipe — including the mid-round eviction rescue — lives in
the keeper docs.
Redundancy & funding
| Keeper script | repo /keeper — run your own copy anywhere a cron job runs |
|---|---|
| Decentralized backstop | under evaluation — Chainlink Automation was sunset industry-wide in July 2026 before launch; successors (Chainlink CRE, Reactive Network) are being assessed in the automation guide. Meanwhile the truly decentralized layer is the one no company can sunset: the permissionless command above, runnable by anyone. |
| Keeper gas wallet | 0xd6DEa4B2fb4Bb20019cab813fe06F992EC1Fd794 — ETH donations on Arbitrum One extend the bot's runway; it holds gas money only, never touches rewards. Please don't send more than gas dust — it's a hot operational wallet by design |
What it costs (full transparency)
| Scale | Txs per round | Approx. cost |
|---|---|---|
| Launch (~5 subscribers) | 1 tx, ~4–7M gas | ~$0.15–0.30 / day |
| Entire pool (100 orchestrators) | 3–7 txs | ~$1–4 / day |
At Arbitrum's typical ~0.02 gwei gas price. There is no fee and no profit motive — this is infrastructure run as a public good, cheap enough for one person to fund and simple enough for anyone to replace.