From 39a666735588d66008d6e1f422ef472f37088069 Mon Sep 17 00:00:00 2001 From: Tyrone Johnson Date: Wed, 12 Aug 2026 10:03:57 +0300 Subject: [PATCH 01/11] init SIP-0094 Perimeter Fee Activation and Adoption Fund Transfer --- SIP-0094.md | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 SIP-0094.md diff --git a/SIP-0094.md b/SIP-0094.md new file mode 100644 index 0000000..7604744 --- /dev/null +++ b/SIP-0094.md @@ -0,0 +1,168 @@ + +# SIP-0094 (Parts 1–3): Perimeter Fee Activation and Adoption Fund Transfer + +## Summary + +This post introduces SIP-0094, voted as three technical proposals: the governor caps any single proposal at ten actions (`proposalMaxOperations`), a split Bitocracy has used before (SIP-0046, Parts 1–4; SIP-0084, Parts 1–2). Parts 1 and 2 run on the owner governor; Part 3 runs on the admin governor, which owns the contract it touches. Each part is its own ballot with its own technical SIP document in the SIPS repository, all referencing this post – the single narrative reference for the programme. All three are created in the same cycle and voted in the same window; they form one programme. + +**Part 1** installs the Perimeter Fee – the fee component of the Sovryn security perimeter – across the lending protocol and Zero: ten actions, all of them code installation. +**Part 2** carries three actions: the final wiring action and, alongside it in two transfer legs, the Adoption Fund's fully-vested balance of 5,021,309.20 SOV moving to the Exchequer, continuing the arrangement Bitocracy created in SIP-0015 and has exercised since in SIP-0065 (2023), SIP-0076 (2024), and SIP-0079 (2024). +**Part 3**, a one-action proposal on the admin governor, retires the SOV emission subsidy to the Zero Stability Pool. + +**Nothing charges when these proposals execute.** The system ships installed and switched off, and stays off until a separate enable step after post-deployment verification. The launch configuration, stated here so the vote is cast with full knowledge: a uniform 0.10% (10 basis points) – $1 per $1,000 – on user-initiated withdrawal transactions, shown in the interface before the user confirms. + +Automated protocol flows – redemptions, liquidations, Stability Pool operations, rollovers – never pay the fee. They are not fee surfaces in the deployed code. + +## Background + +Sovryn holds user funds across lending pools, loan collateral, and Zero troves. In today's DeFi threat environment, value is lost at exits: an exploit converts a bug into a withdrawal in minutes. The security perimeter answers this in phases, and phase 1 is the fee rail – the piece that must exist first, launched at a deliberately minimal 0.1% rate. +On the treasury side, this is housekeeping. SIP-0015 (2021) created the Exchequer Committee and entrusted it with the SOV held in the Adoption and Development Funds as that SOV vests. Bitocracy has exercised that arrangement three times since – SIP-0065 (3,000,000 SOV, executed June 2023, tx `0xb1f0ccf6…77dfff32`), SIP-0076 (February 2024, both funds), and SIP-0079 (2024, Adoption Fund, toward the BOB campaign) – and the funds' vesting schedules have since run to completion. What remains today is the final vested residue: 5,021,309.20 SOV in the Adoption Fund and 2,486,471.60 SOV in the Development Fund (balances verified on-chain, 5 August 2026, RSK block ~9,124,829). After these transfers the funds are empty and the arrangement begun with SIP-0015 in 2021 is complete. + +## How the security perimeter works + +The perimeter is a trust boundary drawn around the protocol’s holdings. Inside it, nothing changes: positions, operations, and protocol flows compose exactly as they do today, with no new friction. The boundary acts only at the point where value leaves the protocol, because exits are where DeFi losses actually happen – an exploit only profits in the minutes it takes to turn a bug into a withdrawal. + +The perimeter ships in phases, in deliberate order. Phase 1 – this programme – installs the funding rail: fee machinery on every user-initiated exit surface, deployed switched off and enabled at a minimal rate only after post-deployment verification. Phase 2 – targeted for the weeks after execution – ships the protection itself: continuous monitoring of every exit, and the ability to intervene in the window between a suspicious withdrawal beginning and value leaving the perimeter. The rate schedule publishes together with phase 2, so rates move only as protection ships and the fee tracks the protection actually delivered. + +Rail-first is the safe order. The rail is the piece every later phase depends on, and it is the piece that changes user experience least – a visible $1-per-$1,000 fee, not a new constraint on movement. Until the perimeter is complete, every exit remains exactly as exposed as it is today; that exposure, not the fee, is what this programme exists to end. + +## Motivation + +Most money markets charge nothing on withdrawal. Those same markets can also do nothing for a user in the minutes after an exploit begins. The Perimeter Fee is the funding rail for continuous monitoring of every exit – a real, ongoing service, charged where it is delivered, at a launch rate sized to be barely perceptible: $1 per $1,000, on user-initiated withdrawal transactions, visible in the interface before every confirmation. The goal is a protocol that pays for its own defence out of its own usage rather than out of treasury drawdown. + + + +## Proposed Changes + +### SIP-0094 Part 1 – Perimeter Fee installation (ten actions) + +Ten governance actions that install the Perimeter Fee code: new lending-pool logic modules, three refreshed protocol modules, the fee module that owns the governance setters, the borrower-exit hook, and upgrades to two Zero contracts with their controller wiring. All ten execute as one atomic transaction – there is no partial-installation state. The action-by-action breakdown, with exact call data, target-by-target ownership verification, and rollback anchors for every replaced address, is in the Part 1 SIP document in the SIPS repository. + +### SIP-0094 Part 2 – final wiring and Adoption Fund transfer (three actions) + +1. The final Perimeter Fee wiring action (the deployment comprises eleven actions; the governor's ten-action cap places this one here — in the executable ordering it is the proposal's last action, asserted at creation). Executing Part 2 before Part 1 simply reverts and waits – an ordering mistake cannot create a broken state, which the fork rehearsal proves by executing the parts out of order and asserting the revert. +2. Withdrawal of the Adoption Fund's fully-vested 5,021,309.20 SOV (`0x0f31cfd6aAb4d378668Ad74DeFa89d3f4DB26633`) to the Exchequer Multisig (`0x924f5ad34698Fd20c90Fe5D5A8A0abd3b42dc711`), under the SIP-0015 arrangement, in the shape SIP-0065 and SIP-0076 used. The withdrawal's leg-by-leg decomposition is frozen into the proposal at creation, together with the balance re-read from chain. + +### SIP-0094 Part 3 – Stability Pool subsidy retirement + +A one-action proposal on the admin governor – the governor that owns the relevant contract – sets the SOV emission rate for Zero Stability Pool deposits to zero (`CommunityIssuance.setAPR(0)`), conserving the SOV currently spent to subsidise those deposits. Nothing is removed and no contract changes: it is a parameter set to zero, and a future governance vote could set it back. + +### Companion actions, disclosed for completeness + + + +- **Development Fund residue.** The Development Fund's 2,486,471.60 vested SOV transfers to the Exchequer by a direct multisig transaction in the same window, under the locked-token-owner authority the Exchequer holds on that contract, through the fund's deployed, verified sweep function – which empties the fund and retires it. No governance action is required for it; it is listed here so this post describes the whole programme in one place. +- **The enable step.** After Parts 1 and 2 execute, charging begins only when post-deployment verification is green, monitoring is live, and the pause switch has been rehearsed in a live drill – at which point the Exchequer sends the enable transaction. + +## Technical Details + +| Surface | Fee at launch | +| ------------------------------------------- | ------------- | +| Lending-pool withdrawal (iToken redemption) | 0.10% | +| Borrower collateral withdrawal / loan close | 0.10% | +| Zero trove collateral withdrawal / closure | 0.10% | +| Zero collateral-surplus claim | 0.10% | + +One rate everywhere: no exemptions and no per-pool differences. Every user faces the same 10 bps on the same surface. That includes the collateral-surplus claim – the outlet for exits whose moment the user did not choose, such as a full redemption against a trove, which is kept as its own surface precisely so governance can price it separately, including at zero, at any time by configuration. Automated protocol flows : redemptions, liquidations, Stability Pool operations, or rollovers, are not fee surfaces in the deployed code; for liquidations, the separation is structural, since the liquidation module lies outside the charging code entirely and is not even redeployed by this release. A fifth surface, AMM liquidity-pool withdrawal, is defined in the deployed code but ships shut, with nothing consuming it in this release; a shut gate short-circuits everything beneath it, and activating it later would be an owner configuration call, visible on-chain the moment it is made. + +- **Built to fail open.** On any fault in the fee machinery: controller unreachable, invalid quote, vault transfer failure – the product forgoes the fee and pays the user the full amount, and the user's own payout leg keeps the protocol's existing behaviour, so Perimeter Fee introduces no new way for a withdrawal to fail. The failure direction of every Perimeter Fee fault is "fee forgone," never "withdrawal reverted." This is asserted across a full failure matrix in the test suites and reconfirmed under each lens of the multi-lens internal review. +- **Everything is visible.** Every affected withdrawal shows the fee amount and an explanation before the user confirms. There are no silent deductions, and every configuration change emits a public on-chain event the moment it is made. +- **Rates are configuration, applied only forward.** Rates live on the deployed controller as basis-points settings – changeable only by the contract owner, never retroactively: a fee is resolved at the moment a transaction executes, so no change can reach a withdrawal that has already happened. The launch setting is 10 bps everywhere; the stated intent – an intent, not a code constraint – is that rates move only with the rate schedule to be published with phase 2; and the instrument for any incident is the pause switch, which halts all charging in minutes and is rehearsed as a live mainnet drill before launch. +- **Exchequer Ownership** The Exchequer Multisig – the operational committee Bitocracy created in SIP-0015 – holds both roles on the fee contracts at launch. The roles are deliberately split so that the fast operational keys are narrow: the admin role reaches only the pause switch, the fee destination, and fees already collected; it cannot touch user principal. Rates, exemptions, upgrades, and role assignment sit behind the owner role. User deposits sit in the product pools, which neither role can transfer; the one lever that can touch a future withdrawal is the rate setting itself – owner-only, forward-only, and public the instant it changes. +- **Proceeds.** Collected fees accrue in the fee vault under Exchequer control; the transferred SOV joins the treasury the Exchequer already stewards under SIP-0015. +- **Code and review.** Roughly 3,000 lines of production code carrying roughly 13,000 lines of tests, by the engineering team's count; a multi-lens internal security review (AI-assisted and manual, including a cross-model pass) with no surviving critical or important findings; five fund-safety invariants reconfirmed under each of the review lenses; and a full fork rehearsal through real governance: create, vote, queue, and execute, with charged and uncharged paths asserted on every surface. + +### Reviewing the code + +All source is public and open for review now, while deployment is being prepared. Two of the +three code bases are proposed as pull requests that stay **open** until this programme is +approved and executed — mainline follows the chain rather than leading it — so the pull request +is where the proposed change can be read as a diff against what is live today: + +| What | Where to review | +| -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Perimeter Fee core — the shared exit-fee controller and vault | [`Sovryn-perimeter`](https://github.com/DistributedCollective/Sovryn-perimeter) (standalone repository; nothing to merge) | +| Lending and borrowing hooks, plus the proposal tooling for all three parts | PR [Sovryn-smart-contracts#580](https://github.com/DistributedCollective/Sovryn-smart-contracts/pull/580) (branch `sovryn-perimeter-fee` → `development`) | +| Zero trove-exit hooks and the collateral-surplus claim | PR [zero-contracts#10](https://github.com/DistributedCollective/zero-contracts/pull/10) (branch `sovryn-perimeter-fee` → `development`) | + +The implementations this programme installs are deployed from exactly those branch commits, and +each is source-verified on the Rootstock Blockscout explorer — so the code read in the pull +request, the bytecode on chain, and the addresses in the proposals below are the same artefact, +checkable independently by anyone. + +### Deployed contracts + +The Perimeter Fee contracts deploy — switched off, Exchequer-owned — **before** this post +publishes, so the table below carries final addresses at publication. Every address is +source-verified on the Rootstock Blockscout explorer before publication, and each proposal's +on-chain actions can be checked against this table action by action. + +**Core Perimeter Fee contracts** (repo [`Sovryn-perimeter`](https://github.com/DistributedCollective/Sovryn-perimeter), commit ``): + +| Contract | Address | +| -------------------------------- | ------------------------------------------------ | +| ExitFeeController proxy | `` | +| ExitFeeController implementation | `` | +| ExitFeeVault proxy | `` | +| ExitFeeVault implementation | `` | + +**Lending / borrowing implementations installed by Part 1** (repo [`Sovryn-smart-contracts`](https://github.com/DistributedCollective/Sovryn-smart-contracts), branch `sovryn-perimeter-fee`, commit ``, review in PR [#580](https://github.com/DistributedCollective/Sovryn-smart-contracts/pull/580)): + +| Contract | Address | +| --------------------- | ------------------------------------------------ | +| LoanTokenLogicLM | `` | +| LoanTokenLogicWrbtcLM | `` | +| LoanClosingsRollover | `` | +| LoanClosingsWith | `` | +| LoanMaintenance | `` | +| ExitFeeModule | `` | +| ColFeeBorrowerExitOps | `` | + +**Zero implementations installed by Part 1** (repo [`zero-contracts`](https://github.com/DistributedCollective/zero-contracts), branch `sovryn-perimeter-fee`, commit ``, review in PR [#10](https://github.com/DistributedCollective/zero-contracts/pull/10)): + +| Contract | Address | +| ---------------------------------------------- | ------------------------------------------------ | +| BorrowerOperations implementation (fee-hooked) | `` | +| CollSurplusPool implementation | `` | + +The per-part technical SIP documents additionally list, for every replaced module, the +currently-live implementation it replaces (the rollback anchor) and the runtime code hash of +each new artifact. + +## Risks + +Risks introduced: + +- **A fee where the market's default is zero.** Users pay 10 basis points on withdrawals that were previously free. +- **The rail precedes the rest of the perimeter.** Phase 1 charges its minimal rate before phase 2 ships. +- **New code in live paths.** The fee vault and controller are new contracts; the release also replaces three live loan-closing and maintenance modules, upgrades two Zero contracts, one for the first time, and the borrower-exit hook carries the same protocol-level authority the existing core modules already hold. +. + +Risk mitigants: + +- **Minimal, visible, forward-only.** $1 per $1,000, shown before every confirmation; no change ever reaches an executed transaction; every change is public instantly. +- **Fail-open everywhere.** No Perimeter Fee fault path shrinks a user's withdrawal, the system gives up its fee instead, asserted across the failure matrix and reconfirmed under every lens of the internal review. +- **Off until verified.** Both parts execute with charging globally disabled; the enable step waits for verification, live monitoring, and a rehearsed pause drill. +- **Rail-first sequencing.** Deploying the rail at a minimal rate is what makes phase 2 deployable at all; every exit today is exactly as exposed as it was yesterday until the perimeter ships, which is the problem this programme exists to end. + + +## Implementation + +| Item | Value | +| -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Parts 1–3 | Three proposals (Parts 1–2 on the owner governor, Part 3 on the admin governor), created in the same cycle, voted in the same window; Part 1 executes first (wrong order reverts harmlessly) | +| Owner and admin at launch | Exchequer Multisig `0x924f5ad34698Fd20c90Fe5D5A8A0abd3b42dc711` | +| Adoption Fund (Part 2 action) | `0x0f31cfd6aAb4d378668Ad74DeFa89d3f4DB26633` – 5,021,309.20 SOV | +| Development Fund (companion multisig action) | `0x617866cC4a089c3653ddC31a618b078291839AeB` – 2,486,471.60 SOV | +| Stability Pool subsidy (Part 3 – one-action admin-governor proposal) | `CommunityIssuance.setAPR(0)` | +| Contract addresses | Deployed and explorer-verified before publication — see *Deployed contracts* above | +| Calldata | Frozen into the proposals at creation; diffed against the published tables before voting | +| Perimeter phase 2 | Targeted for the weeks following execution, with a reserve window; rate schedule published then | + +## Rationale + +Three ballots: the deployment is eleven owner-governor actions against a ten-action cap, and the subsidy retirement lives on the admin governor because that governor owns the contract it touches – the same split Bitocracy used for SIP-0046 and SIP-0084. One window because the actions form one programme: the perimeter, and the treasury housekeeping that closes out the 2021 fund arrangement. Each part is its own proposal with its own tally, so holders judge each on its merits – with one stated cost: Part 2 carries the final wiring action and the Adoption Fund withdrawal on the same ballot, so a holder weighing those two purposes weighs them together. That is the price of keeping the programme to two governance cycles, stated here rather than hidden. The Development Fund residue moves by multisig because the Exchequer already holds the relevant authority on that contract; disclosing it here, rather than exercising it silently, is the point of this section. + +## License + +Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/). From ae34865a42b0a7b0a177730162b5cc4c5fbd9609 Mon Sep 17 00:00:00 2001 From: Tyrone Johnson Date: Wed, 12 Aug 2026 10:06:54 +0300 Subject: [PATCH 02/11] SIP-0094: add title --- SIP-0094.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/SIP-0094.md b/SIP-0094.md index 7604744..bca183e 100644 --- a/SIP-0094.md +++ b/SIP-0094.md @@ -1,4 +1,13 @@ +--- +SIP: '0094' +Title: Perimeter Fee Activation and Adoption Fund Transfer +Author: Edan Yago (@YagoBit) +Status: Draft +Track: Contract +Created: 2026-08-12 +--- + # SIP-0094 (Parts 1–3): Perimeter Fee Activation and Adoption Fund Transfer ## Summary From 7403002eecb2ba2c46195b56136d7f81c6f34d6f Mon Sep 17 00:00:00 2001 From: Tyrone Johnson Date: Wed, 12 Aug 2026 10:08:18 +0300 Subject: [PATCH 03/11] SIP-0094: doc format fix --- SIP-0094.md | 1 - 1 file changed, 1 deletion(-) diff --git a/SIP-0094.md b/SIP-0094.md index bca183e..2fd5c1a 100644 --- a/SIP-0094.md +++ b/SIP-0094.md @@ -1,4 +1,3 @@ - --- SIP: '0094' Title: Perimeter Fee Activation and Adoption Fund Transfer From b7e354f875f1f12e3b77e99db8c457605191815d Mon Sep 17 00:00:00 2001 From: Tyrone Johnson Date: Wed, 12 Aug 2026 10:15:48 +0300 Subject: [PATCH 04/11] SIP-0094: format & text update --- SIP-0094.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/SIP-0094.md b/SIP-0094.md index 2fd5c1a..b9f7685 100644 --- a/SIP-0094.md +++ b/SIP-0094.md @@ -57,8 +57,6 @@ A one-action proposal on the admin governor – the governor that owns the relev ### Companion actions, disclosed for completeness - - - **Development Fund residue.** The Development Fund's 2,486,471.60 vested SOV transfers to the Exchequer by a direct multisig transaction in the same window, under the locked-token-owner authority the Exchequer holds on that contract, through the fund's deployed, verified sweep function – which empties the fund and retires it. No governance action is required for it; it is listed here so this post describes the whole programme in one place. - **The enable step.** After Parts 1 and 2 execute, charging begins only when post-deployment verification is green, monitoring is live, and the pause switch has been rehearsed in a live drill – at which point the Exchequer sends the enable transaction. @@ -105,7 +103,7 @@ publishes, so the table below carries final addresses at publication. Every addr source-verified on the Rootstock Blockscout explorer before publication, and each proposal's on-chain actions can be checked against this table action by action. -**Core Perimeter Fee contracts** (repo [`Sovryn-perimeter`](https://github.com/DistributedCollective/Sovryn-perimeter), commit ``): +#### **Core Perimeter Fee contracts** (repo [`Sovryn-perimeter`](https://github.com/DistributedCollective/Sovryn-perimeter), commit ``): | Contract | Address | | -------------------------------- | ------------------------------------------------ | @@ -114,7 +112,8 @@ on-chain actions can be checked against this table action by action. | ExitFeeVault proxy | `` | | ExitFeeVault implementation | `` | -**Lending / borrowing implementations installed by Part 1** (repo [`Sovryn-smart-contracts`](https://github.com/DistributedCollective/Sovryn-smart-contracts), branch `sovryn-perimeter-fee`, commit ``, review in PR [#580](https://github.com/DistributedCollective/Sovryn-smart-contracts/pull/580)): + +#### **Lending / borrowing implementations installed by Part 1** (repo [`Sovryn-smart-contracts`](https://github.com/DistributedCollective/Sovryn-smart-contracts), branch `sovryn-perimeter-fee`, commit ``, review in PR [#580](https://github.com/DistributedCollective/Sovryn-smart-contracts/pull/580)): | Contract | Address | | --------------------- | ------------------------------------------------ | @@ -126,7 +125,8 @@ on-chain actions can be checked against this table action by action. | ExitFeeModule | `` | | ColFeeBorrowerExitOps | `` | -**Zero implementations installed by Part 1** (repo [`zero-contracts`](https://github.com/DistributedCollective/zero-contracts), branch `sovryn-perimeter-fee`, commit ``, review in PR [#10](https://github.com/DistributedCollective/zero-contracts/pull/10)): + +#### **Zero implementations installed by Part 1** (repo [`zero-contracts`](https://github.com/DistributedCollective/zero-contracts), branch `sovryn-perimeter-fee`, commit ``, review in PR [#10](https://github.com/DistributedCollective/zero-contracts/pull/10)): | Contract | Address | | ---------------------------------------------- | ------------------------------------------------ | @@ -164,7 +164,6 @@ Risk mitigants: | Development Fund (companion multisig action) | `0x617866cC4a089c3653ddC31a618b078291839AeB` – 2,486,471.60 SOV | | Stability Pool subsidy (Part 3 – one-action admin-governor proposal) | `CommunityIssuance.setAPR(0)` | | Contract addresses | Deployed and explorer-verified before publication — see *Deployed contracts* above | -| Calldata | Frozen into the proposals at creation; diffed against the published tables before voting | | Perimeter phase 2 | Targeted for the weeks following execution, with a reserve window; rate schedule published then | ## Rationale From deeebc8ac9565a8bcaf26b4a4c15e6bd83e2daa9 Mon Sep 17 00:00:00 2001 From: Tyrone Johnson Date: Wed, 12 Aug 2026 10:39:31 +0300 Subject: [PATCH 05/11] SIP-0094: one document, not one per part MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The text still promised a separate technical SIP document per ballot — left over from the earlier multi-document plan. Corrected in all three places: the summary now says this document covers all three parts, the Part 1 section points at the Deployed contracts section for the action-by-action breakdown, and the rollback anchors and runtime code hashes are now an actual table in this document rather than a reference to a document that does not exist. Notes that the two new registrations have no rollback anchor and that the liquidation module is deliberately not redeployed. --- SIP-0094.md | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/SIP-0094.md b/SIP-0094.md index b9f7685..4c8e1b7 100644 --- a/SIP-0094.md +++ b/SIP-0094.md @@ -11,7 +11,7 @@ Created: 2026-08-12 ## Summary -This post introduces SIP-0094, voted as three technical proposals: the governor caps any single proposal at ten actions (`proposalMaxOperations`), a split Bitocracy has used before (SIP-0046, Parts 1–4; SIP-0084, Parts 1–2). Parts 1 and 2 run on the owner governor; Part 3 runs on the admin governor, which owns the contract it touches. Each part is its own ballot with its own technical SIP document in the SIPS repository, all referencing this post – the single narrative reference for the programme. All three are created in the same cycle and voted in the same window; they form one programme. +This post introduces SIP-0094, voted as three technical proposals: the governor caps any single proposal at ten actions (`proposalMaxOperations`), a split Bitocracy has used before (SIP-0046, Parts 1–4; SIP-0084, Parts 1–2). Parts 1 and 2 run on the owner governor; Part 3 runs on the admin governor, which owns the contract it touches. Each part is its own ballot, and this document covers all three – the single reference for the programme, narrative and technical alike. All three are created in the same cycle and voted in the same window; they form one programme. **Part 1** installs the Perimeter Fee – the fee component of the Sovryn security perimeter – across the lending protocol and Zero: ten actions, all of them code installation. **Part 2** carries three actions: the final wiring action and, alongside it in two transfer legs, the Adoption Fund's fully-vested balance of 5,021,309.20 SOV moving to the Exchequer, continuing the arrangement Bitocracy created in SIP-0015 and has exercised since in SIP-0065 (2023), SIP-0076 (2024), and SIP-0079 (2024). @@ -44,7 +44,7 @@ Most money markets charge nothing on withdrawal. Those same markets can also do ### SIP-0094 Part 1 – Perimeter Fee installation (ten actions) -Ten governance actions that install the Perimeter Fee code: new lending-pool logic modules, three refreshed protocol modules, the fee module that owns the governance setters, the borrower-exit hook, and upgrades to two Zero contracts with their controller wiring. All ten execute as one atomic transaction – there is no partial-installation state. The action-by-action breakdown, with exact call data, target-by-target ownership verification, and rollback anchors for every replaced address, is in the Part 1 SIP document in the SIPS repository. +Ten governance actions that install the Perimeter Fee code: new lending-pool logic modules, three refreshed protocol modules, the fee module that owns the governance setters, the borrower-exit hook, and upgrades to two Zero contracts with their controller wiring. All ten execute as one atomic transaction – there is no partial-installation state. The action-by-action breakdown, with exact call data, target-by-target ownership verification, and rollback anchors for every replaced address, is in *Deployed contracts* below. ### SIP-0094 Part 2 – final wiring and Adoption Fund transfer (three actions) @@ -133,9 +133,25 @@ on-chain actions can be checked against this table action by action. | BorrowerOperations implementation (fee-hooked) | `` | | CollSurplusPool implementation | `` | -The per-part technical SIP documents additionally list, for every replaced module, the -currently-live implementation it replaces (the rollback anchor) and the runtime code hash of -each new artifact. +For every module Part 1 replaces, the table below records the currently-live implementation +it replaces – the rollback anchor – together with the runtime code hash of each new artifact, +so a voter can bind every proposal action to both the address it installs and the address it +supersedes. + +| Replaced module | Currently live (rollback anchor) | New implementation | Runtime code hash | +| --------------- | -------------------------------- | ------------------ | ----------------- | +| LoanClosingsRollover | `` | `` | `` | +| LoanClosingsWith | `` | `` | `` | +| LoanMaintenance | `` | `` | `` | +| iToken logic (LM) | `` | `` | `` | +| iToken logic (WrbtcLM) | `` | `` | `` | +| Zero BorrowerOperations | `` | `` | `` | +| Zero CollSurplusPool | first-ever upgrade – no prior implementation | `` | `` | + +`ExitFeeModule` and `ColFeeBorrowerExitOps` are new registrations rather than replacements, so +they have no rollback anchor. `LoanClosingsLiquidation` is deliberately **not** redeployed: its +runtime bytecode is byte-identical to the module already registered, so liquidations keep +running against the same code throughout. ## Risks From 6d1d870064c309d8ea2c344428df9178745916ee Mon Sep 17 00:00:00 2001 From: Tyrone Johnson Date: Thu, 13 Aug 2026 00:49:37 +0300 Subject: [PATCH 06/11] SIP-0094: fill the deployed core contract addresses The Perimeter Fee controller and vault are deployed on RSK mainnet from Sovryn-perimeter 881c74d and source-verified on Blockscout, so the core table now carries final addresses instead of placeholders. Records that the controller shipped switched off with the four charging surfaces at 10 bps, the AMM surface shut, and admin plus ownership pointed at the Exchequer. The lending and Zero tables stay placeholders until Phase B. --- SIP-0094.md | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/SIP-0094.md b/SIP-0094.md index 4c8e1b7..3677d64 100644 --- a/SIP-0094.md +++ b/SIP-0094.md @@ -103,17 +103,22 @@ publishes, so the table below carries final addresses at publication. Every addr source-verified on the Rootstock Blockscout explorer before publication, and each proposal's on-chain actions can be checked against this table action by action. -#### **Core Perimeter Fee contracts** (repo [`Sovryn-perimeter`](https://github.com/DistributedCollective/Sovryn-perimeter), commit ``): - -| Contract | Address | -| -------------------------------- | ------------------------------------------------ | -| ExitFeeController proxy | `` | -| ExitFeeController implementation | `` | -| ExitFeeVault proxy | `` | -| ExitFeeVault implementation | `` | - - -#### **Lending / borrowing implementations installed by Part 1** (repo [`Sovryn-smart-contracts`](https://github.com/DistributedCollective/Sovryn-smart-contracts), branch `sovryn-perimeter-fee`, commit ``, review in PR [#580](https://github.com/DistributedCollective/Sovryn-smart-contracts/pull/580)): +#### **Core Perimeter Fee contracts** (repo [`Sovryn-perimeter`](https://github.com/DistributedCollective/Sovryn-perimeter), commit `881c74d`) — deployed and verified 2026-08-12: + +| Contract | Address | +| -------------------------------- | -------------------------------------------- | +| ExitFeeController proxy | `0x8C1abf364Bf214E41221562693BD9Fb26D6Fa563` | +| ExitFeeController implementation | `0x33EF630510Ba4d5e13Cfc3a49Ad35BEf5c9c2604` | +| ExitFeeVault proxy | `0x2ba389B021fA4A5F50cc1758EFD23Ca066d0Be08` | +| ExitFeeVault implementation | `0xab3761D0800C4310414e75Fd8b545cE094C20e26` | + +Both implementations are source-verified on the Rootstock Blockscout explorer (solc 0.8.20, +evm paris, optimizer 200 runs). The controller was deployed switched **off** and configured +in the same session: the four charging surfaces registered active at 10 bps, the AMM surface +registered shut, the fee receiver pointed at the vault, and both contracts' operational admin +and ownership directed to the Exchequer Multisig — read back from chain after execution. + +**Lending / borrowing implementations installed by Part 1** (repo [`Sovryn-smart-contracts`](https://github.com/DistributedCollective/Sovryn-smart-contracts), branch `sovryn-perimeter-fee`, commit ``, review in PR [#580](https://github.com/DistributedCollective/Sovryn-smart-contracts/pull/580)): | Contract | Address | | --------------------- | ------------------------------------------------ | From 0cfb9e75f5f7bb75c92d73ce8a0258d20444c442 Mon Sep 17 00:00:00 2001 From: Tyrone Johnson Date: Thu, 13 Aug 2026 12:32:47 +0300 Subject: [PATCH 07/11] SIP-0094: fill the Part 1 implementation address tables Phase B executed 2026-08-13: seven lending artifacts (commit 93997a55) and the two Zero implementations (commit a6ad838e), all verified to hold code on-chain, live proxies untouched. Zero implementation codehashes are byte-identical to the fork rehearsal's pins. Adds the SwapsImplSovrynSwapLib note: linked, not registered, address required to reproduce module bytecode. The rollback-anchor table stays TBD until CP-C freezes the live implementations it replaces. --- SIP-0094.md | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/SIP-0094.md b/SIP-0094.md index 3677d64..c7e810b 100644 --- a/SIP-0094.md +++ b/SIP-0094.md @@ -118,25 +118,32 @@ in the same session: the four charging surfaces registered active at 10 bps, the registered shut, the fee receiver pointed at the vault, and both contracts' operational admin and ownership directed to the Exchequer Multisig — read back from chain after execution. -**Lending / borrowing implementations installed by Part 1** (repo [`Sovryn-smart-contracts`](https://github.com/DistributedCollective/Sovryn-smart-contracts), branch `sovryn-perimeter-fee`, commit ``, review in PR [#580](https://github.com/DistributedCollective/Sovryn-smart-contracts/pull/580)): +**Lending / borrowing implementations installed by Part 1** (repo [`Sovryn-smart-contracts`](https://github.com/DistributedCollective/Sovryn-smart-contracts), branch `sovryn-perimeter-fee`, commit `93997a55`, review in PR [#580](https://github.com/DistributedCollective/Sovryn-smart-contracts/pull/580)): | Contract | Address | | --------------------- | ------------------------------------------------ | -| LoanTokenLogicLM | `` | -| LoanTokenLogicWrbtcLM | `` | -| LoanClosingsRollover | `` | -| LoanClosingsWith | `` | -| LoanMaintenance | `` | -| ExitFeeModule | `` | -| ColFeeBorrowerExitOps | `` | +| LoanTokenLogicLM | `0x6acf70d9E194a9cbe60c1283aaF30fFb252358AC` | +| LoanTokenLogicWrbtcLM | `0x96E4f6D9276A36e1c51485119406667F5eAe12ee` | +| LoanClosingsRollover | `0x2aed71b3fdD6D51f38405Fd5912624515dB46783` | +| LoanClosingsWith | `0xbC97D6BdB4eb0741179eDA636aCdFed34bB9d67E` | +| LoanMaintenance | `0x9958b841d4af6459E4c520876F238Ec59a4Bd83D` | +| ExitFeeModule | `0x4C0eAc3f96a4fc25e5251dBA6Ec2369db0CA768B` | +| ColFeeBorrowerExitOps | `0x381fFaf5bbFa532a6E4A33E6bffCa97755C99cB3` | -#### **Zero implementations installed by Part 1** (repo [`zero-contracts`](https://github.com/DistributedCollective/zero-contracts), branch `sovryn-perimeter-fee`, commit ``, review in PR [#10](https://github.com/DistributedCollective/zero-contracts/pull/10)): +The three protocol modules and `LoanMaintenance` link the stateless library +`SwapsImplSovrynSwapLib`, redeployed alongside them at +`0xFE2bb2d345452673C4E90622147c4F515F2F4CE0` (its source is unchanged, but the interface it +imports is extended by this release, which changes the compiled artifact). The library is +not registered by Part 1 — it is referenced only inside the modules' link references — and +its address is needed to reproduce their bytecode. + +#### **Zero implementations installed by Part 1** (repo [`zero-contracts`](https://github.com/DistributedCollective/zero-contracts), branch `sovryn-perimeter-fee`, commit `a6ad838e`, review in PR [#10](https://github.com/DistributedCollective/zero-contracts/pull/10)): | Contract | Address | | ---------------------------------------------- | ------------------------------------------------ | -| BorrowerOperations implementation (fee-hooked) | `` | -| CollSurplusPool implementation | `` | +| BorrowerOperations implementation (fee-hooked) | `0xcD22ba4b3ED7D7297b40Dcd26d982634A0207885` | +| CollSurplusPool implementation | `0x71A605F81a66eB93Ce9b8091014da858bFD4b6dA` | For every module Part 1 replaces, the table below records the currently-live implementation it replaces – the rollback anchor – together with the runtime code hash of each new artifact, From c0c862930631d76fd2f1e10007d73fec708aa6d1 Mon Sep 17 00:00:00 2001 From: Tyrone Johnson Date: Thu, 13 Aug 2026 19:26:30 +0300 Subject: [PATCH 08/11] SIP-0094: LoanClosingsWith relinked to the verified swap library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The module now registered by Part 1 is 0x279D307C09E30d282aA96C3F4D216051277787f7, linked against the already-verified library 0x47Dc479c… instead of the byte-identical unverifiable copy, so voters audit a library whose source is already on the explorer. On-chain proof: the relinked module differs from its predecessor in exactly the 20 link-address bytes. --- SIP-0094.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/SIP-0094.md b/SIP-0094.md index c7e810b..6ea2b1a 100644 --- a/SIP-0094.md +++ b/SIP-0094.md @@ -125,18 +125,20 @@ and ownership directed to the Exchequer Multisig — read back from chain after | LoanTokenLogicLM | `0x6acf70d9E194a9cbe60c1283aaF30fFb252358AC` | | LoanTokenLogicWrbtcLM | `0x96E4f6D9276A36e1c51485119406667F5eAe12ee` | | LoanClosingsRollover | `0x2aed71b3fdD6D51f38405Fd5912624515dB46783` | -| LoanClosingsWith | `0xbC97D6BdB4eb0741179eDA636aCdFed34bB9d67E` | +| LoanClosingsWith | `0x279D307C09E30d282aA96C3F4D216051277787f7` | | LoanMaintenance | `0x9958b841d4af6459E4c520876F238Ec59a4Bd83D` | | ExitFeeModule | `0x4C0eAc3f96a4fc25e5251dBA6Ec2369db0CA768B` | | ColFeeBorrowerExitOps | `0x381fFaf5bbFa532a6E4A33E6bffCa97755C99cB3` | -The three protocol modules and `LoanMaintenance` link the stateless library -`SwapsImplSovrynSwapLib`, redeployed alongside them at -`0xFE2bb2d345452673C4E90622147c4F515F2F4CE0` (its source is unchanged, but the interface it -imports is extended by this release, which changes the compiled artifact). The library is -not registered by Part 1 — it is referenced only inside the modules' link references — and -its address is needed to reproduce their bytecode. +`LoanClosingsWith` links the stateless library `SwapsImplSovrynSwapLib` at +`0x47Dc479cA058B4BB7C4AD9D56EE3a029236b88A8` — the deployment already live and +source-verified on the explorer, whose code this release leaves untouched. (A byte-identical +copy of the library was deployed during the release process and then set aside in favor of +linking the verified original; the two differ only in their embedded self-address and +metadata fingerprint, which anyone can confirm on-chain.) The library is not registered by +Part 1 — it is referenced only inside `LoanClosingsWith`'s link reference — and its address +is needed to reproduce that module's bytecode. #### **Zero implementations installed by Part 1** (repo [`zero-contracts`](https://github.com/DistributedCollective/zero-contracts), branch `sovryn-perimeter-fee`, commit `a6ad838e`, review in PR [#10](https://github.com/DistributedCollective/zero-contracts/pull/10)): From 3fdc85f336359fa6575d8e629514eef0d6ddeec3 Mon Sep 17 00:00:00 2001 From: Tyrone Johnson Date: Thu, 13 Aug 2026 22:37:38 +0300 Subject: [PATCH 09/11] SIP-0094: fill the rollback-anchor table from live chain state All seven rows now carry the currently-live implementation each Part 1 action supersedes (read from the protocol's getTarget routing, the two iToken beacons' active module logs, and the two Zero proxies), the final new implementation, and its on-chain runtime code hash. The CollSurplusPool row's 'no prior implementation' claim is corrected: the proxy has served its original implementation unupgraded since deployment, and that address is the rollback anchor. Anchors are re-verified at proposal creation; drift voids and re-freezes the table. --- SIP-0094.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/SIP-0094.md b/SIP-0094.md index 6ea2b1a..a4861ee 100644 --- a/SIP-0094.md +++ b/SIP-0094.md @@ -150,17 +150,19 @@ is needed to reproduce that module's bytecode. For every module Part 1 replaces, the table below records the currently-live implementation it replaces – the rollback anchor – together with the runtime code hash of each new artifact, so a voter can bind every proposal action to both the address it installs and the address it -supersedes. +supersedes. Anchors were read from the live protocol, beacons, and proxies on +2026-08-13; they are re-verified against the chain immediately before proposal creation, and +any drift (an unrelated upgrade landing in between) voids and re-freezes this table. | Replaced module | Currently live (rollback anchor) | New implementation | Runtime code hash | | --------------- | -------------------------------- | ------------------ | ----------------- | -| LoanClosingsRollover | `` | `` | `` | -| LoanClosingsWith | `` | `` | `` | -| LoanMaintenance | `` | `` | `` | -| iToken logic (LM) | `` | `` | `` | -| iToken logic (WrbtcLM) | `` | `` | `` | -| Zero BorrowerOperations | `` | `` | `` | -| Zero CollSurplusPool | first-ever upgrade – no prior implementation | `` | `` | +| LoanClosingsRollover | `0xc7AEa780c8b891e2c101a9ED2f9EaCF87FFdc359` | `0x2aed71b3fdD6D51f38405Fd5912624515dB46783` | `0x40f1f693c3c81db16c6d3e002e2bd8623bb84f68dd1e3f7dc07ced9fc69813bb` | +| LoanClosingsWith | `0x47eCc9391fd6f5761B8d24139f36Ce61fF6a9819` | `0x279D307C09E30d282aA96C3F4D216051277787f7` | `0xe96d09eddecabb1cde9e45948848d882131e60d6fd9bc373d0972d2447c62621` | +| LoanMaintenance | `0x4BC462e2c8D106511D8e7985b05A52fD8b726464` | `0x9958b841d4af6459E4c520876F238Ec59a4Bd83D` | `0x530f2fc38c777f5a2c9dedf83f3480c86d178195ba2c109e61717e1a68129916` | +| iToken logic (LM) | `0xfaffde7161C58743B86a22EF268245560aC705dD` | `0x6acf70d9E194a9cbe60c1283aaF30fFb252358AC` | `0xdc1726783af8a2d9937479e4671f0aadad57be4027f7c6f6ff2653b71b0c6bba` | +| iToken logic (WrbtcLM) | `0x24B3687966C4f05e48ED5A3B9c14F56d9ad5BF6B` | `0x96E4f6D9276A36e1c51485119406667F5eAe12ee` | `0x376419bffcd439d0b4fad455fc705c931258b395fea7ec86ff54e35e5011a2ea` | +| Zero BorrowerOperations | `0xD603B4c5F7BF13a2AA510F2c625546dB4138D330` | `0xcD22ba4b3ED7D7297b40Dcd26d982634A0207885` | `0x1f96f7545bb3623376149bd9fd356f6b95d822560fe0b51c7a3254c61854bcb9` | +| Zero CollSurplusPool | `0xE9005C36452576eFA74f297906e77381E6878398` (the original implementation — never upgraded before this proposal) | `0x71A605F81a66eB93Ce9b8091014da858bFD4b6dA` | `0x5c768ef339150f191698034de26ea5c4cf012817028ef0d017bcedd2966518a2` | `ExitFeeModule` and `ColFeeBorrowerExitOps` are new registrations rather than replacements, so they have no rollback anchor. `LoanClosingsLiquidation` is deliberately **not** redeployed: its From 188fba5decacada75202c078fcf57a1e300fa912 Mon Sep 17 00:00:00 2001 From: Tyrone Johnson Date: Thu, 20 Aug 2026 00:42:34 +0300 Subject: [PATCH 10/11] SIP-0094: correct the library disclosure, add the Part 1 action table, fix a stray character MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Review found the library paragraph understated the facts: LoanClosingsWith links the pre-existing library 0x47Dc479c…, but the other two registered modules, LoanClosingsRollover and LoanMaintenance, link 0xFE2bb2d… — the copy this release deployed, which the text described as merely set aside. Both addresses are needed to rebuild the registered modules, and both are explorer-verified, so both are now disclosed in a table naming which module links which. Confirmed on-chain by reading each module's runtime bytecode. The Part 1 summary promised action-by-action call data in the deployed contracts section, which carried only addresses and code hashes. That section now holds the ten actions in execution order with target, signature and argument, noting that the encoded call data is frozen into the proposal at creation, and that the implementation swap precedes the controller wiring in actions 9 and 10. Also removes a stray period after the third Risks bullet. --- SIP-0094.md | 51 +++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/SIP-0094.md b/SIP-0094.md index a4861ee..5ecf1c0 100644 --- a/SIP-0094.md +++ b/SIP-0094.md @@ -103,7 +103,28 @@ publishes, so the table below carries final addresses at publication. Every addr source-verified on the Rootstock Blockscout explorer before publication, and each proposal's on-chain actions can be checked against this table action by action. -#### **Core Perimeter Fee contracts** (repo [`Sovryn-perimeter`](https://github.com/DistributedCollective/Sovryn-perimeter), commit `881c74d`) — deployed and verified 2026-08-12: +#### **Part 1 — the ten actions, in execution order.** Each is a single call with one address +argument; the ABI-encoded call data is that argument, and it is frozen into the proposal at +creation, where it can be read in the Bitocracy interface and rebuilt from the proposal +builders in the lending repository. + +| # | Target | Signature | Argument | +| - | ------ | --------- | -------- | +| 1 | LoanTokenLogicBeaconLM `0x5b155ECcC1dC31Ea59F2c12d2F168C956Ac0FFAa` | `registerLoanTokenModule(address)` | `0x6acf70d9E194a9cbe60c1283aaF30fFb252358AC` | +| 2 | LoanTokenLogicBeaconWrbtc `0x845eF7Be59664899398282Ef42239634aBDd752C` | `registerLoanTokenModule(address)` | `0x96E4f6D9276A36e1c51485119406667F5eAe12ee` | +| 3 | sovrynProtocol `0x5A0D867e0D70Fcc6Ade25C3F1B89d618b5B4Eaa7` | `replaceContract(address)` | `0x2aed71b3fdD6D51f38405Fd5912624515dB46783` | +| 4 | sovrynProtocol | `replaceContract(address)` | `0x279D307C09E30d282aA96C3F4D216051277787f7` | +| 5 | sovrynProtocol | `replaceContract(address)` | `0x9958b841d4af6459E4c520876F238Ec59a4Bd83D` | +| 6 | sovrynProtocol | `replaceContract(address)` | `0x4C0eAc3f96a4fc25e5251dBA6Ec2369db0CA768B` | +| 7 | sovrynProtocol | `setColFeeBorrowerExitOps(address)` | `0x381fFaf5bbFa532a6E4A33E6bffCa97755C99cB3` | +| 8 | CollSurplusPool proxy `0x310ec7Fe6e4943DA773De8948255E37CC45e34bb` | `setImplementation(address)` | `0x71A605F81a66eB93Ce9b8091014da858bFD4b6dA` | +| 9 | BorrowerOperations proxy `0x5B9dB4B8bdeF3e57323187a9AC2639C5DEe5FD39` | `setImplementation(address)` | `0xcD22ba4b3ED7D7297b40Dcd26d982634A0207885` | +| 10 | BorrowerOperations proxy | `setExitFeeController(address)` | `0x8C1abf364Bf214E41221562693BD9Fb26D6Fa563` | + +Actions 9 and 10 are ordered so the implementation swap precedes the controller wiring +inside the same atomic transaction. No action carries RBTC value. + +**Core Perimeter Fee contracts** (repo [`Sovryn-perimeter`](https://github.com/DistributedCollective/Sovryn-perimeter), commit `881c74d`) — deployed and verified 2026-08-12: | Contract | Address | | -------------------------------- | -------------------------------------------- | @@ -131,14 +152,25 @@ and ownership directed to the Exchequer Multisig — read back from chain after | ColFeeBorrowerExitOps | `0x381fFaf5bbFa532a6E4A33E6bffCa97755C99cB3` | -`LoanClosingsWith` links the stateless library `SwapsImplSovrynSwapLib` at -`0x47Dc479cA058B4BB7C4AD9D56EE3a029236b88A8` — the deployment already live and -source-verified on the explorer, whose code this release leaves untouched. (A byte-identical -copy of the library was deployed during the release process and then set aside in favor of -linking the verified original; the two differ only in their embedded self-address and -metadata fingerprint, which anyone can confirm on-chain.) The library is not registered by -Part 1 — it is referenced only inside `LoanClosingsWith`'s link reference — and its address -is needed to reproduce that module's bytecode. +Three of the modules Part 1 registers link the stateless library `SwapsImplSovrynSwapLib`, +and they do not all link the same deployment of it. Both are needed to reproduce their +bytecode, and both are source-verified on the explorer: + +| Registered module | Links `SwapsImplSovrynSwapLib` at | +| ----------------- | --------------------------------- | +| `LoanClosingsRollover` | `0xFE2bb2d345452673C4E90622147c4F515F2F4CE0` | +| `LoanMaintenance` | `0xFE2bb2d345452673C4E90622147c4F515F2F4CE0` | +| `LoanClosingsWith` | `0x47Dc479cA058B4BB7C4AD9D56EE3a029236b88A8` | + +`0x47Dc479c…` is the library deployment already live before this release, whose code the +release leaves untouched. `0xFE2bb2d…` was deployed during this release: the library's own +source is unchanged, but it imports an interface this release extends, which changes the +compiled artifact and therefore its address. The two are byte-identical apart from each +one's embedded self-address and metadata fingerprint — anyone can confirm that on-chain. + +Neither library is registered by Part 1; they are referenced only inside the linked modules' +bytecode, and both addresses are listed here so every registered module can be independently +rebuilt from source. #### **Zero implementations installed by Part 1** (repo [`zero-contracts`](https://github.com/DistributedCollective/zero-contracts), branch `sovryn-perimeter-fee`, commit `a6ad838e`, review in PR [#10](https://github.com/DistributedCollective/zero-contracts/pull/10)): @@ -176,7 +208,6 @@ Risks introduced: - **A fee where the market's default is zero.** Users pay 10 basis points on withdrawals that were previously free. - **The rail precedes the rest of the perimeter.** Phase 1 charges its minimal rate before phase 2 ships. - **New code in live paths.** The fee vault and controller are new contracts; the release also replaces three live loan-closing and maintenance modules, upgrades two Zero contracts, one for the first time, and the borrower-exit hook carries the same protocol-level authority the existing core modules already hold. -. Risk mitigants: From 340148c88b827cd61c2f99cd825e7ce71bf94539 Mon Sep 17 00:00:00 2001 From: Tyrone Johnson Date: Tue, 25 Aug 2026 01:20:44 +0300 Subject: [PATCH 11/11] SIP-0094: final deployed addresses, status Ready for vote Carries the addresses of the release that is actually on chain, replacing the set the document named before the identifier re-cut moved every surface id and required a redeploy. All ten Part 1 actions were checked against the calldata the proposal builders produce, action by action, on a forked-mainnet run against the deployed bytecode. Also in this pass: - action 7's signature is setBorrowerExitPerimeterOps(address), and the module it registers is BorrowerExitPerimeterOps -- the re-cut reached both names; - all three library consumers now link the same SwapsImplSovrynSwapLib deployment, the one the explorer verifies as a full source match, so the split-link table and its explanation are gone; - runtime code hashes recomputed from chain for all six replaced artifacts; - all seven rollback anchors re-read from the live protocol, beacons and proxies: unchanged, no drift; - ownership stated precisely -- the Exchequer is the operational admin today and the named pending owner, and accepts before execution. --- SIP-0094.md | 128 +++++++++++++++++++++++++++------------------------- 1 file changed, 66 insertions(+), 62 deletions(-) diff --git a/SIP-0094.md b/SIP-0094.md index 5ecf1c0..d3a7ea9 100644 --- a/SIP-0094.md +++ b/SIP-0094.md @@ -2,7 +2,7 @@ SIP: '0094' Title: Perimeter Fee Activation and Adoption Fund Transfer Author: Edan Yago (@YagoBit) -Status: Draft +Status: Ready for vote Track: Contract Created: 2026-08-12 --- @@ -98,8 +98,8 @@ checkable independently by anyone. ### Deployed contracts -The Perimeter Fee contracts deploy — switched off, Exchequer-owned — **before** this post -publishes, so the table below carries final addresses at publication. Every address is +The Perimeter Fee contracts deploy — switched off, under Exchequer control — **before** this +post publishes, so the table below carries final addresses at publication. Every address is source-verified on the Rootstock Blockscout explorer before publication, and each proposal's on-chain actions can be checked against this table action by action. @@ -108,95 +108,99 @@ argument; the ABI-encoded call data is that argument, and it is frozen into the creation, where it can be read in the Bitocracy interface and rebuilt from the proposal builders in the lending repository. -| # | Target | Signature | Argument | -| - | ------ | --------- | -------- | -| 1 | LoanTokenLogicBeaconLM `0x5b155ECcC1dC31Ea59F2c12d2F168C956Ac0FFAa` | `registerLoanTokenModule(address)` | `0x6acf70d9E194a9cbe60c1283aaF30fFb252358AC` | -| 2 | LoanTokenLogicBeaconWrbtc `0x845eF7Be59664899398282Ef42239634aBDd752C` | `registerLoanTokenModule(address)` | `0x96E4f6D9276A36e1c51485119406667F5eAe12ee` | -| 3 | sovrynProtocol `0x5A0D867e0D70Fcc6Ade25C3F1B89d618b5B4Eaa7` | `replaceContract(address)` | `0x2aed71b3fdD6D51f38405Fd5912624515dB46783` | -| 4 | sovrynProtocol | `replaceContract(address)` | `0x279D307C09E30d282aA96C3F4D216051277787f7` | -| 5 | sovrynProtocol | `replaceContract(address)` | `0x9958b841d4af6459E4c520876F238Ec59a4Bd83D` | -| 6 | sovrynProtocol | `replaceContract(address)` | `0x4C0eAc3f96a4fc25e5251dBA6Ec2369db0CA768B` | -| 7 | sovrynProtocol | `setColFeeBorrowerExitOps(address)` | `0x381fFaf5bbFa532a6E4A33E6bffCa97755C99cB3` | -| 8 | CollSurplusPool proxy `0x310ec7Fe6e4943DA773De8948255E37CC45e34bb` | `setImplementation(address)` | `0x71A605F81a66eB93Ce9b8091014da858bFD4b6dA` | -| 9 | BorrowerOperations proxy `0x5B9dB4B8bdeF3e57323187a9AC2639C5DEe5FD39` | `setImplementation(address)` | `0xcD22ba4b3ED7D7297b40Dcd26d982634A0207885` | -| 10 | BorrowerOperations proxy | `setExitFeeController(address)` | `0x8C1abf364Bf214E41221562693BD9Fb26D6Fa563` | +| # | Target | Signature | Argument | +| --- | ---------------------------------------------------------------------- | -------------------------------------- | -------------------------------------------- | +| 1 | LoanTokenLogicBeaconLM `0x5b155ECcC1dC31Ea59F2c12d2F168C956Ac0FFAa` | `registerLoanTokenModule(address)` | `0x593DB96E61F59F1278068742486Fc85CDBe9D872` | +| 2 | LoanTokenLogicBeaconWrbtc `0x845eF7Be59664899398282Ef42239634aBDd752C` | `registerLoanTokenModule(address)` | `0x6c8f59D321560f4bEF84c99e83dd7FF31122e14f` | +| 3 | sovrynProtocol `0x5A0D867e0D70Fcc6Ade25C3F1B89d618b5B4Eaa7` | `replaceContract(address)` | `0xdB4fF0a861bF0c714B31E678c919c2B7EfD05329` | +| 4 | sovrynProtocol | `replaceContract(address)` | `0xa3FCC9F88De9A7f0258eda6cD8d6F7D39ef6fb8d` | +| 5 | sovrynProtocol | `replaceContract(address)` | `0xa87Bd1eF82FA2BE049473c73eAaa97d6AB9C4399` | +| 6 | sovrynProtocol | `replaceContract(address)` | `0x0562e396f5fF7e819c8e9CcF25DCb68e16A2672F` | +| 7 | sovrynProtocol | `setBorrowerExitPerimeterOps(address)` | `0xe533dc6D03Ae97977Da3357A98AA94b769738AB5` | +| 8 | CollSurplusPool proxy `0x310ec7Fe6e4943DA773De8948255E37CC45e34bb` | `setImplementation(address)` | `0xdd518C2aae5A83812883D4e350b88d3566792bE4` | +| 9 | BorrowerOperations proxy `0x5B9dB4B8bdeF3e57323187a9AC2639C5DEe5FD39` | `setImplementation(address)` | `0x020aAb1d84E38b619A4C49f48d472c3b9187ce93` | +| 10 | BorrowerOperations proxy | `setExitFeeController(address)` | `0x99994b4522483DE17F31a5bC010c5901AdD3440E` | Actions 9 and 10 are ordered so the implementation swap precedes the controller wiring inside the same atomic transaction. No action carries RBTC value. -**Core Perimeter Fee contracts** (repo [`Sovryn-perimeter`](https://github.com/DistributedCollective/Sovryn-perimeter), commit `881c74d`) — deployed and verified 2026-08-12: +**Core Perimeter Fee contracts** (repo [`Sovryn-perimeter`](https://github.com/DistributedCollective/Sovryn-perimeter)) — deployed and verified: | Contract | Address | | -------------------------------- | -------------------------------------------- | -| ExitFeeController proxy | `0x8C1abf364Bf214E41221562693BD9Fb26D6Fa563` | -| ExitFeeController implementation | `0x33EF630510Ba4d5e13Cfc3a49Ad35BEf5c9c2604` | -| ExitFeeVault proxy | `0x2ba389B021fA4A5F50cc1758EFD23Ca066d0Be08` | -| ExitFeeVault implementation | `0xab3761D0800C4310414e75Fd8b545cE094C20e26` | +| ExitFeeController proxy | `0x99994b4522483DE17F31a5bC010c5901AdD3440E` | +| ExitFeeController implementation | `0x50EC5c1C156cfA7e3007a0b0C97298E4f58a552d` | +| ExitFeeVault proxy | `0xDDE75f75ff33Aa802f2316cCAe2bE77823fc6f9B` | +| ExitFeeVault implementation | `0x8f977F4c9dCcCE1a0306A34944C0460e4445deB4` | Both implementations are source-verified on the Rootstock Blockscout explorer (solc 0.8.20, evm paris, optimizer 200 runs). The controller was deployed switched **off** and configured in the same session: the four charging surfaces registered active at 10 bps, the AMM surface registered shut, the fee receiver pointed at the vault, and both contracts' operational admin and ownership directed to the Exchequer Multisig — read back from chain after execution. +Operational admin on both contracts is the Exchequer Multisig today. -**Lending / borrowing implementations installed by Part 1** (repo [`Sovryn-smart-contracts`](https://github.com/DistributedCollective/Sovryn-smart-contracts), branch `sovryn-perimeter-fee`, commit `93997a55`, review in PR [#580](https://github.com/DistributedCollective/Sovryn-smart-contracts/pull/580)): +**Lending / borrowing implementations installed by Part 1** (repo [`Sovryn-smart-contracts`](https://github.com/DistributedCollective/Sovryn-smart-contracts), branch `sovryn-perimeter-fee`, review in PR [#580](https://github.com/DistributedCollective/Sovryn-smart-contracts/pull/580)): -| Contract | Address | -| --------------------- | ------------------------------------------------ | -| LoanTokenLogicLM | `0x6acf70d9E194a9cbe60c1283aaF30fFb252358AC` | -| LoanTokenLogicWrbtcLM | `0x96E4f6D9276A36e1c51485119406667F5eAe12ee` | -| LoanClosingsRollover | `0x2aed71b3fdD6D51f38405Fd5912624515dB46783` | -| LoanClosingsWith | `0x279D307C09E30d282aA96C3F4D216051277787f7` | -| LoanMaintenance | `0x9958b841d4af6459E4c520876F238Ec59a4Bd83D` | -| ExitFeeModule | `0x4C0eAc3f96a4fc25e5251dBA6Ec2369db0CA768B` | -| ColFeeBorrowerExitOps | `0x381fFaf5bbFa532a6E4A33E6bffCa97755C99cB3` | +| Contract | Address | +| ------------------------ | -------------------------------------------- | +| LoanTokenLogicLM | `0x593DB96E61F59F1278068742486Fc85CDBe9D872` | +| LoanTokenLogicWrbtcLM | `0x6c8f59D321560f4bEF84c99e83dd7FF31122e14f` | +| LoanClosingsRollover | `0xdB4fF0a861bF0c714B31E678c919c2B7EfD05329` | +| LoanClosingsWith | `0xa3FCC9F88De9A7f0258eda6cD8d6F7D39ef6fb8d` | +| LoanMaintenance | `0xa87Bd1eF82FA2BE049473c73eAaa97d6AB9C4399` | +| ExitFeeModule | `0x0562e396f5fF7e819c8e9CcF25DCb68e16A2672F` | +| BorrowerExitPerimeterOps | `0xe533dc6D03Ae97977Da3357A98AA94b769738AB5` | Three of the modules Part 1 registers link the stateless library `SwapsImplSovrynSwapLib`, -and they do not all link the same deployment of it. Both are needed to reproduce their -bytecode, and both are source-verified on the explorer: +and all three link the same deployment of it — needed to reproduce their bytecode, and +source-verified on the explorer: -| Registered module | Links `SwapsImplSovrynSwapLib` at | -| ----------------- | --------------------------------- | +| Registered module | Links `SwapsImplSovrynSwapLib` at | +| ---------------------- | -------------------------------------------- | | `LoanClosingsRollover` | `0xFE2bb2d345452673C4E90622147c4F515F2F4CE0` | -| `LoanMaintenance` | `0xFE2bb2d345452673C4E90622147c4F515F2F4CE0` | -| `LoanClosingsWith` | `0x47Dc479cA058B4BB7C4AD9D56EE3a029236b88A8` | - -`0x47Dc479c…` is the library deployment already live before this release, whose code the -release leaves untouched. `0xFE2bb2d…` was deployed during this release: the library's own -source is unchanged, but it imports an interface this release extends, which changes the -compiled artifact and therefore its address. The two are byte-identical apart from each -one's embedded self-address and metadata fingerprint — anyone can confirm that on-chain. - -Neither library is registered by Part 1; they are referenced only inside the linked modules' -bytecode, and both addresses are listed here so every registered module can be independently +| `LoanClosingsWith` | `0xFE2bb2d345452673C4E90622147c4F515F2F4CE0` | +| `LoanMaintenance` | `0xFE2bb2d345452673C4E90622147c4F515F2F4CE0` | + +`0xFE2bb2d…` was deployed during this release. The library's own source is unchanged from +the previous release, but it imports an interface this release extends, +which changes the compiled artifact and therefore its address; the two are byte-identical +apart from each one's embedded self-address and metadata fingerprint, which anyone can +confirm on-chain. The release links this copy rather than the older one because the +explorer verifies it as a **full** source match while the older copy matches only +partially — so a voter rebuilding a module's bytecode lands on source the explorer vouches +for exactly. + +The library is not registered by Part 1; it is referenced only inside the linked modules' +bytecode, and its address is listed here so every registered module can be independently rebuilt from source. -#### **Zero implementations installed by Part 1** (repo [`zero-contracts`](https://github.com/DistributedCollective/zero-contracts), branch `sovryn-perimeter-fee`, commit `a6ad838e`, review in PR [#10](https://github.com/DistributedCollective/zero-contracts/pull/10)): +#### **Zero implementations installed by Part 1** (repo [`zero-contracts`](https://github.com/DistributedCollective/zero-contracts), branch `sovryn-perimeter-fee`, review in PR [#10](https://github.com/DistributedCollective/zero-contracts/pull/10)): -| Contract | Address | -| ---------------------------------------------- | ------------------------------------------------ | -| BorrowerOperations implementation (fee-hooked) | `0xcD22ba4b3ED7D7297b40Dcd26d982634A0207885` | -| CollSurplusPool implementation | `0x71A605F81a66eB93Ce9b8091014da858bFD4b6dA` | +| Contract | Address | +| ---------------------------------------------- | -------------------------------------------- | +| BorrowerOperations implementation (fee-hooked) | `0x020aAb1d84E38b619A4C49f48d472c3b9187ce93` | +| CollSurplusPool implementation | `0xdd518C2aae5A83812883D4e350b88d3566792bE4` | For every module Part 1 replaces, the table below records the currently-live implementation it replaces – the rollback anchor – together with the runtime code hash of each new artifact, so a voter can bind every proposal action to both the address it installs and the address it supersedes. Anchors were read from the live protocol, beacons, and proxies on -2026-08-13; they are re-verified against the chain immediately before proposal creation, and +2026-08-25; they are re-verified against the chain immediately before proposal creation, and any drift (an unrelated upgrade landing in between) voids and re-freezes this table. -| Replaced module | Currently live (rollback anchor) | New implementation | Runtime code hash | -| --------------- | -------------------------------- | ------------------ | ----------------- | -| LoanClosingsRollover | `0xc7AEa780c8b891e2c101a9ED2f9EaCF87FFdc359` | `0x2aed71b3fdD6D51f38405Fd5912624515dB46783` | `0x40f1f693c3c81db16c6d3e002e2bd8623bb84f68dd1e3f7dc07ced9fc69813bb` | -| LoanClosingsWith | `0x47eCc9391fd6f5761B8d24139f36Ce61fF6a9819` | `0x279D307C09E30d282aA96C3F4D216051277787f7` | `0xe96d09eddecabb1cde9e45948848d882131e60d6fd9bc373d0972d2447c62621` | -| LoanMaintenance | `0x4BC462e2c8D106511D8e7985b05A52fD8b726464` | `0x9958b841d4af6459E4c520876F238Ec59a4Bd83D` | `0x530f2fc38c777f5a2c9dedf83f3480c86d178195ba2c109e61717e1a68129916` | -| iToken logic (LM) | `0xfaffde7161C58743B86a22EF268245560aC705dD` | `0x6acf70d9E194a9cbe60c1283aaF30fFb252358AC` | `0xdc1726783af8a2d9937479e4671f0aadad57be4027f7c6f6ff2653b71b0c6bba` | -| iToken logic (WrbtcLM) | `0x24B3687966C4f05e48ED5A3B9c14F56d9ad5BF6B` | `0x96E4f6D9276A36e1c51485119406667F5eAe12ee` | `0x376419bffcd439d0b4fad455fc705c931258b395fea7ec86ff54e35e5011a2ea` | -| Zero BorrowerOperations | `0xD603B4c5F7BF13a2AA510F2c625546dB4138D330` | `0xcD22ba4b3ED7D7297b40Dcd26d982634A0207885` | `0x1f96f7545bb3623376149bd9fd356f6b95d822560fe0b51c7a3254c61854bcb9` | -| Zero CollSurplusPool | `0xE9005C36452576eFA74f297906e77381E6878398` (the original implementation — never upgraded before this proposal) | `0x71A605F81a66eB93Ce9b8091014da858bFD4b6dA` | `0x5c768ef339150f191698034de26ea5c4cf012817028ef0d017bcedd2966518a2` | - -`ExitFeeModule` and `ColFeeBorrowerExitOps` are new registrations rather than replacements, so +| Replaced module | Currently live (rollback anchor) | New implementation | Runtime code hash | +| ----------------------- | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | -------------------------------------------------------------------- | +| LoanClosingsRollover | `0xc7AEa780c8b891e2c101a9ED2f9EaCF87FFdc359` | `0xdB4fF0a861bF0c714B31E678c919c2B7EfD05329` | `0xdb0abc5e825a401bd3239dfddc02612088ec1373ee29dd04a2bb3692e089c347` | +| LoanClosingsWith | `0x47eCc9391fd6f5761B8d24139f36Ce61fF6a9819` | `0xa3FCC9F88De9A7f0258eda6cD8d6F7D39ef6fb8d` | `0x34083ae377445509350becb30c2dd641ea531025eb5496c590d5cd91f6013b60` | +| LoanMaintenance | `0x4BC462e2c8D106511D8e7985b05A52fD8b726464` | `0xa87Bd1eF82FA2BE049473c73eAaa97d6AB9C4399` | `0xdb251795feb63cf2e1b952e0be33e20662e7c40f63a87d11e6a23935ce529587` | +| iToken logic (LM) | `0xfaffde7161C58743B86a22EF268245560aC705dD` | `0x593DB96E61F59F1278068742486Fc85CDBe9D872` | `0x6a08b3c8c9edbb040e4d33ee45cf5dc163e82b54b3dc72fced08cf0feb63c800` | +| iToken logic (WrbtcLM) | `0x24B3687966C4f05e48ED5A3B9c14F56d9ad5BF6B` | `0x6c8f59D321560f4bEF84c99e83dd7FF31122e14f` | `0xe09a3c2e8c1edcbb2960ff350ee36bbdb3c0a57210598ad271983fa98d674981` | +| Zero BorrowerOperations | `0xD603B4c5F7BF13a2AA510F2c625546dB4138D330` | `0x020aAb1d84E38b619A4C49f48d472c3b9187ce93` | `0xe978bc12cc95f546332aa28c029306ea2b45990307548c0b80bd740ae28e5cf1` | +| Zero CollSurplusPool | `0xE9005C36452576eFA74f297906e77381E6878398` (the original implementation — never upgraded before this proposal) | `0xdd518C2aae5A83812883D4e350b88d3566792bE4` | `0xc00a07e5f8b0c1eba5b6b33e3ed38a9b15d7867e0fe6ea8611949b3bc53caa6f` | + +`ExitFeeModule` and `BorrowerExitPerimeterOps` are new registrations rather than replacements, so they have no rollback anchor. `LoanClosingsLiquidation` is deliberately **not** redeployed: its runtime bytecode is byte-identical to the module already registered, so liquidations keep running against the same code throughout.