diff --git a/src/test/integration/IntegrationBase.t.sol b/src/test/integration/IntegrationBase.t.sol index b28ee59c3d..3443999d4e 100644 --- a/src/test/integration/IntegrationBase.t.sol +++ b/src/test/integration/IntegrationBase.t.sol @@ -202,7 +202,7 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { /// @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 }); + uint _rand = _randUint({ min: 1, max: (2**validators.length) - 1 }); uint40[] memory result = new uint40[](validators.length); uint newLen; @@ -833,6 +833,20 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { } } + function assert_Snap_StakeBecomeUnslashable( + address operator, + OperatorSet memory operatorSet, + IStrategy[] memory strategies, + string memory err + ) internal { + uint[] memory curSlashableStake = _getMinSlashableStake(operator, operatorSet, strategies); + uint[] memory prevSlashableStake = _getPrevMinSlashableStake(operator, operatorSet, strategies); + + for (uint i = 0; i < strategies.length; i++) { + assertTrue(prevSlashableStake[i] > curSlashableStake[i], err); + } + } + function assert_Snap_Added_SlashableStake( User operator, OperatorSet memory operatorSet, @@ -1658,6 +1672,20 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { } } + function assert_SlashableStake_Decrease_BCSlash( + User staker + ) internal { + if (delegationManager.isDelegated(address(staker))) { + address operator = delegationManager.delegatedTo(address(staker)); + (OperatorSet[] memory operatorSets, Allocation[] memory allocations) = _getStrategyAllocations(operator, BEACONCHAIN_ETH_STRAT); + for (uint i = 0; i < operatorSets.length; i++) { + if (allocations[i].currentMagnitude > 0) { + assert_Snap_StakeBecomeUnslashable(operator, operatorSets[i], BEACONCHAIN_ETH_STRAT.toArray(), "operator should have minSlashableStake decreased"); + } + } + } + } + /******************************************************************************* SNAPSHOT ASSERTIONS: UNDERLYING TOKEN *******************************************************************************/ @@ -1904,6 +1932,16 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { assertEq(prevExitedBalanceGwei + addedGwei, curExitedBalanceGwei, err); } + function assert_Snap_BCSF_Decreased( + User staker, + string memory err + ) internal { + uint64 curBCSF = _getBeaconChainSlashingFactor(staker); + uint64 prevBCSF = _getPrevBeaconChainSlashingFactor(staker); + + assertLt(curBCSF, prevBCSF, err); + } + /******************************************************************************* UTILITY METHODS *******************************************************************************/ @@ -2551,6 +2589,14 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { return _getMinSlashableStake(operator, operatorSet, strategies); } + function _getPrevMinSlashableStake( + address operator, + OperatorSet memory operatorSet, + IStrategy[] memory strategies + ) internal timewarp() returns (uint[] memory) { + return _getMinSlashableStake(operator, operatorSet, strategies); + } + function _getMinSlashableStake( User operator, OperatorSet memory operatorSet, @@ -2564,6 +2610,19 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { })[0]; } + function _getMinSlashableStake( + address operator, + OperatorSet memory operatorSet, + IStrategy[] memory strategies + ) internal view returns (uint[] memory) { + return allocationManager.getMinimumSlashableStake({ + operatorSet: operatorSet, + operators: address(operator).toArray(), + strategies: strategies, + futureBlock: uint32(block.number) + })[0]; + } + function _getPrevAllocatedStake( User operator, OperatorSet memory operatorSet, @@ -2591,6 +2650,14 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter { (operatorSets, allocations) = allocationManager.getStrategyAllocations(address(operator), strategy); } + function _getStrategyAllocations( + address operator, + IStrategy strategy + ) internal view returns (OperatorSet[] memory operatorSets, Allocation[] memory allocations) { + (operatorSets, allocations) = allocationManager.getStrategyAllocations(operator, strategy); + } + + function _getPrevIsSlashable( User operator, OperatorSet memory operatorSet diff --git a/src/test/integration/IntegrationChecks.t.sol b/src/test/integration/IntegrationChecks.t.sol index 5fd762338e..e53f6a12da 100644 --- a/src/test/integration/IntegrationChecks.t.sol +++ b/src/test/integration/IntegrationChecks.t.sol @@ -94,6 +94,9 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Removed_Staker_WithdrawableShares(staker, BEACONCHAIN_ETH_STRAT, slashedAmountGwei * GWEI_TO_WEI, "should have decreased withdrawable shares by slashed amount"); assert_Snap_Removed_ActiveValidatorCount(staker, slashedValidators.length, "should have decreased active validator count"); assert_Snap_Removed_ActiveValidators(staker, slashedValidators, "exited validators should each be WITHDRAWN"); + assert_Snap_BCSF_Decreased(staker, "BCSF should decrease"); + assert_Snap_Unchanged_DSF(staker, BEACONCHAIN_ETH_STRAT.toArray(), "DSF should be unchanged"); + assert_SlashableStake_Decrease_BCSlash(staker); } function check_CompleteCheckpoint_WithSlashing_HandleRoundDown_State( @@ -105,6 +108,9 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Unchanged_Staker_DepositShares(staker, "staker shares should not have decreased"); assert_Snap_Removed_Staker_WithdrawableShares_AtLeast(staker, BEACONCHAIN_ETH_STRAT, slashedAmountGwei * GWEI_TO_WEI, "should have decreased withdrawable shares by at least slashed amount"); + assert_Snap_BCSF_Decreased(staker, "BCSF should decrease"); + assert_Snap_Unchanged_DSF(staker, BEACONCHAIN_ETH_STRAT.toArray(), "DSF should be unchanged"); + assert_SlashableStake_Decrease_BCSlash(staker); // TODO - currently only used after a `NoWithdrawNoRewards` action. Investigate re-adding in future. // assert_Snap_Removed_ActiveValidatorCount(staker, slashedValidators.length, "should have decreased active validator count"); // assert_Snap_Removed_ActiveValidators(staker, slashedValidators, "exited validators should each be WITHDRAWN"); @@ -119,6 +125,9 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Unchanged_Staker_DepositShares(staker, "staker shares should not have decreased"); assert_Snap_Removed_Staker_WithdrawableShares_AtLeast(staker, BEACONCHAIN_ETH_STRAT, slashedAmountGwei * GWEI_TO_WEI, "should have decreased withdrawable shares by at least slashed amount"); assert_Snap_Unchanged_ActiveValidatorCount(staker, "should not have changed active validator count"); + assert_Snap_BCSF_Decreased(staker, "BCSF should decrease"); + assert_Snap_Unchanged_DSF(staker, BEACONCHAIN_ETH_STRAT.toArray(), "DSF should be unchanged"); + assert_SlashableStake_Decrease_BCSlash(staker); } function check_CompleteCheckpoint_WithCLSlashing_State( @@ -130,6 +139,9 @@ contract IntegrationCheckUtils is IntegrationBase { assert_Snap_Unchanged_Staker_DepositShares(staker, "staker shares should not have decreased"); assert_Snap_Removed_Staker_WithdrawableShares(staker, BEACONCHAIN_ETH_STRAT, slashedAmountGwei * GWEI_TO_WEI, "should have decreased withdrawable shares by slashed amount"); assert_Snap_Unchanged_ActiveValidatorCount(staker, "should not have changed active validator count"); + assert_Snap_BCSF_Decreased(staker, "BCSF should decrease"); + assert_Snap_Unchanged_DSF(staker, BEACONCHAIN_ETH_STRAT.toArray(), "DSF should be unchanged"); + assert_SlashableStake_Decrease_BCSlash(staker); } function check_CompleteCheckpoint_WithExits_State( diff --git a/src/test/integration/tests/Slashed_Eigenpod.t.sol b/src/test/integration/tests/Slashed_Eigenpod.t.sol index 5bd01ae746..db49a59268 100644 --- a/src/test/integration/tests/Slashed_Eigenpod.t.sol +++ b/src/test/integration/tests/Slashed_Eigenpod.t.sol @@ -34,6 +34,7 @@ contract Integration_SlashedEigenpod is IntegrationCheckUtils { check_Deposit_State(staker, strategies, shares); uint40[] memory slashedValidators = _choose(validators); + console.log(slashedValidators.length); slashedGwei = beaconChain.slashValidators(slashedValidators); console.log(slashedGwei); beaconChain.advanceEpoch_NoWithdrawNoRewards();