From 1d3eba9fe43799e62ad6a491a105f734a85a7a18 Mon Sep 17 00:00:00 2001 From: Yash Saraswat Date: Wed, 15 Jul 2026 11:17:10 -0500 Subject: [PATCH] test: fix fork test post upgrade --- test/TestSetup.sol | 12 +++++++++++- test/V0MigrationFork.t.sol | 11 +++++++---- test/behaviour-tests/prelude.t.sol | 3 ++- test/fork-tests/RevertEscrowDrain.t.sol | 10 +++++++++- test/fork-tests/UpgradeStorageIntegrity.t.sol | 11 +++++++++-- test/integration-tests/Deposit.t.sol | 8 +++++++- test/integration-tests/Withdraw.t.sol | 7 ++++++- 7 files changed, 51 insertions(+), 11 deletions(-) diff --git a/test/TestSetup.sol b/test/TestSetup.sol index 92004289..b274eb32 100644 --- a/test/TestSetup.sol +++ b/test/TestSetup.sol @@ -715,6 +715,8 @@ contract TestSetup is Test, ContractCodeChecker, DepositDataGeneration { bytes32 _operatingMultisigRole = roleRegistryInstance.OPERATION_MULTISIG_ROLE(); bytes32 _operatingTimelockRole = roleRegistryInstance.OPERATION_TIMELOCK_ROLE(); bytes32 _upgradeTimelockRole = roleRegistryInstance.UPGRADE_TIMELOCK_ROLE(); + bytes32 _housekeepingRole = roleRegistryInstance.HOUSEKEEPING_OPERATIONS_ROLE(); + bytes32 _guardianRole = roleRegistryInstance.GUARDIAN_ROLE(); address _roleRegOwner = roleRegistryInstance.owner(); address _operatingTimelockAddr = deployed.OPERATING_TIMELOCK(); vm.startPrank(_roleRegOwner); @@ -741,7 +743,11 @@ contract TestSetup is Test, ContractCodeChecker, DepositDataGeneration { // routes them through OPERATION_TIMELOCK / OPERATION_MULTISIG, so we // mirror that historical access for the addresses tests prank as. // Note: HOUSEKEEPING / GUARDIAN are intentionally NOT granted here — - // tests for sweepFunds & friends rely on `admin` lacking them. + // tests for sweepFunds & friends rely on `admin` lacking them. The 26Q2 + // upgrade (mainnet block 25533308) granted both to the operating multisig, + // which is `admin` on this fork, so revoke them to restore that assumption. + roleRegistryInstance.revokeRole(_housekeepingRole, admin); + roleRegistryInstance.revokeRole(_guardianRole, admin); roleRegistryInstance.grantRole(_operatingTimelockRole, owner); roleRegistryInstance.grantRole(_operatingTimelockRole, alice); roleRegistryInstance.grantRole(_operatingTimelockRole, admin); @@ -1497,6 +1503,10 @@ contract TestSetup is Test, ContractCodeChecker, DepositDataGeneration { for (uint256 i = 0; i < eethIds.length; i++) { if (!rateLimiterInstance.limitExists(eethIds[i])) { rateLimiterInstance.createNewLimiter(eethIds[i], maxUint64, maxUint64); + } else { + rateLimiterInstance.setCapacity(eethIds[i], maxUint64); + rateLimiterInstance.setRefillRate(eethIds[i], maxUint64); + rateLimiterInstance.setRemaining(eethIds[i], maxUint64); } rateLimiterInstance.updateConsumers(eethIds[i], address(eETHInstance), true); } diff --git a/test/V0MigrationFork.t.sol b/test/V0MigrationFork.t.sol index 00a2589d..de1caf0a 100644 --- a/test/V0MigrationFork.t.sol +++ b/test/V0MigrationFork.t.sol @@ -41,11 +41,14 @@ contract V0MigrationForkTest is Test { MembershipManager mm; + /// @dev Last mainnet state before the 26Q2 security upgrade executed + /// (block 25533308, 2026-07-14). The V0 migration has since run on + /// mainnet, so this test must fork pre-upgrade state to keep + /// exercising the migration path it was written to validate. + uint256 constant PRE_UPGRADE_BLOCK = 25_526_000; + function setUp() public { - // Use the latest fork — these are pure read/migrate flows so block - // pinning is unnecessary. If a tester wants a specific block they can - // override via cheatcodes before calling test_*. - vm.selectFork(vm.createFork(vm.envString("MAINNET_RPC_URL"))); + vm.selectFork(vm.createFork(vm.envString("MAINNET_RPC_URL"), PRE_UPGRADE_BLOCK)); mm = MembershipManager(payable(MEMBERSHIP_MANAGER)); } diff --git a/test/behaviour-tests/prelude.t.sol b/test/behaviour-tests/prelude.t.sol index 2a83af18..d922aacd 100644 --- a/test/behaviour-tests/prelude.t.sol +++ b/test/behaviour-tests/prelude.t.sol @@ -151,7 +151,8 @@ contract PreludeTest is Test, ArrayTestHelper { vm.prank(roleRegistry.owner()); stakingManager.upgradeEtherFiNode(address(etherFiNodeImpl)); - vm.prank(roleRegistry.owner()); + address operatingMultisig = roleRegistry.roleHolders(roleRegistry.OPERATION_MULTISIG_ROLE())[0]; + vm.prank(operatingMultisig); auctionManager.disableWhitelist(); // permissions diff --git a/test/fork-tests/RevertEscrowDrain.t.sol b/test/fork-tests/RevertEscrowDrain.t.sol index ea750f10..d66c6891 100644 --- a/test/fork-tests/RevertEscrowDrain.t.sol +++ b/test/fork-tests/RevertEscrowDrain.t.sol @@ -35,8 +35,16 @@ interface IOwnableRead { function owner() external view returns (address); } contract RevertEscrowDrainTest is Test, Deployed { Blacklister internal blacklister; + /// @dev Last mainnet state before the 26Q2 security upgrade + escrow-drain + /// claim flush executed (2026-07-14, upgrade at block 25533308). These + /// tests validate the upgrade/migration path from live PRE-upgrade + /// state — the deployed post-upgrade impls dropped `owner()` and + /// already ran `initializeOnUpgradeV2`, so a latest-block fork can no + /// longer exercise them. + uint256 constant PRE_UPGRADE_BLOCK = 25_526_000; + function setUp() public { - vm.createSelectFork(vm.envString("MAINNET_RPC_URL")); + vm.createSelectFork(vm.envString("MAINNET_RPC_URL"), PRE_UPGRADE_BLOCK); // The new impls wire a Blacklister as an immutable; deploy a fresh one for the harness. Blacklister bImpl = new Blacklister(ROLE_REGISTRY); blacklister = Blacklister(address(new UUPSProxy(address(bImpl), abi.encodeWithSelector(Blacklister.initialize.selector)))); diff --git a/test/fork-tests/UpgradeStorageIntegrity.t.sol b/test/fork-tests/UpgradeStorageIntegrity.t.sol index ade27895..b55e8bb9 100644 --- a/test/fork-tests/UpgradeStorageIntegrity.t.sol +++ b/test/fork-tests/UpgradeStorageIntegrity.t.sol @@ -135,9 +135,16 @@ contract UpgradeStorageIntegrityTest is Test, SecurityUpgradesConstants { assertEq(a.paused, b.paused, "WRN.paused"); } + /// @dev Last mainnet state before the 26Q2 security upgrade executed + /// (block 25533308, 2026-07-14). These tests validate the upgrade path + /// from live PRE-upgrade state — the deployed post-upgrade impls + /// dropped `owner()` and already ran `initializeOnUpgradeV2`, so a + /// latest-block fork can no longer exercise them. + uint256 constant PRE_UPGRADE_BLOCK = 25_526_000; + function setUp() public { - // Latest-block fork; realistic mainnet state. - vm.createSelectFork(vm.envString("MAINNET_RPC_URL")); + // Pinned pre-upgrade fork; realistic mainnet state. + vm.createSelectFork(vm.envString("MAINNET_RPC_URL"), PRE_UPGRADE_BLOCK); // NOTE: RoleRegistry is intentionally NOT upgraded here. The currently // deployed LP/WRN/PQ impls authorize upgrades via the legacy diff --git a/test/integration-tests/Deposit.t.sol b/test/integration-tests/Deposit.t.sol index 89e5d9fa..4ecc4ef5 100644 --- a/test/integration-tests/Deposit.t.sol +++ b/test/integration-tests/Deposit.t.sol @@ -240,7 +240,13 @@ contract DepositIntegrationTest is TestSetup { stEth.transfer(address(etherFiRestakerInstance), stEthAmount); uint256 stETHAmountOfRestakerBeforeDeposit = stEth.balanceOf(address(etherFiRestakerInstance)); - vm.prank(roleRegistryInstance.owner()); + + address roleRegOwner = roleRegistryInstance.owner(); + bytes32 executorRole = roleRegistryInstance.EXECUTOR_OPERATIONS_ROLE(); + vm.prank(roleRegOwner); + roleRegistryInstance.grantRole(executorRole, roleRegOwner); + + vm.prank(roleRegOwner); uint256 shares = etherFiRestakerInstance.depositIntoStrategy(address(stEth), stEthAmount); assertGt(shares, 0); diff --git a/test/integration-tests/Withdraw.t.sol b/test/integration-tests/Withdraw.t.sol index 9263bde1..372a767b 100644 --- a/test/integration-tests/Withdraw.t.sol +++ b/test/integration-tests/Withdraw.t.sol @@ -506,7 +506,12 @@ contract WithdrawIntegrationTest is TestSetup, Deployed { uint256 restakerBalanceBefore = address(etherFiRestakerInstance).balance; assertEq(restakerBalanceBefore, amount); - vm.prank(roleRegistryInstance.owner()); + address roleRegOwner = roleRegistryInstance.owner(); + bytes32 housekeepingRole = roleRegistryInstance.HOUSEKEEPING_OPERATIONS_ROLE(); + vm.prank(roleRegOwner); + roleRegistryInstance.grantRole(housekeepingRole, roleRegOwner); + + vm.prank(roleRegOwner); etherFiRestakerInstance.withdrawEther(); assertEq(address(etherFiRestakerInstance).balance, 0);