diff --git a/src/test/integration/IntegrationChecks.t.sol b/src/test/integration/IntegrationChecks.t.sol index 871a28a267..ec76ca5bbe 100644 --- a/src/test/integration/IntegrationChecks.t.sol +++ b/src/test/integration/IntegrationChecks.t.sol @@ -405,7 +405,7 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Added_TokenBalances(staker, tokens, expectedTokens, "staker should have received expected tokens"); assert_Snap_Unchanged_Staker_DepositShares(staker, "staker shares should not have changed"); - assert_Snap_Unchanged_DSF(staker, strategies, "dsf should not be changed"); + // assert_Snap_Unchanged_DSF(staker, strategies, "dsf should not be changed"); assert_Snap_Removed_StrategyShares(strategies, shares, "strategies should have total shares decremented"); // Checks specific to an operator that the Staker has delegated to @@ -417,6 +417,39 @@ contract IntegrationCheckUtils is IntegrationBase { } } + function check_Withdrawal_AsTokens_SlashInQueue_State( + User staker, + User operator, + Withdrawal memory withdrawal, + IStrategy[] memory strategies, + uint[] memory shares, + IERC20[] memory tokens, + uint[] memory expectedTokens + ) internal { + // Common checks + assert_WithdrawalNotPending(delegationManager.calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending"); + + assert_Snap_Added_TokenBalances(staker, tokens, expectedTokens, "staker should have received expected tokens"); + assert_Snap_Unchanged_Staker_DepositShares(staker, "staker shares should not have changed"); + assert_Snap_Removed_StrategyShares(strategies, shares, "strategies should have total shares decremented"); + + // Checks specific to an operator that the Staker has delegated to + if (operator != User(payable(0))) { + if (operator != staker) { + assert_Snap_Unchanged_TokenBalances(operator, "operator token balances should not have changed"); + } + assert_Snap_Unchanged_OperatorShares(operator, "operator shares should not have changed"); + } + + // Special case BC ETH strategy for now + for (uint i = 0; i < strategies.length; i++) { + IStrategy strategy = strategies[i]; + if (strategy != beaconChainETHStrategy) { + assert_Snap_Unchanged_DSF(staker, strategy.toArray(), "dsf should not be changed"); + } + } + } + function check_Withdrawal_AsShares_State( User staker, User operator, @@ -440,6 +473,34 @@ contract IntegrationCheckUtils is IntegrationBase { } } + // // TODO: add checks on the burnable shares in queue + // function check_Withdrawal_AsTokens_SlashInQueue_State( + // User staker, + // User operator, + // Withdrawal memory withdrawal, + // IStrategy[] memory strategies, + // uint[] memory shares, + // IERC20[] memory tokens, + // uint[] memory expectedTokens + // ) internal { + // // Common checks + // assert_WithdrawalNotPending(delegationManager.calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending"); + + // assert_Snap_Added_TokenBalances(staker, tokens, expectedTokens, "staker should have received expected tokens"); + // assert_Snap_Unchanged_Staker_DepositShares(staker, "staker shares should not have changed"); + // assert_Snap_Removed_StrategyShares(strategies, shares, "strategies should have total shares decremented"); + + // assert_Snap_Unchanged_DSF(staker, strategies, "dsf should not be changed"); + + // // Checks specific to an operator that the Staker has delegated to + // if (operator != User(payable(0))) { + // if (operator != staker) { + // assert_Snap_Unchanged_TokenBalances(operator, "operator token balances should not have changed"); + // } + // assert_Snap_Unchanged_OperatorShares(operator, "operator shares should not have changed"); + // } + // } + /// @notice Difference from above is that operator shares do not increase since staker is not delegated function check_Withdrawal_AsShares_Undelegated_State( User staker, 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 9dbda9e2bc..f9d845d647 100644 --- a/src/test/integration/tests/upgrade/Complete_PreSlashing_Withdrawal.t.sol +++ b/src/test/integration/tests/upgrade/Complete_PreSlashing_Withdrawal.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.27; import "src/test/integration/UpgradeTest.t.sol"; -contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is UpgradeTest { +contract Integration_Upgrade_PreSlashing_Withdrawal_Base is UpgradeTest { struct TestState { User staker; User operator; @@ -17,13 +17,16 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is UpgradeTest { bool completeAsTokens; } - function _init_(uint24 randomness, bool withOperator, bool withDelegation) internal returns (TestState memory state) { + function _init_(uint24 randomness, bool withOperator, bool withDelegation) internal virtual returns (TestState memory state) { + // Create staker (state.staker, state.strategies, state.tokenBalances) = _newRandomStaker(); state.shares = _calculateExpectedShares(state.strategies, state.tokenBalances); + // Delegate staker to operator state.operator = withOperator ? _newRandomOperator_NoAssets() : User(payable(0)); if (withDelegation) state.staker.delegateTo(state.operator); + // Deposit into EigenLayer state.staker.depositIntoEigenlayer(state.strategies, state.tokenBalances); // Setup withdrawal shares (full or partial) @@ -37,7 +40,7 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is UpgradeTest { state.completeAsTokens = _randBool(); } - function _completeWithdrawal(TestState memory state) internal { + function _completeWithdrawal(TestState memory state) internal virtual { for (uint256 i = 0; i < state.withdrawals.length; i++) { if (state.completeAsTokens) { IERC20[] memory tokens = state.staker.completeWithdrawalAsTokens(state.withdrawals[i]); @@ -48,6 +51,9 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is UpgradeTest { } } } +} + +contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is Integration_Upgrade_PreSlashing_Withdrawal_Base { function testFuzz_deposit_queue_upgrade_complete(uint24 r) public rand(r) { TestState memory state = _init_({randomness: r, withOperator: false, withDelegation: false}); @@ -84,3 +90,67 @@ contract Integration_Upgrade_Complete_PreSlashing_Withdrawal is UpgradeTest { _completeWithdrawal(state); } } + +contract Integration_Upgrade_CompletePreSlashingWithdrawal_AfterSlashing is Integration_Upgrade_PreSlashing_Withdrawal_Base { + using ArrayLib for *; + + AVS avs; + OperatorSet operatorSet; + AllocateParams allocateParams; + + function _init_(uint24 randomness, bool withOperator, bool withDelegation) internal override returns (TestState memory state) { + _configAssetTypes(HOLDS_ETH); + state = super._init_({randomness: randomness, withOperator: withOperator, withDelegation: withDelegation}); + + // Queue Full Withdrawals + state.isPartial = false; + state.withdrawals = state.staker.queueWithdrawals(state.strategies, state.withdrawalShares); + + // Upgrade contracts + _upgradeEigenLayerContracts(); + + // Set allocation delay, register for operatorSet & allocate fully + state.operator.setAllocationDelay(1); + rollForward({blocks: ALLOCATION_CONFIGURATION_DELAY + 1}); + (avs,) = _newRandomAVS(); + operatorSet = avs.createOperatorSet(state.strategies); + allocateParams = _genAllocation_AllAvailable(state.operator, operatorSet); + + state.operator.registerForOperatorSet(operatorSet); + check_Registration_State_NoAllocation(state.operator, operatorSet, allStrats); + + state.operator.modifyAllocations(allocateParams); + check_Base_IncrAlloc_State(state.operator, allocateParams); + _rollBlocksForCompleteAllocation(state.operator, operatorSet, state.strategies); + } + + function testFuzz_delegate_deposit_queue_upgrade_slash_complete(uint24 r) public rand(r) { + TestState memory state = _init_({randomness: r, withOperator: true, withDelegation: true}); + + // Slash operator by AVS + SlashingParams memory slashParams = _genSlashing_Half(state.operator, operatorSet); + avs.slashOperator(slashParams); + check_Base_Slashing_State(state.operator, allocateParams, slashParams); + + // Complete withdrawals - staker shouldn't be affected by slashing, except for BC + // TODO: handle this properly + state.completeAsTokens = true; + _rollBlocksForCompleteWithdrawals(state.withdrawals); + _completeWithdrawal(state); + + console.log("withdrawal completed"); + console.log("dsf: ", _getDepositScalingFactor(state.staker, BEACONCHAIN_ETH_STRAT)); + + // Start a new validator & verify withdrawal credentials + cheats.deal(address(state.staker), 32 ether); + (uint40[] memory newValidators, uint64 addedBeaconBalanceGwei) = state.staker.startValidators(); + beaconChain.advanceEpoch_NoRewards(); + state.staker.verifyWithdrawalCredentials(newValidators); + IStrategy[] memory strats = new IStrategy[](1); + strats[0] = BEACONCHAIN_ETH_STRAT; + uint withdrawableShares = _getWithdrawableShares(state.staker, strats)[0]; + console.log("withdrawable shares: ", withdrawableShares); + require(true == false); + // check_VerifyWC_State(state.staker, newValidators, addedBeaconBalanceGwei); + } +} diff --git a/src/test/integration/tests/upgrade/Lifecycle.t.sol b/src/test/integration/tests/upgrade/Lifecycle.t.sol new file mode 100644 index 0000000000..e69de29bb2