Guardian Routines
The procedure side of the guardian key: the reads to do before and after a call, and when to hand over to the owner. The levers themselves, their arguments and their authority are Guardian.
1. Before you act
- Chain. Confirm the wallet’s chain before signing. Pool salts carry no
block.chainid, so one salt lands at the same address on every chain of the fleet: the right call on the wrong chain reaches a real pool, not a dead address. - Role.
AccessControl.perms(you)carries bit 17 (guardian) on theACthe target reads:Admin.AC(),PoolFactory.AC(); the mark store answers to the same root.AccessControl.quorumPolicyArmed()reports whether the policy is armed; whether the live multisig configuration still satisfies it is not an on-chain view, readgetOwners()/getThreshold()on the Safe directly againstQuorumLib. - That something is actually pending, before any cancel.
AccessControl.pendingRole(role)andUpgradeGate.pendingUpgradehave public getters.Admin.pendingOpsand the mark store’s queued ops are internal: the ETA comes from theTimelockRequestedor storeOpQueuedevent, or the indexer. A cancel with nothing pending revertsNoPendingonAdminand costs only gas. - The live implementation, before a store call. Store levers run on
PoolFactory.implementation(); a call to a retired or pending implementation reverts. - The legs, before a halt. Discovery is
PoolFactory.getOfficialPoolsForToken(token)→getPoolTokens(pool)(Access control).batchRiskOptakes the two arrays positionally; a length mismatch revertsInvalidInput. - The lane, before a store halt.
PoolFactory.laneOf(feedId)minus one is the lane; pick the tiers withtierMask(1 primary, 2 reference, 3 both).
2. After you act
Read state, not the transaction. Halt and pause events are snapshot triggers rather than indexed topics, so the indexer will not answer “what is halted right now” (Observability).
| You called | Verify | Event |
|---|---|---|
haltAsset / batchRiskOp | Pool.getAsset(token).flags carries your bit | AssetHalted / RiskOpsBatched, BatchLegSkipped |
haltAsset(pool, token, 0x0800) (coop kill) | getAsset(token).flags bit 11 (COOP_ENABLED) clear; the leg still swaps | AssetHalted with src 0x0800 |
collapseAnchor | getAsset(token).anchor is the new anchor and HALT_ANCHOR_BIT (0x0004) is set | AnchorUpdated |
Store halt(lane, tierMask) | PoolFactory.feedOf(feedId, t) flags bit 0 set on each tier you halted; the mark reads 0, which is the lever working, not a failed write | LaneHalted |
cancelOp / store cancel / cancel* | The pending read from §1 is now zero | TimelockCancelled, OpCancelled, UpgradeCancelled, RoleCancelled |
pause() | paused() true on that singleton | Paused(true) |
Then check for side effects. A halt on the reference tier alone stops every spoke leg that bands
against that lane. After a halt, the fraction of the book still tradable is
feeds.tradable_ratio and bot_tradable_ratio (Observability).
3. Escalate
The guardian key cannot reverse its own actions. Hand over to the owner as soon as the lever has landed:
- What you halted or paused, with the
srcbits, lanes and tier masks, so the release clears exactly those. - Why, with the read that triggered it.
- What is now blocked that the incident did not require blocking.
Intake and contact are Access control
and security@btr.markets. A suspected vulnerability rather than an operational fault goes through
Audits.
Escalate rather than act when the remedy is a widen, an un-halt, a grant, a param write or a value movement. None of those are reachable from this key.
A coop kill carries no release clock and, on a seated pool, can be re-armed by the seat after TUNING; if the kill must hold there, use HALT_BIT and say so in the hand-over (Guardian §3).
Example: a lane wedged outside its band (dark past ). The remedy is the owner’s
reanchor(lane, tierMask) at TUNING: it drops the dark lane’s anchor so the next push lands
unbanded, which then has to be checked against the source. It acts per lane; hand over every wedged
lane, not a sample. A lane’s bounds themselves (ttl, maxDev, σ floor) change only with a new class
table at a fleet upgrade.
halt is the instant lever for any lane, and it is a guardian lever
(Mark Relayer). The other remedies are not reachable from this key.
Releasing a lane halt is the owner’s action, not yours. unhalt is owner-only on the store;
the lane returns dark, the first push after release is banded against the mark the halt kept over
the whole gap since it was observed, and the lane reads markless until that push lands. Hand the
halt over with the lanes and tier masks. The transaction is not the end of the incident.