Skip to content

Commit

Permalink
wip slash invariants
Browse files Browse the repository at this point in the history
  • Loading branch information
wadealexc committed Feb 18, 2025
1 parent 38f5faa commit 3203ec4
Show file tree
Hide file tree
Showing 6 changed files with 370 additions and 49 deletions.
222 changes: 217 additions & 5 deletions src/test/integration/IntegrationBase.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import "src/test/integration/users/User_M1.t.sol";
abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
using StdStyle for *;
using SlashingLib for *;
using Math for uint256;
using Strings for *;
using print for *;

Expand Down Expand Up @@ -68,6 +69,35 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
return (staker, strategies, tokenBalances);
}

function _newBasicStaker() internal returns (User, IStrategy[] memory, uint[] memory) {
string memory stakerName;

User staker;
IStrategy[] memory strategies;
uint[] memory tokenBalances;

if (!isUpgraded) {
stakerName = string.concat("M2Staker", cheats.toString(numStakers));

(staker, strategies, tokenBalances) = _randUser(stakerName);

stakersToMigrate.push(staker);
} else {
stakerName = string.concat("staker", cheats.toString(numStakers));

(staker, strategies, tokenBalances) = _randUser(stakerName);
}

assert_HasUnderlyingTokenBalances(staker, strategies, tokenBalances, "_newRandomStaker: failed to award token balances");

numStakers++;
assembly { // TODO HACK
mstore(strategies, 1)
mstore(tokenBalances, 1)
}
return (staker, strategies, tokenBalances);
}

/**
* @dev Create a new operator according to configured random variants.
* This user will immediately deposit their randomized assets into eigenlayer.
Expand Down Expand Up @@ -835,6 +865,21 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
}
}

function assert_Snap_Slashed_SlashableStake(
User operator,
OperatorSet memory operatorSet,
SlashingParams memory params,
string memory err
) internal {
uint[] memory curSlashableStake = _getMinSlashableStake(operator, operatorSet, params.strategies);
uint[] memory prevSlashableStake = _getPrevMinSlashableStake(operator, operatorSet, params.strategies);

for (uint i = 0; i < params.strategies.length; i++) {
uint expectedSlashed = prevSlashableStake[i].mulWadRoundUp(params.wadsToSlash[i]);
assertEq(curSlashableStake[i], prevSlashableStake[i] - expectedSlashed, err);
}
}

function assert_Snap_StakeBecameAllocated(
User operator,
OperatorSet memory operatorSet,
Expand Down Expand Up @@ -877,6 +922,59 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
}
}

function assert_Snap_Slashed_AllocatedStake(
User operator,
OperatorSet memory operatorSet,
SlashingParams memory params,
string memory err
) internal {
uint[] memory curAllocatedStake = _getAllocatedStake(operator, operatorSet, params.strategies);
uint[] memory prevAllocatedStake = _getPrevAllocatedStake(operator, operatorSet, params.strategies);

Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, params.strategies);
Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, params.strategies);

for (uint i = 0; i < curAllocatedStake.length; i++) {
// uint expectedSlashed = prevAllocatedStake[i].mulDiv(params.wadsToSlash[i], WAD, Math.Rounding.Up);
uint actualSlashed = prevAllocatedStake[i] - curAllocatedStake[i];
uint expectedSlashed = prevAllocatedStake[i].mulWadRoundUp(params.wadsToSlash[i]);

emit log_named_uint("prev enc mag ", prevMagnitudes[i].encumbered);
emit log_named_uint("prev max mag ", prevMagnitudes[i].max);

emit log_named_uint("cur enc mag ", curMagnitudes[i].encumbered);
emit log_named_uint("cur max mag ", curMagnitudes[i].max);

emit log("--");

emit log_named_uint("prevStake ", prevAllocatedStake[i]);
emit log_named_uint("curStake ", curAllocatedStake[i]);
emit log_named_uint("opShares ", delegationManager.operatorShares(address(operator), params.strategies[0]));
emit log_named_uint("expected slash ", expectedSlashed);
emit log_named_uint("actual slash ", actualSlashed);
emit log_named_string("eq?", expectedSlashed == actualSlashed ? "true" : "false");

emit log("--");

emit log("eq:");

emit log_named_uint("prevStake ", prevAllocatedStake[i]);
emit log_named_uint("expected + cur ", curAllocatedStake[i] + expectedSlashed);

emit log("eq:");

emit log_named_uint("curStake ", curAllocatedStake[i]);
emit log_named_uint("prev - expected", prevAllocatedStake[i] - expectedSlashed);

emit log("--");

uint res = prevAllocatedStake[i] - expectedSlashed;
emit log_named_string("result eq", res == curAllocatedStake[i] ? "true" : "false");

assertEq(curAllocatedStake[i], prevAllocatedStake[i] - expectedSlashed, err);
}
}

function assert_Snap_Added_EncumberedMagnitude(
User operator,
IStrategy[] memory strategies,
Expand Down Expand Up @@ -918,6 +1016,20 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
}
}

function assert_Snap_Slashed_EncumberedMagnitude(
User operator,
SlashingParams memory params,
string memory err
) internal {
Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, params.strategies);
Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, params.strategies);

for (uint i = 0; i < params.strategies.length; i++) {
uint expectedSlashed = prevMagnitudes[i].encumbered.mulWadRoundUp(params.wadsToSlash[i]);
assertEq(curMagnitudes[i].encumbered, prevMagnitudes[i].encumbered - expectedSlashed, err);
}
}

function assert_Snap_Added_AllocatableMagnitude(
User operator,
IStrategy[] memory strategies,
Expand Down Expand Up @@ -948,14 +1060,14 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
function assert_Snap_Removed_AllocatableMagnitude(
User operator,
IStrategy[] memory strategies,
uint64[] memory magnitudeAllocated,
uint64[] memory magnitudeRemoved,
string memory err
) internal {
Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, strategies);
Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, strategies);

for (uint i = 0; i < strategies.length; i++) {
assertEq(curMagnitudes[i].allocatable, prevMagnitudes[i].allocatable - magnitudeAllocated[i], err);
assertEq(curMagnitudes[i].allocatable, prevMagnitudes[i].allocatable - magnitudeRemoved[i], err);
}
}

Expand Down Expand Up @@ -1009,6 +1121,21 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
}
}

function assert_Snap_Slashed_Allocation(
User operator,
OperatorSet memory operatorSet,
SlashingParams memory params,
string memory err
) internal {
Allocation[] memory curAllocations = _getAllocations(operator, operatorSet, params.strategies);
Allocation[] memory prevAllocations = _getPrevAllocations(operator, operatorSet, params.strategies);

for (uint i = 0; i < params.strategies.length; i++) {
uint expectedSlashed = prevAllocations[i].currentMagnitude.mulWadRoundUp(params.wadsToSlash[i]);
assertEq(curAllocations[i].currentMagnitude, prevAllocations[i].currentMagnitude - expectedSlashed, err);
}
}

function assert_Snap_Unchanged_MaxMagnitude(
User operator,
IStrategy[] memory strategies,
Expand All @@ -1022,6 +1149,20 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
}
}

function assert_Snap_Slashed_MaxMagnitude(
User operator,
SlashingParams memory params,
string memory err
) internal {
Magnitudes[] memory curMagnitudes = _getMagnitudes(operator, params.strategies);
Magnitudes[] memory prevMagnitudes = _getPrevMagnitudes(operator, params.strategies);

for (uint i = 0; i < params.strategies.length; i++) {
uint expectedSlashed = prevMagnitudes[i].max.mulWadRoundUp(params.wadsToSlash[i]);
assertEq(curMagnitudes[i].max, prevMagnitudes[i].max - expectedSlashed, err);
}
}

function assert_Snap_Allocations_Slashed(
SlashingParams memory slashingParams,
OperatorSet memory operatorSet,
Expand Down Expand Up @@ -1193,7 +1334,7 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {

// For each strategy, check (prev - removed == cur)
for (uint i = 0; i < strategies.length; i++) {
assertEq(prevShares[i] - removedShares[i], curShares[i], err);
assertEq(prevShares[i], curShares[i] + removedShares[i], err);
}
}

Expand Down Expand Up @@ -1237,6 +1378,21 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
}
}

function assert_Snap_Slashed_OperatorShares(
User operator,
SlashingParams memory params,
string memory err
) internal {
uint[] memory curShares = _getOperatorShares(operator, params.strategies);
uint[] memory prevShares = _getPrevOperatorShares(operator, params.strategies);

for (uint i = 0; i < params.strategies.length; i++) {
// uint expectedSlashed = prevShares[i].mulDiv(params.wadsToSlash[i], WAD, Math.Rounding.Down);
uint expectedSlashed = prevShares[i].mulWadRoundUp(params.wadsToSlash[i]);
assertEq(curShares[i], prevShares[i] - expectedSlashed, err);
}
}

/*******************************************************************************
SNAPSHOT ASSERTIONS: STAKER SHARES
*******************************************************************************/
Expand Down Expand Up @@ -1773,12 +1929,34 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
Magnitudes[] memory magnitudes = _getMagnitudes(operator, strategies);

for (uint i = 0; i < params.strategies.length; i++) {
IStrategy strategy = params.strategies[i];
uint64 halfAvailable = uint64(magnitudes[i].allocatable) / 2;
params.newMagnitudes[i] = allocations[i].currentMagnitude + halfAvailable;
}
}

/// @dev Generate params to allocate a random portion of available magnitude to each strategy
/// in the operator set. All strategies will have a nonzero allocation, and the minimum allocation
/// will be 10% of available magnitude
function _genAllocation_Rand(
User operator,
OperatorSet memory operatorSet
) internal returns (AllocateParams memory params) {
params.operatorSet = operatorSet;
params.strategies = allocationManager.getStrategiesInOperatorSet(operatorSet);
params.newMagnitudes = new uint64[](params.strategies.length);

Allocation[] memory allocations = _getAllocations(operator, operatorSet, params.strategies);
Magnitudes[] memory magnitudes = _getMagnitudes(operator, params.strategies);

for (uint i = 0; i < params.strategies.length; i++) {
// minimum of 10%, maximum of 100%. increments of 10%.
uint r = _randUint({min: 1, max: 10});
uint64 allocation = uint64(magnitudes[i].allocatable) / uint64(r);

params.newMagnitudes[i] = allocations[i].currentMagnitude + allocation;
}
}

/// @dev Generates params for a half deallocation from all strategies the operator is allocated to in the operator set
function _genDeallocation_HalfRemaining(
User operator,
Expand Down Expand Up @@ -1824,12 +2002,46 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
User operator,
OperatorSet memory operatorSet,
IStrategy[] memory strategies
) internal view returns (AllocateParams memory params) {
) internal pure returns (AllocateParams memory params) {
params.operatorSet = operatorSet;
params.strategies = strategies;
params.newMagnitudes = new uint64[](params.strategies.length);
}

/// Generate random slashing between 1 and 99%
function _genSlashing_Rand(
User operator,
OperatorSet memory operatorSet
) internal returns (SlashingParams memory params) {
params.operator = address(operator);
params.operatorSetId = operatorSet.id;
params.description = "genSlashing_Half";
params.strategies = allocationManager.getStrategiesInOperatorSet(operatorSet).sort();
params.wadsToSlash = new uint[](params.strategies.length);

/// 1% * rand(1, 99)
uint slashWad = 1e16 * _randUint({min: 1, max: 99});

for (uint i = 0; i < params.wadsToSlash.length; i++) {
params.wadsToSlash[i] = slashWad;
}
}

function _genSlashing_Half(
User operator,
OperatorSet memory operatorSet
) internal view returns (SlashingParams memory params) {
params.operator = address(operator);
params.operatorSetId = operatorSet.id;
params.description = "genSlashing_Half";
params.strategies = allocationManager.getStrategiesInOperatorSet(operatorSet).sort();
params.wadsToSlash = new uint[](params.strategies.length);

for (uint i = 0; i < params.wadsToSlash.length; i++) {
params.wadsToSlash[i] = 1e17;
}
}

function _randWadToSlash() internal returns (uint) {
return _randUint({ min: 0.01 ether, max: 1 ether });
}
Expand Down
Loading

0 comments on commit 3203ec4

Please sign in to comment.