Skip to content

Commit 8ac7420

Browse files
committed
guard: TroveManager joins the storage-layout zero-diff baseline (W9a)
The Recovery-Mode liquidation fix makes TroveManager an upgraded implementation in the Phase 2 release. It changes no state, so it is a strict zero-diff target. Baseline captured per the test-header recipe from the unmodified sovryn-perimeter-fee @ b6584a6 tree with this branch's hardhat.config.ts overlaid (storageLayout output).
1 parent 9dc28e7 commit 8ac7420

2 files changed

Lines changed: 164 additions & 3 deletions

File tree

tests-perimeter/StorageLayout.zerodiff.test.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
// per-target policy:
1414
//
1515
// ZERO_DIFF — any label/slot/offset/type difference fails (ActivePool,
16-
// CollSurplusPool: hooked but stateless).
16+
// CollSurplusPool: hooked but stateless; TroveManager: upgraded
17+
// for the Recovery-Mode liquidation fix, logic only).
1718
// APPEND_ONLY — the baseline prefix must be byte-identical AND every added
1819
// entry must occupy a slot strictly beyond the baseline's last
1920
// slot; reordering, retyping, resizing or inserting fails
@@ -35,7 +36,7 @@
3536
// 1. git worktree add <tmp> sovryn-perimeter-fee
3637
// 2. overlay this repo's hardhat.config.ts (storageLayout output) into <tmp>
3738
// 3. (cd <tmp> && npx hardhat compile --force)
38-
// 4. extract the normalized layout for the three targets and overwrite
39+
// 4. extract the normalized layout for the four targets and overwrite
3940
// tests-perimeter/baselines/storage-layout.sovryn-perimeter-fee.json (keep _meta).
4041

4142
const assert = require("assert");
@@ -55,6 +56,8 @@ const TARGETS = [
5556
{ fq: "contracts/ActivePool.sol:ActivePool", policy: ZERO_DIFF },
5657
// Gains claimCollWithFee — functions only, no state.
5758
{ fq: "contracts/CollSurplusPool.sol:CollSurplusPool", policy: ZERO_DIFF },
59+
// Upgraded for the Recovery-Mode liquidation fix (W9a): logic only, no state.
60+
{ fq: "contracts/TroveManager.sol:TroveManager", policy: ZERO_DIFF },
5861
];
5962

6063
describe("Perimeter — storage-layout upgrade safety (surplus-claim fee hook + exit-delay reroute)", () => {

tests-perimeter/baselines/storage-layout.sovryn-perimeter-fee.json

Lines changed: 159 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"_meta": {
33
"purpose": "Storage-layout zero-diff baseline for the Zero surplus-claim exit fee AND the security-perimeter delay hooks.",
44
"baseRef": "sovryn-perimeter-fee @ b6584a6",
5-
"note": "Normalized solc storageLayout (AST id suffixes after ')' stripped) for the upgradeable BorrowerOperations and CollSurplusPool proxies plus ActivePool, captured from the UNMODIFIED b6584a6 tree, before the surplus-claim fee hook and before the exit-delay hooks were applied. tests-perimeter/StorageLayout.zerodiff.test.js asserts the current tree's layout is identical \u2014 proving neither hook appends state (the controller and queue pointers live in EIP-1967 unstructured slots). Regenerate only on an intentional, reviewed layout change (see the test header).",
5+
"note": "Normalized solc storageLayout (AST id suffixes after ')' stripped) for the upgradeable BorrowerOperations and CollSurplusPool proxies plus ActivePool, captured from the UNMODIFIED b6584a6 tree, before the surplus-claim fee hook and before the exit-delay hooks were applied. tests-perimeter/StorageLayout.zerodiff.test.js asserts the current tree's layout is identical \u2014 proving neither hook appends state (the controller and queue pointers live in EIP-1967 unstructured slots). Regenerate only on an intentional, reviewed layout change (see the test header). 2026-09-07 (W9a): contracts/TroveManager.sol:TroveManager added as a ZERO_DIFF target, captured from the same b6584a6 tree, because the Recovery-Mode liquidation fix makes TroveManager an upgraded implementation in the Phase 2 release; the fix changes no state.",
66
"consumers": [
77
"tests-perimeter/StorageLayout.zerodiff.test.js",
88
"tests-perimeter/utils/storageLayout.js"
@@ -163,5 +163,163 @@
163163
"offset": 0,
164164
"type": "t_mapping(t_address,t_uint256)"
165165
}
166+
],
167+
"contracts/TroveManager.sol:TroveManager": [
168+
{
169+
"label": "activePool",
170+
"slot": "0",
171+
"offset": 0,
172+
"type": "t_contract(IActivePool)"
173+
},
174+
{
175+
"label": "defaultPool",
176+
"slot": "1",
177+
"offset": 0,
178+
"type": "t_contract(IDefaultPool)"
179+
},
180+
{
181+
"label": "priceFeed",
182+
"slot": "2",
183+
"offset": 0,
184+
"type": "t_contract(IPriceFeed)"
185+
},
186+
{
187+
"label": "liquityBaseParams",
188+
"slot": "3",
189+
"offset": 0,
190+
"type": "t_contract(ILiquityBaseParams)"
191+
},
192+
{
193+
"label": "troveManagerRedeemOps",
194+
"slot": "4",
195+
"offset": 0,
196+
"type": "t_address"
197+
},
198+
{
199+
"label": "borrowerOperationsAddress",
200+
"slot": "5",
201+
"offset": 0,
202+
"type": "t_address"
203+
},
204+
{
205+
"label": "_stabilityPool",
206+
"slot": "6",
207+
"offset": 0,
208+
"type": "t_contract(IStabilityPool)"
209+
},
210+
{
211+
"label": "gasPoolAddress",
212+
"slot": "7",
213+
"offset": 0,
214+
"type": "t_address"
215+
},
216+
{
217+
"label": "collSurplusPool",
218+
"slot": "8",
219+
"offset": 0,
220+
"type": "t_contract(ICollSurplusPool)"
221+
},
222+
{
223+
"label": "_zusdToken",
224+
"slot": "9",
225+
"offset": 0,
226+
"type": "t_contract(IZUSDToken)"
227+
},
228+
{
229+
"label": "_zeroToken",
230+
"slot": "10",
231+
"offset": 0,
232+
"type": "t_contract(IZEROToken)"
233+
},
234+
{
235+
"label": "_zeroStaking",
236+
"slot": "11",
237+
"offset": 0,
238+
"type": "t_contract(IZEROStaking)"
239+
},
240+
{
241+
"label": "feeDistributor",
242+
"slot": "12",
243+
"offset": 0,
244+
"type": "t_contract(IFeeDistributor)"
245+
},
246+
{
247+
"label": "sortedTroves",
248+
"slot": "13",
249+
"offset": 0,
250+
"type": "t_contract(ISortedTroves)"
251+
},
252+
{
253+
"label": "baseRate",
254+
"slot": "14",
255+
"offset": 0,
256+
"type": "t_uint256"
257+
},
258+
{
259+
"label": "lastFeeOperationTime",
260+
"slot": "15",
261+
"offset": 0,
262+
"type": "t_uint256"
263+
},
264+
{
265+
"label": "Troves",
266+
"slot": "16",
267+
"offset": 0,
268+
"type": "t_mapping(t_address,t_struct(Trove)_storage)"
269+
},
270+
{
271+
"label": "totalStakes",
272+
"slot": "17",
273+
"offset": 0,
274+
"type": "t_uint256"
275+
},
276+
{
277+
"label": "totalStakesSnapshot",
278+
"slot": "18",
279+
"offset": 0,
280+
"type": "t_uint256"
281+
},
282+
{
283+
"label": "totalCollateralSnapshot",
284+
"slot": "19",
285+
"offset": 0,
286+
"type": "t_uint256"
287+
},
288+
{
289+
"label": "L_ETH",
290+
"slot": "20",
291+
"offset": 0,
292+
"type": "t_uint256"
293+
},
294+
{
295+
"label": "L_ZUSDDebt",
296+
"slot": "21",
297+
"offset": 0,
298+
"type": "t_uint256"
299+
},
300+
{
301+
"label": "rewardSnapshots",
302+
"slot": "22",
303+
"offset": 0,
304+
"type": "t_mapping(t_address,t_struct(RewardSnapshot)_storage)"
305+
},
306+
{
307+
"label": "TroveOwners",
308+
"slot": "23",
309+
"offset": 0,
310+
"type": "t_array(t_address)dyn_storage"
311+
},
312+
{
313+
"label": "lastETHError_Redistribution",
314+
"slot": "24",
315+
"offset": 0,
316+
"type": "t_uint256"
317+
},
318+
{
319+
"label": "lastZUSDDebtError_Redistribution",
320+
"slot": "25",
321+
"offset": 0,
322+
"type": "t_uint256"
323+
}
166324
]
167325
}

0 commit comments

Comments
 (0)