@@ -4,135 +4,166 @@ pragma solidity 0.8.25;
44import {Test, console} from "forge-std/Test.sol " ;
55import {CollateralManagementContract} from "../../src/CollateralManagement.sol " ;
66import {ERC1967Proxy } from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol " ;
7+ import {PauseRegistry} from "../../src/PauseRegistry.sol " ;
8+ import {IPauseRegistry} from "../../src/interfaces/IPauseRegistry.sol " ;
79
810/// @title CollateralManagement Invariant Tests
911/// @notice Tests critical invariants for the CollateralManagement contract
1012contract CollateralInvariantTest is Test {
1113 CollateralManagementContract public collateralManagement;
12-
14+
1315 address public owner;
1416 address public adder;
1517 address public slasher;
1618 address public punisher;
17-
19+
1820 // Track providers for invariant checks
1921 address [] public providers;
20-
22+
2123 // Ghost variables
2224 uint256 public ghost_totalAdded;
2325 uint256 public ghost_totalSlashed;
2426 uint256 public ghost_totalWithdrawn;
25-
27+
2628 uint256 constant MIN_COLLATERAL = 0.6 ether ;
2729 uint256 constant RESIGN_DELAY = 500 ;
2830 uint256 constant REWARD_PERCENTAGE = 1000 ;
29-
31+
3032 function setUp () public {
3133 owner = makeAddr ("owner " );
3234 adder = makeAddr ("adder " );
3335 slasher = makeAddr ("slasher " );
3436 punisher = makeAddr ("punisher " );
35-
37+
3638 vm.deal (owner, 100 ether);
3739 vm.deal (adder, 100 ether);
38-
40+
41+ // Deploy PauseRegistry first
42+ PauseRegistry prImpl = new PauseRegistry ();
43+ ERC1967Proxy prProxy = new ERC1967Proxy (
44+ address (prImpl),
45+ abi.encodeCall (prImpl.initialize, (0 , owner))
46+ );
47+ IPauseRegistry pauseRegistry = IPauseRegistry (
48+ payable (address (prProxy))
49+ );
50+
3951 // Deploy CollateralManagement
4052 CollateralManagementContract impl = new CollateralManagementContract ();
4153 bytes memory initData = abi.encodeCall (
4254 CollateralManagementContract.initialize,
43- (owner, 30 , MIN_COLLATERAL, RESIGN_DELAY, REWARD_PERCENTAGE)
55+ (
56+ owner,
57+ 30 ,
58+ MIN_COLLATERAL,
59+ RESIGN_DELAY,
60+ REWARD_PERCENTAGE,
61+ pauseRegistry
62+ )
4463 );
4564 ERC1967Proxy proxy = new ERC1967Proxy (address (impl), initData);
46- collateralManagement = CollateralManagementContract (payable (address (proxy)));
47-
65+ collateralManagement = CollateralManagementContract (
66+ payable (address (proxy))
67+ );
68+
4869 // Grant roles
4970 bytes32 adderRole = collateralManagement.COLLATERAL_ADDER ();
5071 bytes32 slasherRole = collateralManagement.COLLATERAL_SLASHER ();
51-
72+
5273 vm.startPrank (owner);
5374 collateralManagement.grantRole (adderRole, adder);
5475 collateralManagement.grantRole (slasherRole, slasher);
5576 vm.stopPrank ();
56-
77+
5778 // Target this contract for invariant testing
5879 targetContract (address (this ));
59-
80+
6081 // Exclude setUp from being called during invariant testing
6182 bytes4 [] memory selectors = new bytes4 [](2 );
6283 selectors[0 ] = this .addCollateral.selector ;
6384 selectors[1 ] = this .resignAndWithdraw.selector ;
64- targetSelector (FuzzSelector ({addr: address (this ), selectors: selectors}));
85+ targetSelector (
86+ FuzzSelector ({addr: address (this ), selectors: selectors})
87+ );
6588 }
66-
89+
6790 // ============ Handler Functions ============
68-
91+
6992 function addCollateral (uint256 providerSeed , uint256 amount ) external {
7093 amount = bound (amount, MIN_COLLATERAL, 10 ether);
7194 address provider = _getOrCreateProvider (providerSeed);
72-
95+
7396 vm.deal (adder, amount);
7497 vm.prank (adder);
7598 collateralManagement.addPegInCollateralTo {value: amount}(provider);
76-
99+
77100 ghost_totalAdded += amount;
78101 }
79-
102+
80103 function resignAndWithdraw (uint256 providerSeed ) external {
81104 if (providers.length == 0 ) return ;
82-
105+
83106 address provider = providers[providerSeed % providers.length ];
84- uint256 pegInCollateral = collateralManagement.getPegInCollateral (provider);
85-
107+ uint256 pegInCollateral = collateralManagement.getPegInCollateral (
108+ provider
109+ );
110+
86111 if (pegInCollateral == 0 ) return ;
87-
112+
88113 // Resign first
89114 vm.prank (provider);
90- try collateralManagement.resign () {} catch { return ; }
91-
115+ try collateralManagement.resign () {} catch {
116+ return ;
117+ }
118+
92119 // Advance blocks past delay
93120 vm.roll (block .number + RESIGN_DELAY + 1 );
94-
121+
95122 // Withdraw
96123 vm.prank (provider);
97124 try collateralManagement.withdrawCollateral () {
98125 ghost_totalWithdrawn += pegInCollateral;
99126 } catch {}
100127 }
101-
128+
102129 // ============ Invariant Tests ============
103-
130+
104131 /// @notice Contract balance should always be >= total collateral obligations
105132 function invariant_ContractSolvent () public view {
106133 uint256 contractBalance = address (collateralManagement).balance;
107134 uint256 totalCollateral = _calculateTotalCollateral ();
108-
135+
109136 assertGe (
110137 contractBalance,
111138 totalCollateral,
112139 "INVARIANT VIOLATED: Contract is insolvent "
113140 );
114141 }
115-
142+
116143 /// @notice Ghost accounting should match contract state (relaxed check)
117144 function invariant_GhostAccountingConsistent () public view {
118145 // If nothing has been added via our handlers, skip this check
119146 if (ghost_totalAdded == 0 ) return ;
120-
147+
121148 uint256 contractBalance = address (collateralManagement).balance;
122-
149+
123150 // Contract balance should be reasonable - not more than we added
124151 assertTrue (
125152 contractBalance <= ghost_totalAdded + 1 ether,
126153 "INVARIANT VIOLATED: Contract has more than deposited "
127154 );
128155 }
129-
156+
130157 /// @notice No provider should have negative collateral (underflow)
131158 function invariant_NoNegativeCollateral () public view {
132159 for (uint256 i = 0 ; i < providers.length ; i++ ) {
133- uint256 pegInCollateral = collateralManagement.getPegInCollateral (providers[i]);
134- uint256 pegOutCollateral = collateralManagement.getPegOutCollateral (providers[i]);
135-
160+ uint256 pegInCollateral = collateralManagement.getPegInCollateral (
161+ providers[i]
162+ );
163+ uint256 pegOutCollateral = collateralManagement.getPegOutCollateral (
164+ providers[i]
165+ );
166+
136167 // Check for underflow - values near max uint256 indicate underflow
137168 assertTrue (
138169 pegInCollateral < 1_000_000 ether,
@@ -144,28 +175,36 @@ contract CollateralInvariantTest is Test {
144175 );
145176 }
146177 }
147-
178+
148179 // ============ Helper Functions ============
149-
150- function _getOrCreateProvider (uint256 seed ) internal returns (address provider ) {
180+
181+ function _getOrCreateProvider (
182+ uint256 seed
183+ ) internal returns (address provider ) {
151184 if (providers.length > 0 && seed % 3 != 0 ) {
152185 return providers[seed % providers.length ];
153186 }
154-
155- provider = address (uint160 (uint256 (keccak256 (abi.encode (seed, providers.length )))));
187+
188+ provider = address (
189+ uint160 (uint256 (keccak256 (abi.encode (seed, providers.length ))))
190+ );
156191 providers.push (provider);
157192 vm.deal (provider, 10 ether);
158193 return provider;
159194 }
160-
195+
161196 function _calculateTotalCollateral () internal view returns (uint256 total ) {
162197 for (uint256 i = 0 ; i < providers.length ; i++ ) {
163- uint256 pegInCollateral = collateralManagement.getPegInCollateral (providers[i]);
164- uint256 pegOutCollateral = collateralManagement.getPegOutCollateral (providers[i]);
198+ uint256 pegInCollateral = collateralManagement.getPegInCollateral (
199+ providers[i]
200+ );
201+ uint256 pegOutCollateral = collateralManagement.getPegOutCollateral (
202+ providers[i]
203+ );
165204 total += pegInCollateral + pegOutCollateral;
166205 }
167206 }
168-
207+
169208 function invariant_callSummary () public view {
170209 console.log ("\n--- Collateral Invariant Summary --- " );
171210 console.log ("Providers: " , providers.length );
0 commit comments