Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/test/integration/IntegrationBase.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1995,11 +1995,12 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
/// @dev On a delegation, the DSF should be increased if the operator magnitude is non-WAD
function assert_Snap_DSF_State_Delegation(
User staker,
User operator,
IStrategy[] memory strategies,
uint[] memory delegatableShares,
string memory err
) internal {
uint64[] memory maxMags = _getMaxMagnitudes(staker, strategies);
uint64[] memory maxMags = _getMaxMagnitudes(operator, strategies);
Comment thread
eigenmikem marked this conversation as resolved.

for (uint i = 0; i < strategies.length; i++) {
IStrategy[] memory stratArray = strategies[i].toArray();
Expand Down Expand Up @@ -2775,7 +2776,8 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
IStrategy strat = strategies[i];

if (strat == BEACONCHAIN_ETH_STRAT) {
expectedTokens[i] = shares[i];
uint64 amountGwei = uint64(shares[i] / GWEI_TO_WEI);
expectedTokens[i] = amountGwei * GWEI_TO_WEI;
} else {
expectedTokens[i] = strat.sharesToUnderlying(shares[i]);
}
Expand Down
2 changes: 1 addition & 1 deletion src/test/integration/IntegrationChecks.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ contract IntegrationCheckUtils is IntegrationBase {
uint256[] memory delegatableShares = _getPrevStakerWithdrawableShares(staker, strategies);
assert_Snap_Added_OperatorShares(operator, strategies, delegatableShares, "operator should have received shares");
check_Added_SlashableStake(operator, strategies, delegatableShares);
assert_Snap_DSF_State_Delegation(staker, strategies, delegatableShares, "staker's DSF not updated correctly");
assert_Snap_DSF_State_Delegation(staker, operator, strategies, delegatableShares, "staker's DSF not updated correctly");
}

function check_Added_SlashableStake(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,6 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat
uint[] numTokensRemaining;

function _init() internal override {
// 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
_configAssetTypes(HOLDS_LST);
_configUserTypes(DEFAULT);

(staker, strategies, initTokenBalances) = _newRandomStaker();
Expand All @@ -33,9 +30,14 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat

uint[] memory tokensToDeposit = new uint[](initTokenBalances.length);
numTokensRemaining = new uint[](initTokenBalances.length);
uint256 eth_to_deal;
for (uint i = 0; i < initTokenBalances.length; i++) {
if (strategies[i] == BEACONCHAIN_ETH_STRAT) {
tokensToDeposit[i] = initTokenBalances[i];
//user.depositIntoEigenlayer uses all ETH balance for a pod, so we deal back staker's
//starting ETH to replicate partial deposit state
eth_to_deal = initTokenBalances[i];
numTokensRemaining[i] = initTokenBalances[i];
continue;
}

Expand All @@ -46,6 +48,8 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat
// 1. Deposit Into Strategies
initDepositShares = _calculateExpectedShares(strategies, tokensToDeposit);
staker.depositIntoEigenlayer(strategies, tokensToDeposit);
//dealing back ETH
cheats.deal(address(staker), eth_to_deal);
check_Deposit_State_PartialDeposit(staker, strategies, initDepositShares, numTokensRemaining);

// 2. Delegate to operator
Expand Down Expand Up @@ -302,4 +306,79 @@ contract Integration_Deposit_Delegate_Allocate_Slash_Queue_Redeposit is Integrat
operator.modifyAllocations(deallocateParams);
check_DecrAlloc_State_Slashable(operator, deallocateParams);
}

function testFuzz_fullSlash_undelegate_redeposit_complete(
uint24 _random
) public rand(_random) {

initDepositShares = _getStakerDepositShares(staker, strategies);

// 4. Fully slash operator
SlashingParams memory slashParams = _genSlashing_Full(operator, operatorSet);
avs.slashOperator(slashParams);
check_FullySlashed_State(operator, allocateParams, slashParams);

// 5. Undelegate from an operator
uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies);
Withdrawal[] memory withdrawals = staker.undelegate();
bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals);
check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, withdrawableShares);

// 6. Redeposit
uint[] memory shares = _calculateExpectedShares(strategies, numTokensRemaining);
staker.depositIntoEigenlayer(strategies, numTokensRemaining);
check_Deposit_State(staker, strategies, shares);

// 7. Complete withdrawal. Staker should receive 0 shares/tokens after a full slash
_rollBlocksForCompleteWithdrawals(withdrawals);

for (uint256 i = 0; i < withdrawals.length; ++i) {
uint[] memory expectedShares = _calculateExpectedShares(withdrawals[i]);
staker.completeWithdrawalAsShares(withdrawals[i]);
check_Withdrawal_AsShares_Undelegated_State(staker, operator, withdrawals[i], withdrawals[i].strategies, expectedShares);
}


// 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_fullSlash_redelegate_redeposit_complete(
uint24 _random
) public rand(_random) {

(User operator2, ,) = _newRandomOperator();
initDepositShares = _getStakerDepositShares(staker, strategies);

// 4. Fully slash operator
SlashingParams memory slashParams = _genSlashing_Full(operator, operatorSet);
avs.slashOperator(slashParams);
check_FullySlashed_State(operator, allocateParams, slashParams);

// 5. Undelegate from an operator
uint[] memory withdrawableShares = _getStakerWithdrawableShares(staker, strategies);
Withdrawal[] memory withdrawals = staker.redelegate(operator2);
bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals);
check_Redelegate_State(staker, operator, operator2, withdrawals, withdrawalRoots, strategies, withdrawableShares);

// 6. Redeposit
uint[] memory shares = _calculateExpectedShares(strategies, numTokensRemaining);
staker.depositIntoEigenlayer(strategies, numTokensRemaining);
check_Deposit_State(staker, strategies, shares);

// 7. Complete withdrawal. Staker should receive 0 shares/tokens after a full slash
_rollBlocksForCompleteWithdrawals(withdrawals);

for (uint256 i = 0; i < withdrawals.length; ++i) {
uint[] memory expectedShares = _calculateExpectedShares(withdrawals[i]);
staker.completeWithdrawalAsShares(withdrawals[i]);
check_Withdrawal_AsShares_Undelegated_State(staker, operator, withdrawals[i], withdrawals[i].strategies, expectedShares);
}


// 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");
}
}
127 changes: 63 additions & 64 deletions src/test/integration/tests/Slashed_Eigenpod_BC.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -134,72 +134,71 @@ contract Integration_SlashedEigenpod_BC is IntegrationCheckUtils {
assertApproxEqAbs(withdrawableSharesAfter[0], depositSharesAfter[0], 100, "Withdrawable shares should equal deposit shares after withdrawal");
}

// TODO: Fix this test
// function testFuzz_delegateSlashedStaker_slashedOperator(uint24 _random) public rand(_random) {


// (User staker2,,) = _newRandomStaker();
// (uint40[] memory validators2,) = staker2.startValidators();
// beaconChain.advanceEpoch_NoWithdrawNoRewards();
// staker2.verifyWithdrawalCredentials(validators2);
// staker2.startCheckpoint();
// staker2.completeCheckpoint();
// staker2.delegateTo(operator);

// //randomize additional deposit to eigenpod
// if(_randBool()){
// uint amount = 32 ether * _randUint({min: 1, max: 5});
// cheats.deal(address(staker), amount);
// (uint40[] memory validators,) = staker.startValidators();
// beaconChain.advanceEpoch_NoWithdrawNoRewards();
// staker.verifyWithdrawalCredentials(validators);
function testFuzz_delegateSlashedStaker_slashedOperator(uint24 _random) public rand(_random) {


(User staker2,,) = _newRandomStaker();
(uint40[] memory validators2,) = staker2.startValidators();
beaconChain.advanceEpoch_NoWithdrawNoRewards();
staker2.verifyWithdrawalCredentials(validators2);
staker2.startCheckpoint();
staker2.completeCheckpoint();
staker2.delegateTo(operator);

//randomize additional deposit to eigenpod
if(_randBool()){
uint amount = 32 ether * _randUint({min: 1, max: 5});
cheats.deal(address(staker), amount);
(uint40[] memory validators,) = staker.startValidators();
beaconChain.advanceEpoch_NoWithdrawNoRewards();
staker.verifyWithdrawalCredentials(validators);

// staker.startCheckpoint();
// staker.completeCheckpoint();
// }

// // Create an operator set and register an operator.
// operatorSet = avs.createOperatorSet(strategies);
// operator.registerForOperatorSet(operatorSet);
// check_Registration_State_NoAllocation(operator, operatorSet, strategies);

// // Allocate to operator set
// allocateParams = _genAllocation_AllAvailable(operator, operatorSet, strategies);
// operator.modifyAllocations(allocateParams);
// check_IncrAlloc_State_Slashable(operator, allocateParams);
// _rollBlocksForCompleteAllocation(operator, operatorSet, strategies);

// //Slash operator before delegation
// IAllocationManagerTypes.SlashingParams memory slashingParams;
// uint wadToSlash = _randWadToSlash();
// slashingParams = avs.slashOperator(operator, operatorSet.id, strategies, wadToSlash.toArrayU256());
// assert_Snap_Allocations_Slashed(slashingParams, operatorSet, true, "operator allocations should be slashed");

// uint256[] memory initDelegatableShares = _getWithdrawableShares(staker, strategies);
// uint256[] memory initDepositShares = _getStakerDepositShares(staker, strategies);

// // Delegate to an operator
// staker.delegateTo(operator);
// (uint256[] memory delegatedShares, ) = delegationManager.getWithdrawableShares(address(staker), strategies);
// check_Delegation_State(staker, operator, strategies, initDepositShares);
staker.startCheckpoint();
staker.completeCheckpoint();
}

// Create an operator set and register an operator.
operatorSet = avs.createOperatorSet(strategies);
operator.registerForOperatorSet(operatorSet);
check_Registration_State_NoAllocation(operator, operatorSet, strategies);

// Allocate to operator set
allocateParams = _genAllocation_AllAvailable(operator, operatorSet, strategies);
operator.modifyAllocations(allocateParams);
check_IncrAlloc_State_Slashable(operator, allocateParams);
_rollBlocksForCompleteAllocation(operator, operatorSet, strategies);

//Slash operator before delegation
IAllocationManagerTypes.SlashingParams memory slashingParams;
uint wadToSlash = _randWadToSlash();
slashingParams = avs.slashOperator(operator, operatorSet.id, strategies, wadToSlash.toArrayU256());
assert_Snap_Allocations_Slashed(slashingParams, operatorSet, true, "operator allocations should be slashed");

uint256[] memory initDelegatableShares = _getWithdrawableShares(staker, strategies);
uint256[] memory initDepositShares = _getStakerDepositShares(staker, strategies);

// Delegate to an operator
staker.delegateTo(operator);
(uint256[] memory delegatedShares, ) = delegationManager.getWithdrawableShares(address(staker), strategies);
check_Delegation_State(staker, operator, strategies, initDepositShares);

// // Undelegate from an operator
// IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate();
// bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals);
// check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, initDepositShares, delegatedShares);

// // 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_Undelegated_State(staker, operator, withdrawals[i], withdrawals[i].strategies, delegatedShares);
// }

// (uint256[] memory withdrawableSharesAfter, uint256[] memory depositSharesAfter) = delegationManager.getWithdrawableShares(address(staker), strategies);
// assertEq(depositSharesAfter[0], delegatedShares[0], "Deposit shares should reset to reflect slash(es)");
// assertApproxEqAbs(withdrawableSharesAfter[0], depositSharesAfter[0], 100, "Withdrawable shares should equal deposit shares after withdrawal");
// }
// Undelegate from an operator
IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.undelegate();
bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals);
check_Undelegate_State(staker, operator, withdrawals, withdrawalRoots, strategies, delegatedShares);

// 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_Undelegated_State(staker, operator, withdrawals[i], withdrawals[i].strategies, delegatedShares);
}

(uint256[] memory withdrawableSharesAfter, uint256[] memory depositSharesAfter) = delegationManager.getWithdrawableShares(address(staker), strategies);
assertEq(depositSharesAfter[0], delegatedShares[0], "Deposit shares should reset to reflect slash(es)");
assertApproxEqAbs(withdrawableSharesAfter[0], depositSharesAfter[0], 100, "Withdrawable shares should equal deposit shares after withdrawal");
}

function testFuzz_delegateSlashedStaker_redelegate_complete(uint24 _random) public rand(_random){

Expand Down
1 change: 0 additions & 1 deletion src/test/integration/tests/SlashingWithdrawals.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ contract Integration_ALMSlashBase is IntegrationCheckUtils {
/// 5. Operator registers for operator set
/// NOTE: Steps 4 and 5 are done in random order, as these should not have an outcome on the test
function _init() internal virtual override {
_configAssetTypes(HOLDS_LST);
(staker, strategies, initTokenBalances) = _newRandomStaker();
operator = _newRandomOperator_NoAssets();
(avs,) = _newRandomAVS();
Expand Down