Safety and the registry
A module only decides where fees go. The dispatcher calls it read-only with a gas cap, the registry screens its bytecode before any vote, and activation waits for a vote and a timelock.
Read-only calls
The module runs inside a STATICCALL: any attempt to write storage, emit, transfer or create reverts, and the dispatcher falls back to the default split. The five sinks are fixed in the dispatcher. A module never names an address, never changes swap amounts and never raises the fee, which stays at 1%.
The bytecode screen
Before a proposal opens, the registry walks the module's runtime code opcode by opcode and rejects any of these:
| Opcode | Why |
|---|---|
SSTORE, TSTORE | writes state |
CALL, CALLCODE, DELEGATECALL | can move value or run other code in its place |
CREATE, CREATE2 | deploys code |
SELFDESTRUCT | removes code |
LOG0 to LOG4 | emits events |
STATICCALL stays allowed, so modules can read feeds and pools.
Hashes
The proposal carries the module's code hash and the hash of its fork report. The registry checks the code hash against the deployed contract (extcodehash), so what stakers vote on is exactly what runs. The module page shows the source hash, the report hash and the onchain code hash side by side.
The guardian
The machine wallet is the guardian. It can pause the live module, which sends fees back to the default split, and unpause it. It cannot add a module: only a passing vote followed by the timelock can.
