Skip to content

Commit

Permalink
feat: fix t-26 and t-27
Browse files Browse the repository at this point in the history
  • Loading branch information
ypatil12 committed Feb 21, 2025
1 parent fa4f838 commit b97878a
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 67 deletions.
91 changes: 69 additions & 22 deletions src/test/integration/IntegrationBase.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1312,10 +1312,11 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
/*******************************************************************************
SNAPSHOT ASSERTIONS: BEACON CHAIN AND AVS SLASHING
*******************************************************************************/
//TODO: handle all of these bounds properly

/// @dev Same as above, but when a BC slash occurs before an AVS slash
/// @dev There is additional rounding error when a BC and AVS slash occur together
function assert_Snap_StakerWithdrawableShares_AfterBCAndAVSSlash(
function assert_Snap_StakerWithdrawableShares_AfterBCSlash_AVSSlash(
User staker,
AllocateParams memory allocateParams,
SlashingParams memory slashingParams,
Expand Down Expand Up @@ -1344,9 +1345,8 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
}

/// @dev Validates behavior of "restaking", ie. that the funds can be slashed twice
function assert_Snap_StakerWithdrawableShares_AfterAVSAndBCSlash(
function assert_Snap_StakerWithdrawableShares_AfterAVSSlash_BCSlash(
User staker,
uint256 originalWithdrawableShares,
AllocateParams memory allocateParams,
SlashingParams memory slashingParams,
string memory err
Expand All @@ -1357,32 +1357,79 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {

uint curShares = _getWithdrawableShares(staker, allocateParams.strategies)[0];
uint prevShares = _getPrevWithdrawableShares(staker, allocateParams.strategies)[0];
uint depositShares = _getStakerDepositShares(staker, allocateParams.strategies)[0];

// 1. The withdrawable shares should decrease by a factor of the BCSF
assertApproxEqAbs(prevShares.mulWad(_getBeaconChainSlashingFactor(staker)), curShares, 1, err);

// for (uint i = 0; i < allocateParams.strategies.length; i++) {
// IStrategy strat = allocateParams.strategies[i];

// uint256 avsSlashedShares = 0;

// if (slashingParams.strategies.contains(strat)) {
// uint wadToSlash = slashingParams.wadsToSlash[slashingParams.strategies.indexOf(strat)];
// avsSlashedShares = originalWithdrawableShares.mulWadRoundUp(allocateParams.newMagnitudes[i].mulWadRoundUp(wadToSlash));
// }

// uint256 postAVSSlashShares = originalWithdrawableShares - avsSlashedShares;
assertApproxEqAbs(prevShares.mulWad(_getBeaconChainSlashingFactor(staker)), curShares, 1e3, err);

/**
* 2. The delta in shares is given by:
* (depositShares * operatorMag) - (depositShares * operatorMag * BCSF)
* = depositShares * operatorMag * (1 - BCSF)
*/
uint beaconChainSlashingFactor = _getBeaconChainSlashingFactor(staker);
uint wadToSlash = slashingParams.wadsToSlash[0];
uint originalAVSSlashedShares = depositShares.mulWadRoundUp(allocateParams.newMagnitudes[0].mulWadRoundUp(wadToSlash));
uint withdrawableSharesAfterAVSSlash = depositShares - originalAVSSlashedShares;
uint expectedDelta = withdrawableSharesAfterAVSSlash.mulWad(WAD - beaconChainSlashingFactor);
assertApproxEqAbs(prevShares - expectedDelta, curShares, 1e3, err);

/**
* 3. The attributable avs slashed shares should decrease by a factor of the BCSF
* Attributable avs slashed shares = originalWithdrawableShares - bcSlashedShares - curShares
* Where bcSlashedShares = originalWithdrawableShares * (1 - BCSF)
*/
uint bcSlashedShares = depositShares.mulWad(WAD - beaconChainSlashingFactor);
uint attributableAVSSlashedShares = depositShares - bcSlashedShares - curShares;
assertApproxEqAbs(originalAVSSlashedShares.mulWad(beaconChainSlashingFactor), attributableAVSSlashedShares, 1e3, err);
}

// uint256 expectedDelta = postAVSSlashShares.mulWad(WAD - _getBeaconChainSlashingFactor(staker));
/**
* @dev Validates behavior of "restaking", ie. that the funds can be slashed twice. Also validates
* the edge case where a validator is proven prior to the BC slash.
* @dev TODO: handle the bounds properly
*/
function assert_Snap_StakerWithdrawableShares_AVSSlash_ValidatorProven_BCSlash(
User staker,
uint256 originalWithdrawableShares,
uint256 extraValidatorShares,
AllocateParams memory allocateParams,
SlashingParams memory slashingParams,
string memory err
) internal {
require(allocateParams.strategies.length == 1 && slashingParams.strategies.length == 1, "only beacon strategy supported");
require(allocateParams.strategies[0] == BEACONCHAIN_ETH_STRAT, "only beacon strategy supported");
require(slashingParams.strategies[0] == BEACONCHAIN_ETH_STRAT, "only beacon strategy supported");

// // TODO: bound this better
// assertApproxEqAbs(prevShares[i] - expectedDelta, curShares[i], 1e3, err);
uint curShares = _getWithdrawableShares(staker, allocateParams.strategies)[0];
uint prevShares = _getPrevWithdrawableShares(staker, allocateParams.strategies)[0];

// // Prev shares should decrease by a factor of the BCSF
// assertApproxEqAbs(prevShares[i].mulWad(_getBeaconChainSlashingFactor(staker)), curShares[i], 1e3, err);
// }
// 1. The withdrawable shares should decrease by a factor of the BCSF
assertApproxEqAbs(prevShares.mulWad(_getBeaconChainSlashingFactor(staker)), curShares, 1e4, err);

/**
* 2. The delta in shares is given by:
* (originalWithdrawableShares * operatorMag) + extraValidatorShares - (depositShares * operatorMag * BCSF * dsf)
*/
uint beaconChainSlashingFactor = _getBeaconChainSlashingFactor(staker);
uint wadToSlash = slashingParams.wadsToSlash[0];
uint originalAVSSlashedShares = originalWithdrawableShares.mulWadRoundUp(allocateParams.newMagnitudes[0].mulWadRoundUp(wadToSlash));
uint withdrawableSharesAfterValidatorProven = originalWithdrawableShares - originalAVSSlashedShares + extraValidatorShares;
uint expectedDelta = withdrawableSharesAfterValidatorProven.mulWad(WAD - beaconChainSlashingFactor);
assertApproxEqAbs(prevShares - expectedDelta, curShares, 1e4, err);

/**
* 3. The attributable avs slashed shares should decrease by a factor of the BCSF
* Attributable avs slashed shares = depositShares - bcSlashedShares - curShars
* Where bcSlashedShares = depositShares * (1 - BCSF)
*/
uint depositShares = _getStakerDepositShares(staker, allocateParams.strategies)[0];
uint bcSlashedShares = depositShares.mulWad(WAD - beaconChainSlashingFactor);
uint attributableAVSSlashedShares = depositShares - bcSlashedShares - curShares;
assertApproxEqAbs(originalAVSSlashedShares.mulWad(beaconChainSlashingFactor), attributableAVSSlashedShares, 1e4, err);
}


// TODO: slashable stake

/*******************************************************************************
Expand Down
19 changes: 10 additions & 9 deletions src/test/integration/IntegrationChecks.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -1003,10 +1003,10 @@ contract IntegrationCheckUtils is IntegrationBase {
BC/AVS SLASHING CHECKS
*******************************************************************************/

function check_CompleteCheckPoint_AfterAVSAndBCSlash(
function check_CompleteCheckPoint_AfterAVS_BCSlash(
User staker,
uint40[] memory slashedValidators,
uint256 originalWithdrawableShares,
uint256 depositShares,
uint64 slashedBalanceGwei,
AllocateParams memory allocateParams,
SlashingParams memory slashingParams
Expand All @@ -1017,18 +1017,20 @@ contract IntegrationCheckUtils is IntegrationBase {
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");

// Between the AVS slash and the BC slash, the shares should have decreased by at least the BC slash amount
assert_withdrawableSharesDecreasedByAtLeast(staker, BEACONCHAIN_ETH_STRAT, originalWithdrawableShares, uint256(slashedBalanceGwei * GWEI_TO_WEI), "should have decreased withdrawable shares by at least the BC slash amount");
// From the original shares to the BC slash, the shares should have decreased by at least the BC slash amount
assert_withdrawableSharesDecreasedByAtLeast(staker, BEACONCHAIN_ETH_STRAT, depositShares, uint256(slashedBalanceGwei * GWEI_TO_WEI), "should have decreased withdrawable shares by at least the BC slash amount");

// Calculate the withdrawable shares
assert_Snap_StakerWithdrawableShares_AfterAVSAndBCSlash(staker, originalWithdrawableShares, allocateParams, slashingParams, "should have decreased withdrawable shares correctly");
assert_Snap_StakerWithdrawableShares_AfterAVSSlash_BCSlash(staker, allocateParams, slashingParams, "should have decreased withdrawable shares correctly");
}

function check_CompleteCheckpoint_AfterAVSAndBCSlash_ExtraValidatorProven(
function check_CompleteCheckpoint_AfterAVSSlash_ValidatorProven_BCSlash(
User staker,
uint40[] memory slashedValidators,
uint256 originalWithdrawableShares,
uint64 slashedAmountGwei
uint256 extraValidatorShares,
AllocateParams memory allocateParams,
SlashingParams memory slashingParams
) internal {
// Checkpoint State
check_CompleteCheckpoint_State(staker);
Expand All @@ -1037,7 +1039,6 @@ contract IntegrationCheckUtils is IntegrationBase {
assert_Snap_Removed_ActiveValidators(staker, slashedValidators, "exited validators should each be WITHDRAWN");

// TODO: bound this better
// assert_Snap_StakerWithdrawableShares_AfterAVSAndBCSlash_ExtraValidatorProven(staker, originalWithdrawableShares, allocateParams, slashingParams, "should have decreased withdrawable shares correctly");
// assert_Snap_Removed_Staker_WithdrawableShares_AtLeast(staker, BEACONCHAIN_ETH_STRAT, slashedAmountGwei * GWEI_TO_WEI, 1e11, "should have decreased withdrawable shares by at least slashed amount");
assert_Snap_StakerWithdrawableShares_AVSSlash_ValidatorProven_BCSlash(staker, originalWithdrawableShares, extraValidatorShares, allocateParams, slashingParams, "should have decreased withdrawable shares correctly");
}
}
74 changes: 38 additions & 36 deletions src/test/integration/tests/BC_AVS_Slashing.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ contract Integration_BeaconChain_AVS_Ordering is IntegrationCheckUtils {
staker.startCheckpoint();
check_StartCheckpoint_WithPodBalance_State(staker, beaconBalanceGwei - slashedAmountGwei);
staker.completeCheckpoint();
check_CompleteCheckPoint_AfterAVSAndBCSlash(staker, validators, initDepositShares[0], slashedAmountGwei, allocateParams, slashingParams);
check_CompleteCheckPoint_AfterAVS_BCSlash(staker, validators, initDepositShares[0], slashedAmountGwei, allocateParams, slashingParams);
}

function testFuzz_bcSlash_checkpoint_avsSlash(uint24 _random) public rand(_random) {
Expand All @@ -98,42 +98,44 @@ contract Integration_BeaconChain_AVS_Ordering is IntegrationCheckUtils {
slashingParams = avs.slashOperator(operator, operatorSet.id, strategiesToSlash, wadsToSlash);
assert_Snap_Allocations_Slashed(slashingParams, operatorSet, true, "operator allocations should be slashed");
assert_Snap_Unchanged_Staker_DepositShares(staker, "staker deposit shares should be unchanged after slashing");
assert_Snap_StakerWithdrawableShares_AfterBCAndAVSSlash(staker, allocateParams, slashingParams, "staker withdrawable shares should be slashed");
assert_Snap_StakerWithdrawableShares_AfterBCSlash_AVSSlash(staker, allocateParams, slashingParams, "staker withdrawable shares should be slashed");
}
}

// function testFuzz_avsSlash_verifyValidator_bcSlash_checkpoint(uint24 _random) public rand(_random) {
// // 6. Slash operator by AVS
// SlashingParams memory slashingParams;
// {
// (IStrategy[] memory strategiesToSlash, uint256[] memory wadsToSlash) =
// _randStrategiesAndWadsToSlash(operatorSet);
// console.log("Strategies to slash: %s", strategiesToSlash.length);
// slashingParams = avs.slashOperator(operator, operatorSet.id, strategiesToSlash, wadsToSlash);
// assert_Snap_Allocations_Slashed(slashingParams, operatorSet, true, "operator allocations should be slashed");
// assert_Snap_Unchanged_Staker_DepositShares(staker, "staker deposit shares should be unchanged after slashing");
// assert_Snap_StakerWithdrawableShares_AfterSlash(staker, allocateParams, slashingParams, "staker withdrawable shares should be slashed");
// }

// // 7. Verify Validator
// cheats.deal(address(staker), 32 ether);
// (uint40[] memory newValidators, uint64 addedBeaconBalanceGwei) = staker.startValidators();
// beaconChain.advanceEpoch_NoRewards();
// staker.verifyWithdrawalCredentials(newValidators);
// check_VerifyWC_State(staker, newValidators, addedBeaconBalanceGwei);
// assert_Snap_Added_Staker_WithdrawableSharesAtLeast(staker, BEACONCHAIN_ETH_STRAT.toArray(), uint256(addedBeaconBalanceGwei * GWEI_TO_WEI).toArrayU256(), "staker withdrawable shares should increase by the added beacon balance");

// // 8. Slash first validators on BC
// uint64 slashedAmountGwei = beaconChain.slashValidators(validators);
// beaconChain.advanceEpoch_NoRewards();

// // 9. Checkpoint
// staker.startCheckpoint();
// check_StartCheckpoint_WithPodBalance_State(staker, beaconBalanceGwei - slashedAmountGwei);
// staker.completeCheckpoint();
// check_CompleteCheckpoint_WithAVSAndBCSlashing_HandleRoundDown_State(staker, validators, slashedAmountGwei);
// }
function testFuzz_avsSlash_verifyValidator_bcSlash_checkpoint(uint24 _random) public rand(_random) {
// 6. Slash operator by AVS
SlashingParams memory slashingParams;
{
(IStrategy[] memory strategiesToSlash, uint256[] memory wadsToSlash) =
_randStrategiesAndWadsToSlash(operatorSet);
console.log("Strategies to slash: %s", strategiesToSlash.length);
slashingParams = avs.slashOperator(operator, operatorSet.id, strategiesToSlash, wadsToSlash);
assert_Snap_Allocations_Slashed(slashingParams, operatorSet, true, "operator allocations should be slashed");
assert_Snap_Unchanged_Staker_DepositShares(staker, "staker deposit shares should be unchanged after slashing");
assert_Snap_StakerWithdrawableShares_AfterSlash(staker, allocateParams, slashingParams, "staker withdrawable shares should be slashed");
}

// 7. Verify Validator
cheats.deal(address(staker), 32 ether);
(uint40[] memory newValidators, uint64 addedBeaconBalanceGwei) = staker.startValidators();
uint beaconSharesAdded = uint256(addedBeaconBalanceGwei * GWEI_TO_WEI);
beaconChain.advanceEpoch_NoRewards();
staker.verifyWithdrawalCredentials(newValidators);
check_VerifyWC_State(staker, newValidators, addedBeaconBalanceGwei);
assert_Snap_Added_Staker_WithdrawableSharesAtLeast(staker, BEACONCHAIN_ETH_STRAT.toArray(), beaconSharesAdded.toArrayU256(), "staker withdrawable shares should increase by the added beacon balance");

// 8. Slash first validators on BC
uint64 slashedAmountGwei = beaconChain.slashValidators(validators);
beaconChain.advanceEpoch_NoRewards();

// 9. Checkpoint
staker.startCheckpoint();
check_StartCheckpoint_WithPodBalance_State(staker, beaconBalanceGwei - slashedAmountGwei);
staker.completeCheckpoint();
check_CompleteCheckpoint_AfterAVSSlash_ValidatorProven_BCSlash(staker, validators, initDepositShares[0], beaconSharesAdded, allocateParams, slashingParams);
}

/// @dev Same as above, but validator is proven after BC slash (this ordering doesn't matter) to EL
function testFuzz_avsSlash_bcSlash_verifyValidator_checkpoint(uint24 _random) public rand(_random) {
// 6. Slash operator by AVS
SlashingParams memory slashingParams;
Expand All @@ -154,16 +156,16 @@ contract Integration_BeaconChain_AVS_Ordering is IntegrationCheckUtils {
// 8. Verify Validator
cheats.deal(address(staker), 32 ether);
(uint40[] memory newValidators, uint64 addedBeaconBalanceGwei) = staker.startValidators();
uint beaconSharesAdded = uint256(addedBeaconBalanceGwei * GWEI_TO_WEI);
beaconChain.advanceEpoch_NoRewards();
staker.verifyWithdrawalCredentials(newValidators);
check_VerifyWC_State(staker, newValidators, addedBeaconBalanceGwei);
assert_Snap_Added_Staker_WithdrawableSharesAtLeast(staker, BEACONCHAIN_ETH_STRAT.toArray(), uint256(addedBeaconBalanceGwei * GWEI_TO_WEI).toArrayU256(), "staker withdrawable shares should increase by the added beacon balance");
assert_Snap_Added_Staker_WithdrawableSharesAtLeast(staker, BEACONCHAIN_ETH_STRAT.toArray(), beaconSharesAdded.toArrayU256(), "staker withdrawable shares should increase by the added beacon balance");

// 9. Checkpoint
staker.startCheckpoint();
check_StartCheckpoint_WithPodBalance_State(staker, beaconBalanceGwei - slashedAmountGwei);
staker.completeCheckpoint();
check_CompleteCheckpoint_AfterAVSAndBCSlash_ExtraValidatorProven(staker, validators, initDepositShares[0], slashedAmountGwei);
check_CompleteCheckpoint_AfterAVSSlash_ValidatorProven_BCSlash(staker, validators, initDepositShares[0], beaconSharesAdded, allocateParams, slashingParams);
}

}

0 comments on commit b97878a

Please sign in to comment.