From a1f43dc4d9dcf2cc957d93f2a4f5fe4bef2a1b23 Mon Sep 17 00:00:00 2001 From: Alex <18387287+wadealexc@users.noreply.github.com> Date: Thu, 16 Jan 2025 10:16:04 -0500 Subject: [PATCH] test: separate upgrade test functionality from main integration tests (#1031) * refactor(test): clean up random config and upgrade tests * test: move test to upgrade tests --- src/test/integration/IntegrationBase.t.sol | 26 +- src/test/integration/IntegrationChecks.t.sol | 11 - .../integration/IntegrationDeployer.t.sol | 57 ++- .../Delegate_Deposit_Queue_Complete.t.sol | 26 +- .../tests/Deposit_Delegate_Allocate.t.sol | 86 +---- ...egate_Allocate_Slash_Queue_Redeposit.t.sol | 340 ++++++++++++++++++ .../Deposit_Delegate_Queue_Complete.t.sol | 54 +-- ...Deposit_Delegate_Redelegate_Complete.t.sol | 66 +--- ...Deposit_Delegate_Undelegate_Complete.t.sol | 49 +-- .../tests/Deposit_Queue_Complete.t.sol | 22 +- ...it_Register_QueueWithdrawal_Complete.t.sol | 23 +- .../EigenPod_Slashing_Migration.t.sol | 72 ---- .../VerifyWC_StartCP_CompleteCP.t.sol | 88 ++--- .../Complete_PreSlashing_Withdrawal.t.sol | 12 +- .../upgrade/Delegate_Upgrade_Allocate.t.sol | 19 +- .../upgrade/EigenPod_Slashing_Migration.t.sol | 16 + src/test/integration/tests/upgrade/README.md | 45 +++ 17 files changed, 526 insertions(+), 486 deletions(-) create mode 100644 src/test/integration/tests/Deposit_Delegate_Allocate_Slash_Queue_Redeposit.t.sol delete mode 100644 src/test/integration/tests/eigenpod/EigenPod_Slashing_Migration.t.sol create mode 100644 src/test/integration/tests/upgrade/README.md diff --git a/src/test/integration/IntegrationBase.t.sol b/src/test/integration/IntegrationBase.t.sol index 1617c1500e..01e497bce2 100644 --- a/src/test/integration/IntegrationBase.t.sol +++ b/src/test/integration/IntegrationBase.t.sol @@ -139,31 +139,7 @@ abstract contract IntegrationBase is IntegrationDeployer { return (gweiSent, remainderSent); } - - /// @dev If we're on mainnet, upgrade contracts to slashing and migrate stakers/operators - function _upgradeEigenLayerContracts() internal { - if (forkType == MAINNET) { - require(!isUpgraded, "_upgradeEigenLayerContracts: already performed slashing upgrade"); - - emit log("_upgradeEigenLayerContracts: upgrading mainnet to slashing"); - _upgradeMainnetContracts(); - - // Unpause EigenPodManager - cheats.prank(eigenLayerPauserReg.unpauser()); - eigenPodManager.unpause(0); - - // Bump block.timestamp forward to allow verifyWC proofs for migrated pods - emit log("advancing block time to start of next epoch:"); - - beaconChain.advanceEpoch_NoRewards(); - - emit log("======"); - - isUpgraded = true; - emit log("_upgradeEigenLayerContracts: slashing upgrade complete"); - } - } - + /// @dev Choose a random subset of validators (selects AT LEAST ONE) function _choose(uint40[] memory validators) internal returns (uint40[] memory) { uint rand = _randUint({ min: 1, max: validators.length ** 2 }); diff --git a/src/test/integration/IntegrationChecks.t.sol b/src/test/integration/IntegrationChecks.t.sol index c01db4e72b..1a6ed6b81d 100644 --- a/src/test/integration/IntegrationChecks.t.sol +++ b/src/test/integration/IntegrationChecks.t.sol @@ -15,17 +15,6 @@ contract IntegrationCheckUtils is IntegrationBase { EIGENPOD CHECKS *******************************************************************************/ - function check_VerifyWC_State( - User_M2 staker, - uint40[] memory validators, - uint64 beaconBalanceGwei - ) internal { - uint beaconBalanceWei = beaconBalanceGwei * GWEI_TO_WEI; - assert_Snap_Added_Staker_DepositShares(staker, BEACONCHAIN_ETH_STRAT, beaconBalanceWei, "staker should have added deposit shares to beacon chain strat"); - assert_Snap_Added_ActiveValidatorCount(staker, validators.length, "staker should have increased active validator count"); - assert_Snap_Added_ActiveValidators(staker, validators, "validators should each be active"); - } - function check_VerifyWC_State( User staker, uint40[] memory validators, diff --git a/src/test/integration/IntegrationDeployer.t.sol b/src/test/integration/IntegrationDeployer.t.sol index 35188be93d..32a2681e1a 100644 --- a/src/test/integration/IntegrationDeployer.t.sol +++ b/src/test/integration/IntegrationDeployer.t.sol @@ -78,6 +78,23 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { // Set only once in setUp, if FORK_MAINNET env is set uint forkType; + /// @dev used to configure randomness and default user/asset types + /// + /// Tests that want alternate user/asset types can still use this modifier, + /// and then configure user/asset types individually using the methods: + /// _configAssetTypes(...) + /// _configUserTypes(...) + /// + /// (Alternatively, this modifier can be overwritten) + modifier rand(uint24 r) virtual { + _configRand({ + _randomSeed: r, + _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, + _userTypes: DEFAULT | ALT_METHODS + }); + _; + } + constructor() { address stETH_Holesky = 0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034; address stETH_Mainnet = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84; @@ -91,6 +108,10 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { tokensNotTested[osETH_Holesky] = true; tokensNotTested[osETH_Mainnet] = true; tokensNotTested[cbETH_Holesky] = true; + + // Use current contracts by default. Upgrade tests are only run with mainnet fork tests + // using the `UpgradeTest.t.sol` mixin. + isUpgraded = true; } function NAME() public view virtual override returns (string memory) { @@ -105,15 +126,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { * Note that forkIds are also created so you can make explicit fork tests using cheats.selectFork(forkId) */ function setUp() public virtual { - isUpgraded = false; - - /** - * env FOUNDRY_PROFILE=forktest forge t --mc Integration - * - * Running foundry like this will trigger the fork test profile, - * lowering fuzz runs and using a remote RPC to test against mainnet state - */ - bool forkMainnet = _hash("forktest") == _hash(cheats.envOr(string("FOUNDRY_PROFILE"), string("default"))); + bool forkMainnet = isForktest(); if (forkMainnet) { forkType = MAINNET; @@ -124,11 +137,19 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { } } + /** + * env FOUNDRY_PROFILE=forktest forge t --mc Integration + * + * Running foundry like this will trigger the fork test profile, + * lowering fuzz runs and using a remote RPC to test against mainnet state + */ + function isForktest() public view returns (bool) { + return _hash("forktest") == _hash(cheats.envOr(string("FOUNDRY_PROFILE"), string("default"))); + } + /// Deploy EigenLayer locally function _setUpLocal() public virtual { console.log("Setting up `%s` integration tests:", "LOCAL".yellow().bold()); - // Bypass upgrade tests when running locally - isUpgraded = true; // Deploy ProxyAdmin eigenLayerProxyAdmin = new ProxyAdmin(); @@ -209,7 +230,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { allStrats.push(strategy); allTokens.push(strategy.underlyingToken()); } - + // Create time machine and mock beacon chain BEACON_GENESIS_TIME = GENESIS_TIME_MAINNET; timeMachine = new TimeMachine(); @@ -230,7 +251,6 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { } - /// Deploy current implementation contracts and upgrade existing proxies function _upgradeMainnetContracts() public virtual { cheats.startPrank(address(executorMultisig)); @@ -473,10 +493,17 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser { random = _hash(_randomSeed); // Convert flag bitmaps to bytes of set bits for easy use with _randUint - assetTypes = _bitmapToBytes(_assetTypes); - userTypes = _bitmapToBytes(_userTypes); + _configAssetTypes(_assetTypes); + _configUserTypes(_userTypes); + } + function _configAssetTypes(uint _assetTypes) internal { + assetTypes = _bitmapToBytes(_assetTypes); assertTrue(assetTypes.length != 0, "_configRand: no asset types selected"); + } + + function _configUserTypes(uint _userTypes) internal { + userTypes = _bitmapToBytes(_userTypes); assertTrue(userTypes.length != 0, "_configRand: no user types selected"); } diff --git a/src/test/integration/tests/Delegate_Deposit_Queue_Complete.t.sol b/src/test/integration/tests/Delegate_Deposit_Queue_Complete.t.sol index 0ef86e4b04..ad4fe205eb 100644 --- a/src/test/integration/tests/Delegate_Deposit_Queue_Complete.t.sol +++ b/src/test/integration/tests/Delegate_Deposit_Queue_Complete.t.sol @@ -5,13 +5,8 @@ import "src/test/integration/IntegrationChecks.t.sol"; import "src/test/integration/users/User.t.sol"; contract Integration_Delegate_Deposit_Queue_Complete is IntegrationCheckUtils { - function testFuzz_delegate_deposit_queue_completeAsShares(uint24 _random) public { - // Configure the random parameters for the test - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); + + function testFuzz_delegate_deposit_queue_completeAsShares(uint24 _random) public rand(_random) { // Create a staker and an operator with a nonzero balance and corresponding strategies (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); (User operator, ,) = _newRandomOperator(); @@ -33,9 +28,6 @@ contract Integration_Delegate_Deposit_Queue_Complete is IntegrationCheckUtils { bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawals, withdrawalRoots); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); - // 4. Complete Queued Withdrawal _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; i++) { @@ -44,14 +36,7 @@ contract Integration_Delegate_Deposit_Queue_Complete is IntegrationCheckUtils { } } - function testFuzz_delegate_deposit_queue_completeAsTokens(uint24 _random) public { - // Configure the random parameters for the test - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_delegate_deposit_queue_completeAsTokens(uint24 _random) public rand(_random) { // Create a staker and an operator with a nonzero balance and corresponding strategies (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); (User operator, ,) = _newRandomOperator(); @@ -63,6 +48,7 @@ contract Integration_Delegate_Deposit_Queue_Complete is IntegrationCheckUtils { // 2. Deposit into strategy staker.depositIntoEigenlayer(strategies, tokenBalances); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); // Check that the deposit increased operator shares the staker is delegated to check_Deposit_State(staker, strategies, shares); @@ -73,13 +59,9 @@ contract Integration_Delegate_Deposit_Queue_Complete is IntegrationCheckUtils { bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawals, withdrawalRoots); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); - // 4. Complete Queued Withdrawal _rollBlocksForCompleteWithdrawals(withdrawals); for (uint i = 0; i < withdrawals.length; i++) { - uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]); check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], strategies, shares, tokens, expectedTokens); } diff --git a/src/test/integration/tests/Deposit_Delegate_Allocate.t.sol b/src/test/integration/tests/Deposit_Delegate_Allocate.t.sol index 48cc93ff63..c55d8eb7af 100644 --- a/src/test/integration/tests/Deposit_Delegate_Allocate.t.sol +++ b/src/test/integration/tests/Deposit_Delegate_Allocate.t.sol @@ -4,20 +4,8 @@ pragma solidity ^0.8.27; import "src/test/integration/IntegrationChecks.t.sol"; import "src/test/integration/users/User.t.sol"; -// TODO: move randomness from tests - contract Integration_Deposit_Delegate_Allocate is IntegrationCheckUtils { - function testFuzz_deposit_delegate_allocate( - uint24 _random - ) public { - // Configure the random parameters for the test - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - _upgradeEigenLayerContracts(); // Upgrade contracts if forkType is not local - + function testFuzz_deposit_delegate_allocate(uint24 _random) public rand(_random) { (User staker, IStrategy[] memory strategies, uint256[] memory tokenBalances) = _newRandomStaker(); (User operator,,) = _newRandomOperator(); (AVS avs,) = _newRandomAVS(); @@ -44,54 +32,9 @@ contract Integration_Deposit_Delegate_Allocate is IntegrationCheckUtils { ); } - function testFuzz_deposit_delegate_upgrade_allocate( - uint24 _random - ) public { - // Configure the random parameters for the test - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - - (User staker, IStrategy[] memory strategies, uint256[] memory tokenBalances) = _newRandomStaker(); - (User operator,,) = _newRandomOperator(); - - // 1. Deposit Into Strategies - staker.depositIntoEigenlayer(strategies, tokenBalances); - - // 2. Delegate to an operator - staker.delegateTo(operator); - - _upgradeEigenLayerContracts(); // Upgrade contracts if forkType is not local - (AVS avs,) = _newRandomAVS(); - - // 3. Set allocation delay for operator - operator.setAllocationDelay(1); - rollForward({blocks: ALLOCATION_CONFIGURATION_DELAY}); - - // 4. Create an operator set and register an operator. - OperatorSet memory operatorSet = avs.createOperatorSet(strategies); - operator.registerForOperatorSet(operatorSet); - - // 5. Allocate to operator set. - IAllocationManagerTypes.AllocateParams memory allocateParams = - operator.modifyAllocations(operatorSet, _randMagnitudes({sum: 1 ether, len: strategies.length})); - assert_Snap_Allocations_Modified( - operator, allocateParams, false, "operator allocations should be updated before delay" - ); - _rollBlocksForCompleteAllocation(operator, operatorSet, strategies); - assert_Snap_Allocations_Modified( - operator, allocateParams, true, "operator allocations should be updated after delay" - ); - } - function testFuzz_deposit_delegate_allocate_slash_undelegate_completeAsTokens( uint24 _random - ) public { - _configRand({_randomSeed: _random, _assetTypes: HOLDS_ALL, _userTypes: DEFAULT}); - _upgradeEigenLayerContracts(); // Upgrade contracts if forkType is not local - + ) public rand(_random) { (User staker, IStrategy[] memory strategies, uint256[] memory tokenBalances) = _newRandomStaker(); (User operator,,) = _newRandomOperator(); (AVS avs,) = _newRandomAVS(); @@ -155,10 +98,7 @@ contract Integration_Deposit_Delegate_Allocate is IntegrationCheckUtils { function testFuzz_deposit_delegate_allocate_slash_undelegate_completeAsShares( uint24 _random - ) public { - _configRand({_randomSeed: _random, _assetTypes: HOLDS_ALL, _userTypes: DEFAULT}); - _upgradeEigenLayerContracts(); // Upgrade contracts if forkType is not local - + ) public rand(_random) { (User staker, IStrategy[] memory strategies, uint256[] memory tokenBalances) = _newRandomStaker(); (User operator,,) = _newRandomOperator(); (AVS avs,) = _newRandomAVS(); @@ -218,10 +158,7 @@ contract Integration_Deposit_Delegate_Allocate is IntegrationCheckUtils { function testFuzz_deposit_delegate_allocate_queue_slash_completeAsTokens( uint24 _random - ) public { - _configRand({_randomSeed: _random, _assetTypes: HOLDS_ALL, _userTypes: DEFAULT}); - _upgradeEigenLayerContracts(); // Upgrade contracts if forkType is not local - + ) public rand(_random) { (User staker, IStrategy[] memory strategies, uint256[] memory tokenBalances) = _newRandomStaker(); (User operator,,) = _newRandomOperator(); (AVS avs,) = _newRandomAVS(); @@ -287,10 +224,7 @@ contract Integration_Deposit_Delegate_Allocate is IntegrationCheckUtils { function testFuzz_deposit_delegate_allocate_queue_slash_completeAsShares( uint24 _random - ) public { - _configRand({_randomSeed: _random, _assetTypes: HOLDS_ALL, _userTypes: DEFAULT}); - _upgradeEigenLayerContracts(); // Upgrade contracts if forkType is not local - + ) public rand(_random) { (User staker, IStrategy[] memory strategies, uint256[] memory tokenBalances) = _newRandomStaker(); (User operator,,) = _newRandomOperator(); (AVS avs,) = _newRandomAVS(); @@ -348,10 +282,7 @@ contract Integration_Deposit_Delegate_Allocate is IntegrationCheckUtils { function testFuzz_deposit_delegate_allocate_deallocate_slash_queue_completeAsTokens( uint24 _random - ) public { - _configRand({_randomSeed: _random, _assetTypes: HOLDS_ALL, _userTypes: DEFAULT}); - _upgradeEigenLayerContracts(); // Upgrade contracts if forkType is not local - + ) public rand(_random) { (User staker, IStrategy[] memory strategies, uint256[] memory tokenBalances) = _newRandomStaker(); (User operator,,) = _newRandomOperator(); (AVS avs,) = _newRandomAVS(); @@ -421,10 +352,7 @@ contract Integration_Deposit_Delegate_Allocate is IntegrationCheckUtils { function testFuzz_deposit_delegate_allocate_deregister_slash( uint24 _random - ) public { - _configRand({_randomSeed: _random, _assetTypes: HOLDS_ALL, _userTypes: DEFAULT}); - _upgradeEigenLayerContracts(); // Upgrade contracts if forkType is not local - + ) public rand(_random) { (User staker, IStrategy[] memory strategies, uint256[] memory tokenBalances) = _newRandomStaker(); (User operator,,) = _newRandomOperator(); (AVS avs,) = _newRandomAVS(); diff --git a/src/test/integration/tests/Deposit_Delegate_Allocate_Slash_Queue_Redeposit.t.sol b/src/test/integration/tests/Deposit_Delegate_Allocate_Slash_Queue_Redeposit.t.sol new file mode 100644 index 0000000000..3ea423dfc8 --- /dev/null +++ b/src/test/integration/tests/Deposit_Delegate_Allocate_Slash_Queue_Redeposit.t.sol @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import "src/test/integration/IntegrationChecks.t.sol"; +import "src/test/integration/users/User.t.sol"; +import {console} from "forge-std/console.sol"; + +contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is IntegrationCheckUtils, IDelegationManagerTypes { + + // TODO: Partial deposits don't work when beacon chain eth balance is initialized to < 64 ETH, need to write _newRandomStaker variant that ensures beacon chain ETH balance + // greater than or equal to 64 + modifier rand(uint24 r) override { + _configRand({ + _randomSeed: r, + _assetTypes: HOLDS_LST, + _userTypes: DEFAULT + }); + _; + } + + function testFuzz_deposit_delegate_allocate_fullSlash_queue_complete_redeposit( + uint24 _random + ) public rand(_random) { + (User staker, IStrategy[] memory strategies, uint256[] memory tokenBalances) = _newRandomStaker(); + (User operator,,) = _newRandomOperator(); + (AVS avs,) = _newRandomAVS(); + + uint256[] memory tokensToDeposit = new uint256[](tokenBalances.length); + uint256[] memory numTokensRemaining = new uint256[](tokenBalances.length); + for (uint256 i = 0; i < tokenBalances.length; i++) { + tokensToDeposit[i] = tokenBalances[i]/2; + numTokensRemaining[i] = tokenBalances[i] - tokensToDeposit[i]; + } + + uint256[] memory shares = _calculateExpectedShares(strategies, tokensToDeposit); + + // 1. Deposit Into Strategies + staker.depositIntoEigenlayer(strategies, tokensToDeposit); + check_Deposit_State_PartialDeposit(staker, strategies, shares, numTokensRemaining); + + // 2. Delegate to operator + staker.delegateTo(operator); + check_Delegation_State(staker, operator, strategies, shares); + + // Create operator set and register operator + OperatorSet memory operatorSet = avs.createOperatorSet(strategies); + operator.registerForOperatorSet(operatorSet); + + // 3. Allocate to operator set + IAllocationManagerTypes.AllocateParams memory allocateParams = + operator.modifyAllocations(operatorSet, _maxMagnitudes(operatorSet, operator)); + + assert_Snap_Allocations_Modified( + operator, + allocateParams, + false, + "operator allocations should be updated before delay" + ); + + _rollBlocksForCompleteAllocation(operator, operatorSet, strategies); + + assert_Snap_Allocations_Modified( + operator, + allocateParams, + true, + "operator allocations should be updated after delay" + ); + + // 4. Fully slash operator + IAllocationManagerTypes.SlashingParams memory slashingParams; + { + (IStrategy[] memory strategiesToSlash, uint256[] memory wadsToSlash) = + _strategiesAndWadsForFullSlash(operatorSet); + + slashingParams = avs.slashOperator(operator, operatorSet.id, strategiesToSlash, wadsToSlash); + assert_Snap_Allocations_Slashed(slashingParams, operatorSet, true, "operator allocations should be slashed"); + assert_Snap_Unchanged_StakerDepositShares(staker, "staker deposit shares should be unchanged after slashing"); + assert_Snap_StakerWithdrawableShares_AfterSlash(staker, allocateParams, slashingParams, "staker deposit shares should be slashed"); + } + + // 5. Undelegate from an operator + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); + bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + + // 6. Complete withdrawal + _rollBlocksForCompleteWithdrawals(withdrawals); + for (uint256 i = 0; i < withdrawals.length; ++i) { + uint256[] memory expectedTokens = + _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State_AfterSlash(staker, operator, withdrawals[i], allocateParams, slashingParams, expectedTokens); + } + + // 7. Redeposit + shares = _calculateExpectedShares(strategies, numTokensRemaining); + staker.depositIntoEigenlayer(strategies, numTokensRemaining); + check_Deposit_State(staker, strategies, shares); + + // Final state checks + assert_HasExpectedShares(staker, strategies, shares, "staker should have expected shares after redeposit"); + assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); + } + + function testFuzz_deposit_delegate_allocate_queue_fullSlash_complete_redeposit( + uint24 _random + ) public rand(_random) { + (User staker, IStrategy[] memory strategies, uint256[] memory tokenBalances) = _newRandomStaker(); + (User operator,,) = _newRandomOperator(); + (AVS avs,) = _newRandomAVS(); + + uint256[] memory tokensToDeposit = new uint256[](tokenBalances.length); + uint256[] memory numTokensRemaining = new uint256[](tokenBalances.length); + for (uint256 i = 0; i < tokenBalances.length; i++) { + tokensToDeposit[i] = tokenBalances[i]/2; + numTokensRemaining[i] = tokenBalances[i] - tokensToDeposit[i]; + } + + uint256[] memory shares = _calculateExpectedShares(strategies, tokensToDeposit); + + // 1. Deposit Into Strategies + staker.depositIntoEigenlayer(strategies, tokensToDeposit); + check_Deposit_State_PartialDeposit(staker, strategies, shares, numTokensRemaining); + + // 2. Delegate to operator + staker.delegateTo(operator); + check_Delegation_State(staker, operator, strategies, shares); + + // Create operator set and register operator + OperatorSet memory operatorSet = avs.createOperatorSet(strategies); + operator.registerForOperatorSet(operatorSet); + + // 3. Allocate to operator set + IAllocationManagerTypes.AllocateParams memory allocateParams = + operator.modifyAllocations(operatorSet, _maxMagnitudes(operatorSet, operator)); + + assert_Snap_Allocations_Modified( + operator, + allocateParams, + false, + "operator allocations should be updated before delay" + ); + + _rollBlocksForCompleteAllocation(operator, operatorSet, strategies); + + assert_Snap_Allocations_Modified( + operator, + allocateParams, + true, + "operator allocations should be updated after delay" + ); + + // 4. Undelegate from an operator + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); + bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + + // 5. Fully slash operator + IAllocationManagerTypes.SlashingParams memory slashingParams; + { + (IStrategy[] memory strategiesToSlash, uint256[] memory wadsToSlash) = + _strategiesAndWadsForFullSlash(operatorSet); + + slashingParams = avs.slashOperator(operator, operatorSet.id, strategiesToSlash, wadsToSlash); + assert_Snap_Allocations_Slashed(slashingParams, operatorSet, true, "operator allocations should be slashed"); + assert_Snap_Unchanged_StakerDepositShares(staker, "staker deposit shares should be unchanged after slashing"); + assert_Snap_StakerWithdrawableShares_AfterSlash(staker, allocateParams, slashingParams, "staker deposit shares should be slashed"); + } + + // 6. Complete withdrawal + _rollBlocksForCompleteWithdrawals(withdrawals); + for (uint256 i = 0; i < withdrawals.length; ++i) { + uint256[] memory expectedTokens = + _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State_AfterSlash(staker, operator, withdrawals[i], allocateParams, slashingParams, expectedTokens); + } + + // 7. Redeposit + shares = _calculateExpectedShares(strategies, numTokensRemaining); + staker.depositIntoEigenlayer(strategies, numTokensRemaining); + check_Deposit_State(staker, strategies, shares); + + // Final state checks + assert_HasExpectedShares(staker, strategies, shares, "staker should have expected shares after redeposit"); + assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); + } + + function testFuzz_deposit_delegate_allocateMultSets_fullSlash_queue_complete_redeposit( + uint24 _random + ) public rand(_random) { + (User staker, IStrategy[] memory strategies, uint256[] memory tokenBalances) = _newRandomStaker(); + (User operator,,) = _newRandomOperator(); + (AVS avs,) = _newRandomAVS(); + OperatorSet memory operatorSet; + + uint256[] memory tokensToDeposit = new uint256[](tokenBalances.length); + uint256[] memory numTokensRemaining = new uint256[](tokenBalances.length); + for (uint256 i = 0; i < tokenBalances.length; i++) { + tokensToDeposit[i] = tokenBalances[i]/2; + numTokensRemaining[i] = tokenBalances[i] - tokensToDeposit[i]; + } + + uint256[] memory shares = _calculateExpectedShares(strategies, tokensToDeposit); + + // 1. Deposit Into Strategies + staker.depositIntoEigenlayer(strategies, tokensToDeposit); + check_Deposit_State_PartialDeposit(staker, strategies, shares, numTokensRemaining); + + // 2. Delegate to operator + staker.delegateTo(operator); + check_Delegation_State(staker, operator, strategies, shares); + + // Create operator sets and register operator + { + uint numOpSets = _randUint({min: 2, max: 4}); + OperatorSet[] memory operatorSets = new OperatorSet[](numOpSets); + for (uint i = 0; i < numOpSets; i++){ + operatorSets[i] = avs.createOperatorSet(strategies); + } + operatorSet = operatorSets[_randUint({min: 0, max: numOpSets-1})]; + } + + operator.registerForOperatorSet(operatorSet); + + // 3. Allocate to operator set + IAllocationManagerTypes.AllocateParams memory allocateParams = + operator.modifyAllocations(operatorSet, _maxMagnitudes(operatorSet, operator)); + + assert_Snap_Allocations_Modified( + operator, + allocateParams, + false, + "operator allocations should be updated before delay" + ); + + _rollBlocksForCompleteAllocation(operator, operatorSet, strategies); + + assert_Snap_Allocations_Modified( + operator, + allocateParams, + true, + "operator allocations should be updated after delay" + ); + + // 4. Fully slash operator + IAllocationManagerTypes.SlashingParams memory slashingParams; + { + (IStrategy[] memory strategiesToSlash, uint256[] memory wadsToSlash) = + _strategiesAndWadsForFullSlash(operatorSet); + + slashingParams = avs.slashOperator(operator, operatorSet.id, strategiesToSlash, wadsToSlash); + assert_Snap_Allocations_Slashed(slashingParams, operatorSet, true, "operator allocations should be slashed"); + assert_Snap_Unchanged_StakerDepositShares(staker, "staker deposit shares should be unchanged after slashing"); + assert_Snap_StakerWithdrawableShares_AfterSlash(staker, allocateParams, slashingParams, "staker deposit shares should be slashed"); + } + + // 5. Undelegate from an operator + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); + bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + + // 6. Complete withdrawal + _rollBlocksForCompleteWithdrawals(withdrawals); + for (uint256 i = 0; i < withdrawals.length; ++i) { + uint256[] memory expectedTokens = + _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares); + staker.completeWithdrawalAsTokens(withdrawals[i]); + check_Withdrawal_AsTokens_State_AfterSlash(staker, operator, withdrawals[i], allocateParams, slashingParams, expectedTokens); + } + + // 7. Redeposit + shares = _calculateExpectedShares(strategies, numTokensRemaining); + staker.depositIntoEigenlayer(strategies, numTokensRemaining); + check_Deposit_State(staker, strategies, shares); + + // Final state checks + assert_HasExpectedShares(staker, strategies, shares, "staker should have expected shares after redeposit"); + assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); + } + + function testFuzz_deposit_delegate_allocate_fullSlash_undelegate_completeAsShares( + uint24 _random + ) public rand(_random) { + _configAssetTypes(HOLDS_ALL); + + (User staker, IStrategy[] memory strategies, uint256[] memory tokenBalances) = _newRandomStaker(); + (User operator,,) = _newRandomOperator(); + (AVS avs,) = _newRandomAVS(); + + + // 1. Deposit Into Strategies + staker.depositIntoEigenlayer(strategies, tokenBalances); + uint256[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + // TODO - post-deposit and post-delegate checks? + + // 2. Delegate to an operator + staker.delegateTo(operator); + + // Create an operator set and register an operator. + OperatorSet memory operatorSet = avs.createOperatorSet(strategies); + operator.registerForOperatorSet(operatorSet); + + // 3. Allocate to operator set. + IAllocationManagerTypes.AllocateParams memory allocateParams = + operator.modifyAllocations(operatorSet, _maxMagnitudes(operatorSet, operator)); + assert_Snap_Allocations_Modified( + operator, allocateParams, false, "operator allocations should be updated before delay" + ); + _rollBlocksForCompleteAllocation(operator, operatorSet, strategies); + assert_Snap_Allocations_Modified( + operator, allocateParams, true, "operator allocations should be updated after delay" + ); + + // 4. Fully slash random proper subset of operators strategies + IAllocationManagerTypes.SlashingParams memory slashingParams; + { + (IStrategy[] memory strategiesToSlash, uint256[] memory wadsToSlash) = + _strategiesAndWadsForRandFullSlash(operatorSet); + slashingParams = avs.slashOperator(operator, operatorSet.id, strategiesToSlash, wadsToSlash); + assert_Snap_Allocations_Slashed(slashingParams, operatorSet, true, "operator allocations should be slashed"); + assert_Snap_Unchanged_StakerDepositShares(staker, "staker deposit shares should be unchanged after slashing"); + assert_Snap_StakerWithdrawableShares_AfterSlash(staker, allocateParams, slashingParams, "staker deposit shares should be slashed"); + } + + // 5. Undelegate from an operator + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate(); + bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals); + + // 6. Complete withdrawal as shares + // Fast forward to when we can complete the withdrawal + _rollBlocksForCompleteWithdrawals(withdrawals); + + for (uint256 i = 0; i < withdrawals.length; ++i) { + staker.completeWithdrawalAsShares(withdrawals[i]); + check_Withdrawal_AsShares_State_AfterSlash(staker, operator, withdrawals[i], allocateParams, slashingParams); + } + + // Check final state: + assert_HasNoUnderlyingTokenBalance(staker, strategies, "staker not have any underlying tokens"); + assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); + } +} \ No newline at end of file diff --git a/src/test/integration/tests/Deposit_Delegate_Queue_Complete.t.sol b/src/test/integration/tests/Deposit_Delegate_Queue_Complete.t.sol index 8c2c4e086c..c1184a8d46 100644 --- a/src/test/integration/tests/Deposit_Delegate_Queue_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Delegate_Queue_Complete.t.sol @@ -16,14 +16,7 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { /// 2. delegates to an operator /// 3. queues a withdrawal for a ALL shares /// 4. completes the queued withdrawal as tokens - function testFuzz_deposit_delegate_queue_completeAsTokens(uint24 _random) public { - // When new Users are created, they will choose a random configuration from these params: - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_delegate_queue_completeAsTokens(uint24 _random) public rand(_random) { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random subset of valid strategies (StrategyManager and/or EigenPodManager) @@ -35,8 +28,6 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { uint[] memory tokenBalances ) = _newRandomStaker(); (User operator, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); @@ -78,14 +69,7 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { /// 2. delegates to an operator /// 3. queues a withdrawal for a ALL shares /// 4. completes the queued withdrawal as shares - function testFuzz_deposit_delegate_queue_completeAsShares(uint24 _random) public { - // When new Users are created, they will choose a random configuration from these params: - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_delegate_queue_completeAsShares(uint24 _random) public rand(_random) { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random subset of valid strategies (StrategyManager and/or EigenPodManager) @@ -97,8 +81,6 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { uint[] memory tokenBalances ) = _newRandomStaker(); (User operator, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); @@ -143,14 +125,7 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { /// 2. delegates to an operator /// 3. queues a withdrawal for a random subset of shares /// 4. completes the queued withdrawal as tokens - function testFuzz_deposit_delegate_queueRand_completeAsTokens(uint24 _random) public { - // When new Users are created, they will choose a random configuration from these params: - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_delegate_queueRand_completeAsTokens(uint24 _random) public rand(_random) { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random subset of valid strategies (StrategyManager and/or EigenPodManager) @@ -162,8 +137,6 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { uint[] memory tokenBalances ) = _newRandomStaker(); (User operator, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); @@ -208,14 +181,7 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { /// 2. delegates to an operator /// 3. queues a withdrawal for a random subset of shares /// 4. completes the queued withdrawal as shares - function testFuzz_deposit_delegate_queueRand_completeAsShares(uint24 _random) public { - // When new Users are created, they will choose a random configuration from these params: - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_delegate_queueRand_completeAsShares(uint24 _random) public rand(_random) { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random subset of valid strategies (StrategyManager and/or EigenPodManager) @@ -227,8 +193,6 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { uint[] memory tokenBalances ) = _newRandomStaker(); (User operator, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); @@ -280,12 +244,8 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { /// 2. delegates to an operator /// /// ... we check that the final step fails - function testFuzz_deposit_delegate_revert_alreadyDelegated(uint24 _random) public { - _configRand({ - _randomSeed: _random, - _assetTypes: NO_ASSETS | HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); + function testFuzz_deposit_delegate_revert_alreadyDelegated(uint24 _random) public rand(_random) { + _configAssetTypes(NO_ASSETS | HOLDS_LST | HOLDS_ETH | HOLDS_ALL); /// 0. Create a staker and operator ( @@ -294,8 +254,6 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils { uint[] memory tokenBalances ) = _newRandomStaker(); (User operator, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); diff --git a/src/test/integration/tests/Deposit_Delegate_Redelegate_Complete.t.sol b/src/test/integration/tests/Deposit_Delegate_Redelegate_Complete.t.sol index 7825645917..9936fce413 100644 --- a/src/test/integration/tests/Deposit_Delegate_Redelegate_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Delegate_Redelegate_Complete.t.sol @@ -13,14 +13,7 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti /// 5. delegate to a new operator /// 5. queueWithdrawal /// 7. complete their queued withdrawal as tokens - function testFuzz_deposit_delegate_reDelegate_completeAsTokens(uint24 _random) public { - // When new Users are created, they will choose a random configuration from these params: - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_delegate_reDelegate_completeAsTokens(uint24 _random) public rand(_random) { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random number of strategies @@ -34,8 +27,6 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti ) = _newRandomStaker(); (User operator1, ,) = _newRandomOperator(); (User operator2, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); @@ -85,14 +76,7 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti } } - function testFuzz_deposit_delegate_reDelegate_completeAsShares(uint24 _random) public { - // When new Users are created, they will choose a random configuration from these params: - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_delegate_reDelegate_completeAsShares(uint24 _random) public rand(_random) { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random number of strategies @@ -106,8 +90,6 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti ) = _newRandomStaker(); (User operator1, ,) = _newRandomOperator(); (User operator2, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); @@ -170,13 +152,8 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti ); } - function testFuzz_deposit_delegate_reDelegate_depositAfterRedelegate(uint24 _random) public { - // When new Users are created, they will choose a random configuration from these params: - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST, // not holding ETH since we can only deposit 32 ETH multiples - _userTypes: DEFAULT | ALT_METHODS - }); + function testFuzz_deposit_delegate_reDelegate_depositAfterRedelegate(uint24 _random) public rand(_random) { + _configAssetTypes(HOLDS_LST); // not holding ETH since we can only deposit 32 ETH multiples /// 0. Create an operator and a staker with: // - some nonzero underlying token balances @@ -191,8 +168,6 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti ) = _newRandomStaker(); (User operator1, ,) = _newRandomOperator(); (User operator2, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); @@ -262,13 +237,8 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti } } - function testFuzz_deposit_delegate_reDelegate_depositBeforeRedelegate(uint24 _random) public { - // When new Users are created, they will choose a random configuration from these params: - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST, // not holding ETH since we can only deposit 32 ETH multiples - _userTypes: DEFAULT | ALT_METHODS - }); + function testFuzz_deposit_delegate_reDelegate_depositBeforeRedelegate(uint24 _random) public rand(_random) { + _configAssetTypes(HOLDS_LST); // not holding ETH since we can only deposit 32 ETH multiples /// 0. Create an operator and a staker with: // - some nonzero underlying token balances @@ -283,8 +253,6 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti ) = _newRandomStaker(); (User operator1, ,) = _newRandomOperator(); (User operator2, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); @@ -354,14 +322,7 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti } } - function testFuzz_deposit_delegate_undelegate_withdrawAsTokens_reDelegate_completeAsTokens(uint24 _random) public { - // When new Users are created, they will choose a random configuration from these params: - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_delegate_undelegate_withdrawAsTokens_reDelegate_completeAsTokens(uint24 _random) public rand(_random) { /// 0. Create operators and a staker ( User staker, @@ -370,8 +331,6 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti ) = _newRandomStaker(); (User operator1, ,) = _newRandomOperator(); (User operator2, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); @@ -428,14 +387,7 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti } } - function testFuzz_deposit_delegate_undelegate_withdrawAsTokens_reDelegate_completeAsShares(uint24 _random) public { - // When new Users are created, they will choose a random configuration from these params: - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_delegate_undelegate_withdrawAsTokens_reDelegate_completeAsShares(uint24 _random) public rand(_random) { /// 0. Create operators and a staker ( User staker, @@ -444,8 +396,6 @@ contract Integration_Deposit_Delegate_Redelegate_Complete is IntegrationCheckUti ) = _newRandomStaker(); (User operator1, ,) = _newRandomOperator(); (User operator2, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); diff --git a/src/test/integration/tests/Deposit_Delegate_Undelegate_Complete.t.sol b/src/test/integration/tests/Deposit_Delegate_Undelegate_Complete.t.sol index ab157f0ced..41b61cff31 100644 --- a/src/test/integration/tests/Deposit_Delegate_Undelegate_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Delegate_Undelegate_Complete.t.sol @@ -10,14 +10,7 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti /// 2. delegate to an operator /// 3. undelegates from the operator /// 4. complete their queued withdrawal as tokens - function testFuzz_deposit_undelegate_completeAsTokens(uint24 _random) public { - // When new Users are created, they will choose a random configuration from these params: - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_undelegate_completeAsTokens(uint24 _random) public rand(_random) { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random number of strategies @@ -30,8 +23,6 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti uint[] memory tokenBalances ) = _newRandomStaker(); (User operator, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); @@ -73,14 +64,7 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti /// 2. delegate to an operator /// 3. undelegates from the operator /// 4. complete their queued withdrawal as shares - function testFuzz_deposit_undelegate_completeAsShares(uint24 _random) public { - // When new Users are created, they will choose a random configuration from these params: - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_undelegate_completeAsShares(uint24 _random) public rand(_random) { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random number of strategies @@ -93,8 +77,6 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti uint[] memory tokenBalances ) = _newRandomStaker(); (User operator, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); @@ -129,14 +111,7 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); } - function testFuzz_deposit_delegate_forceUndelegate_completeAsTokens(uint24 _random) public { - // When new Users are created, they will choose a random configuration from these params: - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_delegate_forceUndelegate_completeAsTokens(uint24 _random) public rand(_random) { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random number of strategies @@ -149,8 +124,6 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti uint[] memory tokenBalances ) = _newRandomStaker(); (User operator, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); @@ -186,14 +159,7 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending"); } - function testFuzz_deposit_delegate_forceUndelegate_completeAsShares(uint24 _random) public { - // When new Users are created, they will choose a random configuration from these params: - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_delegate_forceUndelegate_completeAsShares(uint24 _random) public rand(_random) { /// 0. Create an operator and a staker with: // - some nonzero underlying token balances // - corresponding to a random number of strategies @@ -206,8 +172,6 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti uint[] memory tokenBalances ) = _newRandomStaker(); (User operator, ,) = _newRandomOperator(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); @@ -243,9 +207,8 @@ contract Integration_Deposit_Delegate_Undelegate_Complete is IntegrationCheckUti function testFuzz_deposit_delegate_undelegate_completeAsTokens_Max_Strategies( uint24 _random - ) public { - _configRand({_randomSeed: _random, _assetTypes: HOLDS_MAX, _userTypes: DEFAULT}); - _upgradeEigenLayerContracts(); // Upgrade contracts if forkType is not local + ) public rand(_random) { + _configAssetTypes(HOLDS_MAX); (User staker, IStrategy[] memory strategies, uint256[] memory tokenBalances) = _newRandomStaker(); (User operator,,) = _newRandomOperator(); diff --git a/src/test/integration/tests/Deposit_Queue_Complete.t.sol b/src/test/integration/tests/Deposit_Queue_Complete.t.sol index 748b2bfa24..c119c7e1ba 100644 --- a/src/test/integration/tests/Deposit_Queue_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Queue_Complete.t.sol @@ -9,18 +9,9 @@ contract Integration_Deposit_QueueWithdrawal_Complete is IntegrationCheckUtils { /// 1. deposit into strategy /// 2. queueWithdrawal /// 3. completeQueuedWithdrawal" - function testFuzz_deposit_queueWithdrawal_completeAsTokens(uint24 _random) public { - // Configure the random parameters for the test - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_queueWithdrawal_completeAsTokens(uint24 _random) public rand(_random) { // Create a staker with a nonzero balance and corresponding strategies (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); // 1. Deposit into strategy staker.depositIntoEigenlayer(strategies, tokenBalances); @@ -45,18 +36,9 @@ contract Integration_Deposit_QueueWithdrawal_Complete is IntegrationCheckUtils { assertFalse(delegationManager.isDelegated(address(staker)), "Staker should still not be delegated after withdrawal"); } - function testFuzz_deposit_queueWithdrawal_completeAsShares(uint24 _random) public { - // Configure the random parameters for the test - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_queueWithdrawal_completeAsShares(uint24 _random) public rand(_random) { // Create a staker with a nonzero balance and corresponding strategies (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); // 1. Deposit into strategy staker.depositIntoEigenlayer(strategies, tokenBalances); diff --git a/src/test/integration/tests/Deposit_Register_QueueWithdrawal_Complete.t.sol b/src/test/integration/tests/Deposit_Register_QueueWithdrawal_Complete.t.sol index b0482c8551..1875cf0b27 100644 --- a/src/test/integration/tests/Deposit_Register_QueueWithdrawal_Complete.t.sol +++ b/src/test/integration/tests/Deposit_Register_QueueWithdrawal_Complete.t.sol @@ -5,18 +5,9 @@ import "src/test/integration/users/User.t.sol"; import "src/test/integration/IntegrationChecks.t.sol"; contract Integration_Deposit_Register_QueueWithdrawal_Complete is IntegrationCheckUtils { - function testFuzz_deposit_registerOperator_queueWithdrawal_completeAsShares(uint24 _random) public { - // Configure the random parameters for the test - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_registerOperator_queueWithdrawal_completeAsShares(uint24 _random) public rand(_random) { // Create a staker with a nonzero balance and corresponding strategies (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); // 1. Staker deposits into strategy staker.depositIntoEigenlayer(strategies, tokenBalances); @@ -40,19 +31,9 @@ contract Integration_Deposit_Register_QueueWithdrawal_Complete is IntegrationChe } } - function testFuzz_deposit_registerOperator_queueWithdrawal_completeAsTokens(uint24 _random) public { - // Configure the random parameters for the test - _configRand({ - _randomSeed: _random, - _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL, - _userTypes: DEFAULT | ALT_METHODS - }); - + function testFuzz_deposit_registerOperator_queueWithdrawal_completeAsTokens(uint24 _random) public rand(_random) { // Create a staker with a nonzero balance and corresponding strategies (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); - // Upgrade contracts if forkType is not local - _upgradeEigenLayerContracts(); - // 1. Staker deposits into strategy staker.depositIntoEigenlayer(strategies, tokenBalances); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); diff --git a/src/test/integration/tests/eigenpod/EigenPod_Slashing_Migration.t.sol b/src/test/integration/tests/eigenpod/EigenPod_Slashing_Migration.t.sol deleted file mode 100644 index e69d79468c..0000000000 --- a/src/test/integration/tests/eigenpod/EigenPod_Slashing_Migration.t.sol +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.27; - -import "src/test/integration/IntegrationChecks.t.sol"; -import "src/test/integration/users/User.t.sol"; - -contract Integration_Upgrade_EigenPod_Slashing_Migration is UpgradeTest, EigenPodPausingConstants { - - function _init() internal override { - _configAssetTypes(HOLDS_ETH); - _configUserTypes(DEFAULT); - } - - /** - * @dev Assumes that the Prooftra and slashing upgrade occur at the same time - * 1. Verify validators' withdrawal credentials - * -- earn rewards on beacon chain (withdrawn to pod) - * 2. Start a checkpoint - * 3. Pause starting checkpoints - * 4. Complete in progress checkpoint - * 5. Upgrade EigenPod contracts - * 6. Exit subset of Validators - */ - function test_upgrade_eigenpod_migration(uint24 _rand) public r(_rand) { - // Only run this test as a fork test - if (forkType == LOCAL) { - return; - } - - // Initialize state - (User staker, ,) = _newRandomStaker(); - - (uint40[] memory validators, ,) = staker.startValidators(); - beaconChain.advanceEpoch_NoRewards(); - - // 1. Verify validators' withdrawal credentials - staker.verifyWithdrawalCredentials(validators); - - // Advance epoch, generating consensus rewards and withdrawing anything over 32 ETH - beaconChain.advanceEpoch(); - uint64 expectedWithdrawnGwei = uint64(validators.length) * beaconChain.CONSENSUS_REWARD_AMOUNT_GWEI(); - - // 2. Start a checkpoint - staker.startCheckpoint(); - - // 3. Pause checkpoint starting - cheats.prank(pauserMultisig); - eigenPodManager.pause(2 ** PAUSED_START_CHECKPOINT); - - cheats.expectRevert("EigenPod.onlyWhenNotPaused: index is paused in EigenPodManager"); - staker.startCheckpoint(); - - // 4. Complete in progress checkpoint - staker.completeCheckpoint(); - check_CompleteCheckpoint_WithPodBalance_State(staker, expectedWithdrawnGwei); - - // 5. Upgrade Contracts for slashing - _upgradeEigenLayerContracts(); - - // 6. Exit validators - // Fully exit one or more validators and advance epoch without generating rewards - uint40[] memory subset = _choose(validators); - uint64 exitedBalanceGwei = staker.exitValidators(subset); - beaconChain.advanceEpoch_NoRewards(); - - staker.startCheckpoint(); - check_StartCheckpoint_WithPodBalance_State(staker, exitedBalanceGwei); - - // staker.completeCheckpoint(); - // check_CompleteCheckpoint_WithExits_State(staker, subset, exitedBalanceGwei); - } -} \ No newline at end of file diff --git a/src/test/integration/tests/eigenpod/VerifyWC_StartCP_CompleteCP.t.sol b/src/test/integration/tests/eigenpod/VerifyWC_StartCP_CompleteCP.t.sol index 7a0d6dd9a0..4a87fb93c9 100644 --- a/src/test/integration/tests/eigenpod/VerifyWC_StartCP_CompleteCP.t.sol +++ b/src/test/integration/tests/eigenpod/VerifyWC_StartCP_CompleteCP.t.sol @@ -6,19 +6,18 @@ import "src/test/integration/users/User.t.sol"; contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { - modifier r(uint24 _rand) { + modifier rand(uint24 r) override { _configRand({ - _randomSeed: _rand, + _randomSeed: r, _assetTypes: HOLDS_ETH, _userTypes: DEFAULT }); - _; } - function test_GasMetering() public r(0) { + function test_GasMetering() public rand(0) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); + // Deal user 20 full stakers worth of ETH emit log_named_string("Dealing ETH to", staker.NAME()); cheats.deal(address(staker), 32 ether * 20); @@ -81,9 +80,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => no change in shares between 1 and 3 - function test_VerifyWC_StartCP_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -101,9 +99,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 1. Verify validators' withdrawal credentials /// 2. Verify validators' withdrawal credentials again /// => This should fail - function test_VerifyWC_VerifyWC_Fails(uint24 _rand) public r(_rand) { + function test_VerifyWC_VerifyWC_Fails(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -119,9 +116,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. start a checkpoint again /// => This should fail - function test_VerifyWC_StartCP_StartCP_Fails(uint24 _rand) public r(_rand) { + function test_VerifyWC_StartCP_StartCP_Fails(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -141,9 +137,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 3. complete a checkpoint /// 4. start a checkpoint without advancing a block /// => this should fail - function test_VerifyWC_StartCP_CompleteCP_StartCP_Fails(uint24 _rand) public r(_rand) { + function test_VerifyWC_StartCP_CompleteCP_StartCP_Fails(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -166,9 +161,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => no change in shares between 1 and 3 - function test_VerifyWC_Advance_StartCP_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_Advance_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -191,9 +185,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// -- move forward 1 or more epochs /// 3. complete a checkpoint /// => no change in shares between 1 and 3 - function test_VerifyWC_StartCP_Advance_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_StartCP_Advance_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -219,9 +212,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// -- Fully exit validators before verifying withdrawal credentials /// 1. Verify validators' withdrawal credentials /// => This should fail - function test_ExitValidators_VerifyWC_Fails(uint24 _rand) public r(_rand) { + function test_ExitValidators_VerifyWC_Fails(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, ,) = staker.startValidators(); staker.exitValidators(validators); @@ -236,9 +228,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => no change in shares between 1 and 3 - function test_VerifyWC_ExitValidators_StartCP_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_ExitValidators_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -267,9 +258,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 4. start a checkpoint /// 5. complete a checkpoint /// => exited balance should be reflected in 4 and 5 - function test_VerifyWC_StartCP_ExitValidators_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_StartCP_ExitValidators_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -303,9 +293,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// -- get slashed on beacon chain /// 1. Try to verify validators' withdrawal credentials /// => this should fail - function test_SlashToPod_VerifyWC_Fails(uint24 _rand) public r(_rand) { + function test_SlashToPod_VerifyWC_Fails(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, ,) = staker.startValidators(); beaconChain.slashValidators(validators); @@ -321,9 +310,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares should decrease by slashed amount - function test_VerifyWC_SlashToPod_StartCP_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_SlashToPod_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); // Advance epoch without generating rewards @@ -351,9 +339,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 4. start a checkpoint /// 5. complete a checkpoint /// => slashed balance should be reflected in 4 and 5 - function test_VerifyWC_StartCP_SlashToPod_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_StartCP_SlashToPod_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); // Advance epoch without generating rewards @@ -384,9 +371,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 4. verify withdrawal credentials for another validator while checkpoint in progress /// 5. complete a checkpoint /// => Increase in shares between 1 and 4 should reflect the new validator, less the slashed amount - function test_VerifyWC_Slash_StartCP_VerifyWC_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_Slash_StartCP_VerifyWC_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -422,9 +408,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares should decrease by slashed amount - function test_VerifyWC_SlashToPod_VerifyStale_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_SlashToPod_VerifyStale_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); // Advance epoch without generating rewards @@ -448,9 +433,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares should decrease by slashed amount - function test_VerifyWC_SlashToCL_VerifyStale_CompleteCP_SlashAgain(uint24 _rand) public r(_rand) { + function test_VerifyWC_SlashToCL_VerifyStale_CompleteCP_SlashAgain(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); // Advance epoch without generating rewards @@ -489,9 +473,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 4. start a checkpoint /// 5. complete a checkpoint /// => slashed balance should be reflected in 4 and 5 - function test_VerifyWC_StartCP_SlashToPod_CompleteCP_VerifyStale(uint24 _rand) public r(_rand) { + function test_VerifyWC_StartCP_SlashToPod_CompleteCP_VerifyStale(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); // Advance epoch without generating rewards @@ -526,9 +509,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares increase by rewards earned on beacon chain - function test_EarnOnBeacon_VerifyWC_StartCP_CompleteCP(uint24 _rand) public r(_rand) { + function test_EarnOnBeacon_VerifyWC_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, uint maxEBValidators) = staker.startValidators(); // Advance epoch and generate consensus rewards, but don't withdraw to pod @@ -556,9 +538,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares increase by rewards earned on beacon chain - function test_VerifyWC_EarnOnBeacon_StartCP_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_EarnOnBeacon_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -582,9 +563,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// -- earn rewards on beacon chain (not withdrawn to pod) /// 3. complete a checkpoint /// => no change in shares between 1 and 3 - function test_VerifyWC_StartCP_EarnOnBeacon_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_StartCP_EarnOnBeacon_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -612,9 +592,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares increase by rewards withdrawn to pod - function test_EarnToPod_VerifyWC_StartCP_CompleteCP(uint24 _rand) public r(_rand) { + function test_EarnToPod_VerifyWC_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, uint maxEBValidators) = staker.startValidators(); // Advance epoch, generating consensus rewards and withdrawing anything over MaxEB @@ -641,9 +620,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares increase by rewards withdrawn to pod - function test_VerifyWC_EarnToPod_StartCP_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_EarnToPod_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, uint maxEBValidators) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -667,9 +645,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// -- earn rewards on beacon chain (withdrawn to pod) /// 3. complete a checkpoint /// => no change in shares between 1 and 3 - function test_VerifyWC_StartCP_EarnToPod_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_StartCP_EarnToPod_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, uint maxEBValidators) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -700,9 +677,9 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// -- Pod receives native ETH via fallback /// 1. start a checkpoint /// => checkpoint should auto-complete, awarding shares for ETH in pod - function test_NativeETH_StartCP(uint24 _rand) public r(_rand) { + function test_NativeETH_StartCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); + // Send a random amount of ETH to staker's fallback (uint64 gweiSent, ) = _sendRandomETH(address(staker.pod())); @@ -719,9 +696,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares should account for native ETH - function test_NativeETH_VerifyWC_StartCP_CompleteCP(uint24 _rand) public r(_rand) { + function test_NativeETH_VerifyWC_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -747,9 +723,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// 2. start a checkpoint /// 3. complete a checkpoint /// => after 3, shares should account for native ETH - function test_VerifyWC_NativeETH_StartCP_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_NativeETH_StartCP_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); @@ -775,9 +750,8 @@ contract Integration_VerifyWC_StartCP_CompleteCP is IntegrationCheckUtils { /// -- Pod receives native ETH via fallback /// 3. complete a checkpoint /// => no change in shares between 1 and 3 - function test_VerifyWC_StartCP_NativeETH_CompleteCP(uint24 _rand) public r(_rand) { + function test_VerifyWC_StartCP_NativeETH_CompleteCP(uint24 _rand) public rand(_rand) { (User staker, ,) = _newRandomStaker(); - _upgradeEigenLayerContracts(); (uint40[] memory validators, uint64 beaconBalanceGwei, ) = staker.startValidators(); beaconChain.advanceEpoch_NoRewards(); diff --git a/src/test/integration/tests/upgrade/Complete_PreSlashing_Withdrawal.t.sol b/src/test/integration/tests/upgrade/Complete_PreSlashing_Withdrawal.t.sol index 67547287d3..968d240da8 100644 --- a/src/test/integration/tests/upgrade/Complete_PreSlashing_Withdrawal.t.sol +++ b/src/test/integration/tests/upgrade/Complete_PreSlashing_Withdrawal.t.sol @@ -14,7 +14,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is UpgradeTest { staker.depositIntoEigenlayer(strategies, tokenBalances); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); - Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); /// Upgrade to slashing contracts _upgradeEigenLayerContracts(); @@ -27,7 +27,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is UpgradeTest { } } - function testFuzz_delegate_deposit_queue_upgrade_completeAsShares(uint24 _random) public rand(_random) { + function testFuzz_delegate_deposit_queue_completeAsShares(uint24 _random) public rand(_random) { /// Pre-upgrade: /// 1. Create staker and operator with some asset amounts /// 2. Staker delegates to operator @@ -39,7 +39,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is UpgradeTest { staker.delegateTo(operator); staker.depositIntoEigenlayer(strategies, tokenBalances); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); - Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); /// Upgrade to slashing contracts _upgradeEigenLayerContracts(); @@ -63,7 +63,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is UpgradeTest { staker.depositIntoEigenlayer(strategies, tokenBalances); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); - Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); /// Upgrade to slashing contracts _upgradeEigenLayerContracts(); @@ -76,7 +76,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is UpgradeTest { } } - function testFuzz_delegate_deposit_queue_upgrade_completeAsTokens(uint24 _random) public rand(_random) { + function testFuzz_delegate_deposit_queue_completeAsTokens(uint24 _random) public rand(_random) { /// Pre-upgrade: /// 1. Create staker and operator with some asset amounts /// 2. Staker delegates to operator @@ -89,7 +89,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is UpgradeTest { staker.depositIntoEigenlayer(strategies, tokenBalances); uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); uint[] memory expectedTokens = _calculateExpectedTokens(strategies, shares); - Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); /// Upgrade to slashing contracts _upgradeEigenLayerContracts(); diff --git a/src/test/integration/tests/upgrade/Delegate_Upgrade_Allocate.t.sol b/src/test/integration/tests/upgrade/Delegate_Upgrade_Allocate.t.sol index 8d878beec9..6c9ee61c65 100644 --- a/src/test/integration/tests/upgrade/Delegate_Upgrade_Allocate.t.sol +++ b/src/test/integration/tests/upgrade/Delegate_Upgrade_Allocate.t.sol @@ -21,20 +21,21 @@ contract Integration_Upgrade_Deposit_Delegate_Allocate is UpgradeTest { // 3. Set allocation delay for operator operator.setAllocationDelay(1); - rollForward({blocks: ALLOCATION_CONFIGURATION_DELAY + 1}); + rollForward({blocks: ALLOCATION_CONFIGURATION_DELAY}); // 4. Create an operator set and register an operator. OperatorSet memory operatorSet = avs.createOperatorSet(strategies); operator.registerForOperatorSet(operatorSet); - check_Registration_State_NoAllocation(operator, operatorSet, allStrats); // 5. Allocate to operator set. - AllocateParams memory allocateParams = AllocateParams({ - operatorSet: operatorSet, - strategies: strategies, - newMagnitudes: _randMagnitudes({sum: 1 ether, len: strategies.length}) - }); - operator.modifyAllocations(allocateParams); - check_IncrAlloc_State_Slashable(operator, allocateParams); + IAllocationManagerTypes.AllocateParams memory allocateParams = + operator.modifyAllocations(operatorSet, _randMagnitudes({sum: 1 ether, len: strategies.length})); + assert_Snap_Allocations_Modified( + operator, allocateParams, false, "operator allocations should be updated before delay" + ); + _rollBlocksForCompleteAllocation(operator, operatorSet, strategies); + assert_Snap_Allocations_Modified( + operator, allocateParams, true, "operator allocations should be updated after delay" + ); } } \ No newline at end of file diff --git a/src/test/integration/tests/upgrade/EigenPod_Slashing_Migration.t.sol b/src/test/integration/tests/upgrade/EigenPod_Slashing_Migration.t.sol index 9be5e673f7..aa57d26942 100644 --- a/src/test/integration/tests/upgrade/EigenPod_Slashing_Migration.t.sol +++ b/src/test/integration/tests/upgrade/EigenPod_Slashing_Migration.t.sol @@ -5,9 +5,25 @@ import "src/test/integration/UpgradeTest.t.sol"; contract Integration_Upgrade_EigenPod_Slashing_Migration is UpgradeTest, EigenPodPausingConstants { +<<<<<<< HEAD function _init() internal override { _configAssetTypes(HOLDS_ETH); _configUserTypes(DEFAULT); +======= +<<<<<<<< HEAD:src/test/integration/tests/eigenpod/EigenPod_Slashing_Migration.t.sol + function _init() internal override { + _configAssetTypes(HOLDS_ETH); + _configUserTypes(DEFAULT); +======== + modifier rand(uint24 _rand) override { + _configRand({ + _randomSeed: _rand, + _assetTypes: HOLDS_ETH, + _userTypes: DEFAULT + }); + _; +>>>>>>>> 0156d76e (test: separate upgrade test functionality from main integration tests (#1031)):src/test/integration/tests/upgrade/EigenPod_Slashing_Migration.t.sol +>>>>>>> 0156d76e (test: separate upgrade test functionality from main integration tests (#1031)) } /** diff --git a/src/test/integration/tests/upgrade/README.md b/src/test/integration/tests/upgrade/README.md new file mode 100644 index 0000000000..c9844a3143 --- /dev/null +++ b/src/test/integration/tests/upgrade/README.md @@ -0,0 +1,45 @@ +## Upgrade Tests + +This folder contains specific tests we want to conduct to determine upgrade compatibility. Tests in this folder are only run if the `forktest` profile is selected, e.g: + +`env FOUNDRY_PROFILE=forktest forge t --mc Upgrade` + +#### How to Write + +Upgrade tests inherit from the `UpgradeTest` mixin, which imports everything you need for a standard integration test. A standard integration test automatically upgrades all contracts to the latest repo contracts, even when forking from mainnet. + +In contrast, the `UpgradeTest` mixin ensures that (when a test begins) the contracts we're working with are _not upgraded_. This allows the test writer to perform some initial setup actions before calling `_upgradeEigenLayerContracts()`, after which we can check that the upgrade correctly handles pre-upgrade state. + +#### Example + +Say we want to check that withdrawals initiated before the slashing upgrade are completable after the slashing upgrade. This example test shows how: + +```solidity +contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is UpgradeTest { + + function testFuzz_deposit_queue_upgrade_completeAsShares(uint24 _random) public rand(_random) { + /// Pre-upgrade: + /// 1. Create staker with some assets + /// 2. Staker deposits into EigenLayer + /// 3. Staker queues a withdrawal + (User staker, IStrategy[] memory strategies, uint[] memory tokenBalances) = _newRandomStaker(); + User operator = User(payable(0)); + + staker.depositIntoEigenlayer(strategies, tokenBalances); + uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances); + IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares); + + /// Upgrade to slashing contracts + _upgradeEigenLayerContracts(); + + // Complete pre-slashing withdrawals as shares + _rollBlocksForCompleteWithdrawals(withdrawals); + for (uint i = 0; i < withdrawals.length; i++) { + staker.completeWithdrawalAsShares(withdrawals[i]); + check_Withdrawal_AsShares_State(staker, operator, withdrawals[i], strategies, shares); + } + } +} +``` + +**Note** how the initial staker actions are NOT followed by `check_X_State` methods. This is because, before calling `_upgradeEigenLayerContracts`, the test is being run on old contracts. Adding invariant checks to old state transitions is not the point of this test and would add a lot of maintenance overhead. \ No newline at end of file