SIP-0096 (Parts 1–2): Perimeter Delay — 24-Hour Withdrawal Protection

Summary

This post introduces SIP-0096, voted as two technical proposals on the owner governor — the same governor-split discipline Bitocracy used for SIP-0094. Each part is its own ballot, created as a separate proposal, but both reference the same single SIP-0096 document in the SIPS repository (SIPS PR #93): both proposal descriptions bind the identical final document bytes and SHA256, so the two ballots decide on exactly the same text — with this post as the narrative reference.

  • Part 1 installs the Perimeter Delay across the lending protocol: nine actions, covering two lending-pool beacon modules, the close-with-deposit and close-with-swap modules, the current Maintenance/Views module pair, the fee/delay admin module, the borrower operations companion, and the queue pointer.
  • Part 2 installs the Zero side: five actions — the CollSurplusPool upgrade first, then BorrowerOperations implementation, its operations companion, its queue wiring, and last the TroveManager implementation (a Recovery-Mode accounting correction, included in this release vehicle).

Nothing is delayed when these proposals execute. The system ships installed and switched off, and stays off until a separate, separately authorized enable step after post-installation verification. The launch configuration, stated here so the vote is cast with full knowledge: a uniform 24-hour hold (86,400 seconds) on voluntary, user-initiated withdrawal payouts, shown in the interface before the user confirms and visible in the account menu while it counts down. Both parts are planned for creation on Wednesday, 21 October 2026, in the same cycle.

Liquidations, rollovers and other forced or protocol-initiated flows are never delayed. The SIP-0094 Perimeter Fee remains live, separate, and unchanged: fee and delay are independent controls — either can exist without the other.

Background

SIP-0094 (executed September 2026) installed phase 1 of the Sovryn security perimeter: the fee rail, live and collecting since 2026-09-07 at 0.10% on user-initiated withdrawal surfaces. That post said phase 2 would ship the protection itself — the ability to act in the window between a suspicious withdrawal beginning and value leaving the perimeter. SIP-0096 is that phase.

The premise is unchanged: value is lost at exits. An exploit converts a bug into a withdrawal in minutes, and a protocol that can do nothing in those minutes absorbs the full loss. A mandatory settlement window on voluntary exits is what turns “nothing can be done” into a bounded, reviewable interval — while leaving every ordinary user a guaranteed, automatic path to their own funds after the window closes.

How the Perimeter Delay works

The delay is a hold placed on the user payout leg of a covered withdrawal — not on the position, and not on the protocol’s accounting.

  1. Withdraw as today. The user initiates a withdrawal on a covered surface (lender redemption, borrower collateral withdrawal or loan close, Zero collateral withdrawal or trove close, Zero surplus claim). The product authenticates and settles exactly as it does today: shares are burned, collateral is released from the position, the SIP-0094 fee is taken first where it applies.
  2. The payout is recorded, not paid. Instead of leaving immediately, the net user amount moves into the ExitDelayQueue — a dedicated custody contract — as an individually identified request: asset, amount, originator, position owner, receiver, surface, creation time and unlock time. All of it is immutable from that moment. No guardian, no policy change, no later executor can retarget the payout; it can only ever go to its recorded receiver.
  3. Wait 24 hours. The unlock time is the recording block timestamp plus 86,400 seconds — read from chain, not rounded.
  4. Withdraw as a regular flow. Once mature, the request is released by a plain transaction — submitted by the user from the dapp’s Perimeter queue view (account menu), which lists every pending request with amount, asset, destination and release time. Delivery always pays the recorded receiver. There is no re-approval, no discretion, and no expiry: a mature request waits for its transaction.
  5. The intervention window. During the hold, guardians (the queue Admin/Owner roles, held by the Exchequer Multisig) have exactly two levers, both address-level and public on-chain:
    • Freeze — a precautionary hold on an address while something is investigated. Frozen addresses’ payouts stop until unfrozen.
    • Blacklist — the confirmed-incident state. Blacklisting qualifies the frozen value for administrative resolution: return to the affected pool’s remaining participants along a pre-approved route, or resolution to a named destination by the queue Owner. Resolution never requires touching any other user’s request.

Turning the delay off stops new holds; it never shortens, cancels or retargets requests already queued — every request matures and pays out under its original terms. Pausing the queue stops ordinary releases while incident resolution stays available.

Motivation

Phase 1 made exits visible and funded the perimeter’s operation. It could not, by itself, stop anything. The delay is the mechanism that creates time: time to notice, time to freeze, time to blacklist and recover — at a cost borne only in patience, only on voluntary exits, with a floor of 24 hours configured at deployment and an immutable recipient on every request. Automated protocol flows — liquidations, rollovers, Stability Pool operations, redemptions — remain direct, uncharged and undelayed; they are not covered surfaces in the deployed code.

Proposed changes

SIP-0096 Part 1 — Lending installation (9 actions)

Nine governance actions on the owner governor, executed atomically — there is no partial-installation state: registration of the two lending-pool beacon modules (lender exits), the close-with-deposit and close-with-swap modules (borrower exits), the current LoanMaintenance and LoanMaintenanceViews pair (five state-changing and eight read-only routes), the ExitFeeModule admin module (fee/delay setters and the queue pointer), the borrower operations companion, and the queue pointer itself.

SIP-0096 Part 2 — Zero installation (5 actions)

Five actions on the owner governor, in a fixed order: the CollSurplusPool proxy upgrade first (the delay-capable surplus path the BorrowerOperations setters depend on — a setter on the wrong pool would silently no-op), then the BorrowerOperations implementation, its operations companion, its queue wiring, and last the TroveManager implementation. The TroveManager action is not perimeter code: it carries Liquity’s correction to Recovery-Mode batch liquidations (both loops now subtract gas compensation and collateral surplus from the running collateral total), is address-compatible, adds no state, and ships in this vehicle to save a governance cycle.

Companion actions (disclosed for completeness)

  • Controller upgrade: the existing ExitFeeController proxy (the SIP-0094 controller) is upgraded by the Exchequer Multisig — not by these proposals — to the delay-quoting implementation. This happens before both proposals, and its verification gates them.
  • Collector exemption pair: the Exchequer installs the FeeSharingCollector’s fee-zero/delay-bypass exemption on the lender-withdraw surface before Part 1, so the Collector’s own redemption accounting is never silently altered. The fee half is already live (Exchequer tx 2214, September).
  • Collector implementation upgrade: after Part 1 installs the new two-return iWRBTC interface, the Exchequer upgrades the already-initialized Collector proxy (no re-initialization).
  • The enable step: after full installation verification — every host’s pointer, every pool, every backing and accounting check, with the delay still off — the Exchequer sets the global delay to 86,400 and, as the final separately authorized act, enables the security perimeter.

What changes — and what does not

For full transparency, the release’s contract set, classified by behavior change relative to what is live today:

Carrying the new delay behavior: the ExitFeeController implementation (delay quoting and switches), both lending beacon modules (lender-exit holds), LoanClosingsWith and LoanClosingsWithSwap (borrower-exit holds), LoanMaintenance (collateral-withdrawal hold), ExitFeeModule (adds the queue-pointer admin), BorrowerExitPerimeterOps (request/claim companion), FeeSharingCollector (two-return redemption accounting), and the Zero BorrowerOperations, CollSurplusPool and BorrowerOperationsPerimeterOps implementations.

No functional change: LoanMaintenanceViews — the eight read-only query routes are split out of the combined Maintenance module purely to fit the contract size limit; the queries themselves are unchanged. It ships so the deployed bytecode matches the reviewed canonical build, not to alter any behavior.

Not touched at all: the original Liquidation and Rollover modules (forced exits stay direct, uncharged and undelayed — structurally, since the liquidation module lies outside the covered code entirely), the original swap library, the non-LM loan-token logic variants (their only difference is a view their selector list does not register, so they are not re-registered), the ExitFeeVault, and every existing proxy — all upgrades in this release are implementation swaps behind existing proxies.

TroveManager (separate): the Recovery-Mode correction described above — a functional fix, but not perimeter behavior.

Deployed contracts

Implementations are staged on mainnet switched off before this post publishes, so the tables below carry final addresses, and each proposal’s on-chain actions can be checked against these tables action by action.

Source verification. Every contract in these tables is source-verified. On Rootstock Blockscout: the controller implementation, all nine lending deployments, the Zero CollSurplusPool and BorrowerOperationsPerimeterOps, and both ExitDelayQueue contracts (implementation and proxy). The two remaining Zero implementations, BorrowerOperations and TroveManager, could not be verified on Blockscout: both carry a constructor-set Permit2 immutable in their deployed bytecode, and Blockscout’s verifier currently fails to match immutable-bearing standard-json submissions. This is a verifier-side limitation, not a code mismatch — their on-chain bytecode is identical to the reviewed deployment records outside the immutable spans. Both are exact-match verified on Sourcify (full creation and runtime bytecode match: match ID 56004603 for BorrowerOperations, 56004786 for TroveManager — viewable without any account) and publicly verified on Tenderly (viewable with any Tenderly account: BorrowerOperations, TroveManager).

Core perimeter contracts (repo Sovryn-perimeter):

Contract Address
ExitFeeController proxy (delay controller, existing) 0x99994b4522483de17f31a5bc010c5901add3440e
ExitFeeController implementation (new) 0xe85e7e5c81a4dcafa6976cd57988b81dbfcb18e1
ExitDelayQueue proxy 0x6A281FCB0838F7a75f93d678000cb0E57ed8Dc45

Lending implementations (repo Sovryn-smart-contracts):

Contract Address
LoanTokenLogicLM 0xeD1761D4Ef713f274555Fb7C956Ca088Bf4Ae236
LoanTokenLogicWrbtcLM 0x4315C5b88F3B5be824B1aac8CD2B12b7C1C01316
BorrowerExitPerimeterOps 0x61f1955F54f8DE6858A752f3445309889c03c441
LoanClosingsWith 0xd0661123b5F3E3d43E61c06385657ca503d71b8d
LoanClosingsWithSwap 0x1d38628B6746b6b8097A380D8a17aa7111855cf3
ExitFeeModule 0xb6474794e1ed9e0CF3EA8511aEcfA8e9462Ef1F4
LoanMaintenance 0x4abAbF0a00C3F809CC0D6C1A2E13f8A9dfa8bf43
LoanMaintenanceViews 0x1c07317fFF655b1ff0083C0460c45A8b556bc14e
FeeSharingCollector proxy (existing) 0x115cAF168c51eD15ec535727F64684D33B7b08D1
FeeSharingCollector implementation (new) 0xcCB75e444f4808012A57Eb2Db06648249f370D2f

Zero implementations (repo zero-contracts):

Contract Address
BorrowerOperations proxy (existing) 0x5B9dB4B8bdeF3e57323187a9AC2639C5DEe5FD39
BorrowerOperations implementation (new) 0x8d69F344c051a73671Aef27D7695dF52C0bD7f7e
CollSurplusPool proxy (existing) 0x310ec7Fe6e4943DA773De8948255E37CC45e34bb
CollSurplusPool implementation (new) 0xDf0391a2bE429091D878a09753fCD3eB04C32149
TroveManager implementation (new) 0x57219Dd6c9e869750c23e4043C62562dc6Fd1EC4
BorrowerOperationsPerimeterOps 0x3dCecd9c0524bBA3990DCB403601Ee5Ea1136bf8

Note: The SIP-0096 document additionally lists, for every replaced module, the currently-live implementation it replaces (the rollback anchor) and the runtime code hash of each new artifact.
Note: The SIP-0096 document carries the final address table; the pull requests linked from it carry the complete reviewed diffs, and every address in the table can be checked against the proposals’ on-chain actions.

Technical details

Covered surfaces. Lending lender withdrawal (including the liquidity-mining-aware and BTC-native burn variants); lending borrower withdrawal (collateral withdrawal, close by deposit or swap, including governed surplus legs); Zero collateral withdrawal (including DLLR/NUE/Permit2 wrappers); Zero surplus claim. A catalogued AMM remove-liquidity policy exists but ships with no hook in this release.

Atomicity. If queue funding or recording fails, the entire originating withdrawal reverts — product accounting and fee effects included. The system never silently pays direct to bypass a resolved hold; a successful hold commits the position change and the user receives the later queue payout, never both.

Fee independence. The SIP-0094 fee resolves first and independently; a failed or non-charging fee leg never changes the delay evaluation, and the delay never changes the fee.

Self-recovery. A stuck payout (a receiver contract that cannot accept funds) is recoverable by the recorded parties through a contract function that tries the original receiver first and, on caught failure, pays an alternative — bounded by the same unblock conditions as ordinary delivery. Neither production UI exposes this; operator-handled cases follow a written-instruction procedure.

Custody and guards. The queue holds escrow per asset with backing verification on every payout, a queue-local reentrancy guard, and host allowlisting — only registered product contracts can create requests. Fee proceeds stay in the separate fee vault; guardians cannot sweep user escrow.

Code and review. The release carries completed canonical builds; a full fork rehearsal of both proposals through real governance (create, vote, queue, execute) with charged/uncharged and held/released paths asserted on every surface, plus complete rollback rehearsal restoring every replaced target; a scoped internal security review across core, lending and Zero with zero confirmed in-scope findings at seal; and bounded adversarial/property suites (core 622 tests green; multi-thousand-case property and invariant campaigns). A consolidated pre-SIP check-up on 2026-10-13 re-ran the full campaign set against the exact deployed-bytecode source commits and added independent second-opinion reviews; it found one Medium availability issue — native-RBTC loan closes would have failed under an active delay — which was fixed, proven by executed regression tests, and the affected companion redeployed (the tables carry the fixed address). The review treats the protocol Owner/Admin and their managed contracts as trusted guardians and ordinary users as untrusted.

Risks

Risks introduced:

  • A 24-hour wait where exits were instant: voluntary withdrawals on covered surfaces settle a day later. Users with urgent liquidity needs bear that cost on every covered exit.
  • New custody code: the queue is a new contract holding user payouts in transit.
  • Guardian powers: freeze, blacklist and resolution authority over queued payouts, held by the Exchequer Multisig. These powers cannot retarget a request to an arbitrary address — resolution follows pre-approved routes or the queue Owner acting on blacklisted parties — but they can delay a legitimate user’s funds longer than 24 hours.

Risk mitigants:

  • Immutable requests: amount, receiver and unlock time are fixed at recording; no role can redirect a payout.
  • Off until verified: installation executes with the delay globally disabled; enabling is a separate, separately authorized act after full state verification.
  • Narrow covered set: forced and protocol-initiated flows are never delayed; ordinary users always have the regular release path after 24 hours.
  • Rollback anchors: every replaced target has a captured original; rollback restores prior modules (the original combined Maintenance restores all thirteen selectors in one action) and disabling the delay is a single switch that stops new holds while existing requests stay deliverable under their original terms.
  • Accepted residual risks, stated: self-service recovery is uncapped by design; contract-owned borrower positions rely on operator-assisted delivery; the keeper Collector exemption is configuration, visible on-chain; the frontend follows a fail-hidden policy (no queue, no fee shown) rather than showing unknown states.

Implementation

Item Value
Parts 1–2 Two proposals on the owner governor; Part 1 (9 actions) executes before Part 2 (5 actions); wrong order reverts harmlessly
Owner and Admin at launch Exchequer Multisig 0x924f5ad34698Fd20c90Fe5D5A8A0abd3b42dc711
Delay floor and launch value 86,400 seconds (24 hours)
Queue custody ExitDelayQueue 0x6A281FCB0838F7a75f93d678000cb0E57ed8Dc45
Contract addresses and calldata Frozen into the SIP documents at proposal creation; both descriptions bind the same final SIP-0096 bytes and SHA256
Proposal creation target Wednesday, 21 October 2026 — both parts created in the same cycle
Vote target The window immediately following creation
Execution target The days following the vote, after post-installation verification

Rationale

Two ballots because the governor’s action caps and the natural system boundary (lending, then Zero) make it the clean split — the same discipline as SIP-0094. One window because the parts form one programme: the perimeter’s protection layer. The TroveManager correction rides this vehicle, disclosed here rather than hidden in a larger proposal, because it saves a governance cycle for a fix Liquity itself shipped.