Skip to content

Sovryn Perimeter Delay: Zero - #11

Draft
tjcloa wants to merge 1 commit into
sovryn-perimeter-feefrom
sovryn-perimeter-delay
Draft

Sovryn Perimeter Delay: Zero#11
tjcloa wants to merge 1 commit into
sovryn-perimeter-feefrom
sovryn-perimeter-delay

Conversation

@tjcloa

@tjcloa tjcloa commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Phase 2 of the Sovryn security perimeter — the Zero half.

A voluntary borrower collateral exit that already pays the Perimeter Fee can additionally be held in the ExitDelayQueue for a governance-configured period, so a detected theft can be frozen or blacklisted and routed to recovery before the funds leave.

What this carries

  • Delay hooks on the voluntary collateral-out paths — withdrawColl, the collateral-decreasing adjustTrove, and closeTrove — sharing the surface the fee already uses. The fee leg is paid immediately and only the net is escrowed, and a single delay quote taken once per exit governs the whole exit, including the full-gross path taken when the fee leg fails.
  • ActivePool pushes the native RBTC to the queue and the record follows in the same transaction, so a record failure rolls the push back and the exit reverts as a whole rather than leaving value stranded.
  • Fail-open pointer, fail-closed quote. The queue's custom-error selectors propagate unchanged so the off-chain halt watcher can key on them.
  • BorrowerOperations gains the owner-gated setter for the queue pointer. The pointer lives in an unstructured slot, so neither hook adds state to any upgradeable proxy — asserted by the storage-layout zero-diff guard, whose baseline now covers the delay hooks as well.

Redemptions, liquidations and Stability Pool operations are untouched, as is the surplus claim, which remains exempt from the delay and keeps a pinning test to prove it. The delay ships disabled and is enabled only by governance after post-deployment verification.

Base branch

Opened against sovryn-perimeter-fee rather than development so the diff is the delay delta alone. Re-target to development once SIP-0094 is approved and executed.

Not ready to merge — known blocker

Contract size (EIP-170). BorrowerOperations reaches 25,242 bytes with the delay hooks, against a 24,576-byte limit, so it cannot be deployed as it stands. The deployed Phase-1 implementation is 23,917 bytes, leaving 659 bytes of headroom that the hooks exceed. The candidate fix is the TroveManagerRedeemOps pattern — split the delay legs into a companion contract reached by delegatecall.

Also planned for this branch

The surplus claim is currently exempt from the delay. That is being reversed: surplus withdrawals will route into the vault like every other delayed exit. It needs a new CollSurplusPool function, because the deployed claimCollWithFee sends the net straight to the claimant with no parameter to redirect it — so it carries a second pool implementation upgrade.

Verification so far

  • Compiles clean (132 files).
  • Storage-layout zero-diff guard green on BorrowerOperations, CollSurplusPool and ActivePool.

Phase 2 of the Sovryn security perimeter: a voluntary borrower collateral exit
that already pays the Perimeter Fee can additionally be held in the
ExitDelayQueue for a governance-configured delay, so a detected theft can be
frozen or blacklisted and routed to recovery before the funds leave. This
change carries the Zero half.

- delay hooks on the voluntary collateral-out paths (withdrawColl, the
  collateral-decreasing adjustTrove, and closeTrove), sharing the surface the
  fee already uses. The fee leg is paid immediately and only the NET is
  escrowed, and a single delay quote taken once per exit governs the whole
  exit — including the full-gross path taken when the fee leg fails, so a
  fee-vault fault cannot route around the delay;
- ActivePool pushes the native RBTC to the queue and the record follows in the
  same transaction, so a record failure rolls the push back and the exit
  reverts as a whole rather than leaving value stranded;
- fail-open POINTER, fail-closed QUOTE: an unset queue or controller pointer
  leaves exits paying direct, while a controller that answers incorrectly
  reverts the exit rather than silently disabling the perimeter. The queue's
  custom-error selectors propagate unchanged so the off-chain halt watcher can
  key on them;
- BorrowerOperations gains the owner-gated setter for the queue pointer; the
  pointer lives in an unstructured slot, so neither hook adds state to any
  upgradeable proxy (asserted by the storage-layout zero-diff guard, whose
  baseline now covers the delay hooks as well).

Redemptions, liquidations and Stability Pool operations stay untouched, as does
the surplus claim, which remains exempt from the delay and keeps a pinning test
to prove it. The delay ships disabled and is enabled only by governance after
post-deployment verification.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant