Skip to content

Commit

Permalink
test: separate upgrade test functionality from main integration tests (
Browse files Browse the repository at this point in the history
…#1031)

* refactor(test): clean up random config and upgrade tests

* test: move test to upgrade tests
  • Loading branch information
wadealexc authored and ypatil12 committed Jan 30, 2025
1 parent 7246714 commit ea876c1
Show file tree
Hide file tree
Showing 17 changed files with 369 additions and 428 deletions.
26 changes: 1 addition & 25 deletions src/test/integration/IntegrationBase.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -138,31 +138,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 });
Expand Down
11 changes: 0 additions & 11 deletions src/test/integration/IntegrationChecks.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
63 changes: 48 additions & 15 deletions src/test/integration/IntegrationDeployer.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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;
Expand All @@ -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();
Expand Down Expand Up @@ -203,14 +224,19 @@ 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();
beaconChain = new BeaconChainMock(eigenPodManager, BEACON_GENESIS_TIME);

// Since we haven't done the slashing upgrade on mainnet yet, upgrade mainnet contracts
// prior to test. `isUpgraded` is true by default, but is set to false in `UpgradeTest.t.sol`
if (isUpgraded) {
_upgradeMainnetContracts();
}
}

/// Deploy current implementation contracts and upgrade existing proxies
function _upgradeMainnetContracts() public virtual {
cheats.startPrank(address(executorMultisig));

Expand Down Expand Up @@ -453,10 +479,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");
}

Expand Down
38 changes: 38 additions & 0 deletions src/test/integration/UpgradeTest.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;

import "src/test/integration/IntegrationDeployer.t.sol";
import "src/test/integration/IntegrationChecks.t.sol";

abstract contract UpgradeTest is IntegrationCheckUtils {

/// Only run upgrade tests on mainnet forks
function setUp() public virtual override {
if (!isForktest()) {
cheats.skip(true);
} else {
isUpgraded = false;
super.setUp();
}
}

/// Deploy current implementation contracts and upgrade existing proxies
function _upgradeEigenLayerContracts() public virtual {
require(forkType == MAINNET, "_upgradeEigenLayerContracts: somehow running upgrade test locally");
require(!isUpgraded, "_upgradeEigenLayerContracts: already performed upgrade");

emit log("_upgradeEigenLayerContracts: upgrading mainnet to slashing");

_upgradeMainnetContracts();

// 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");
}
}
26 changes: 4 additions & 22 deletions src/test/integration/tests/Delegate_Deposit_Queue_Complete.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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++) {
Expand All @@ -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();
Expand All @@ -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);
Expand All @@ -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);
}
Expand Down
Loading

0 comments on commit ea876c1

Please sign in to comment.