Skip to content

test: more slashing integration todos #961

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
18 changes: 18 additions & 0 deletions script/utils/ExistingDeploymentParser.sol
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,24 @@ contract ExistingDeploymentParser is Script, Logger {

eigenLayerProxyAdmin = ProxyAdmin(json.readAddress(".addresses.eigenLayerProxyAdmin"));
eigenLayerPauserReg = PauserRegistry(json.readAddress(".addresses.eigenLayerPauserReg"));

// FIXME: hotfix - remove later...
permissionControllerImplementation = new PermissionController();
permissionController = PermissionController(
address(new TransparentUpgradeableProxy(address(permissionControllerImplementation), address(eigenLayerProxyAdmin), ""))
);

allocationManagerImplementation = new AllocationManager(
delegationManager,
eigenLayerPauserReg,
permissionController,
DEALLOCATION_DELAY,
ALLOCATION_CONFIGURATION_DELAY
);
allocationManager = AllocationManager(
address(new TransparentUpgradeableProxy(address(allocationManagerImplementation), address(eigenLayerProxyAdmin), ""))
);


// // AllocationManager
// allocationManager = AllocationManager(json.readAddress(".addresses.allocationManager"));
Expand Down
68 changes: 59 additions & 9 deletions src/test/integration/IntegrationBase.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ abstract contract IntegrationBase is IntegrationDeployer {
string.concat(err, " (pendingDiff)")
);

delay = DEALLOCATION_DELAY;
delay = DEALLOCATION_DELAY + 1;
}

assertEq(
Expand Down Expand Up @@ -540,6 +540,29 @@ abstract contract IntegrationBase is IntegrationDeployer {
}
}

function assert_Snap_StakerWithdrawableShares_AfterSlash(
User staker,
IAllocationManagerTypes.AllocateParams memory allocateParams,
IAllocationManagerTypes.SlashingParams memory slashingParams,
string memory err
) internal {
uint[] memory curShares = _getWithdrawableShares(staker, allocateParams.strategies);
uint[] memory prevShares = _getPrevWithdrawableShares(staker, allocateParams.strategies);

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

uint256 slashedShares = 0;

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

assertApproxEqAbs(prevShares[i] - slashedShares, curShares[i], 1, err);
}
}

// TODO: slashable stake

/*******************************************************************************
Expand Down Expand Up @@ -809,7 +832,7 @@ abstract contract IntegrationBase is IntegrationDeployer {
uint prevShare = prevShares[i];
uint curShare = curShares[i];

assertEq(prevShare - removedShares[i], curShare, err);
assertApproxEqAbs(prevShare - removedShares[i], curShare, 1, err);
}
}

Expand Down Expand Up @@ -850,7 +873,7 @@ abstract contract IntegrationBase is IntegrationDeployer {
uint prevBalance = prevTokenBalances[i];
uint curBalance = curTokenBalances[i];

assertEq(prevBalance + addedTokens[i], curBalance, err);
assertApproxEqAbs(prevBalance + addedTokens[i], curBalance, 1, err);
}
}

Expand Down Expand Up @@ -1321,14 +1344,33 @@ abstract contract IntegrationBase is IntegrationDeployer {
}

/// @dev Rolls forward by the default allocation delay blocks.
function _rollBlocksForCompleteAllocation() internal {
(, uint32 delay) = allocationManager.getAllocationDelay(address(this));
rollForward({blocks: delay});
function _rollBlocksForCompleteAllocation(
User operator,
OperatorSet memory operatorSet,
IStrategy[] memory strategies
) internal {
uint256 latest;
for (uint i = 0; i < strategies.length; ++i) {
uint effectBlock = allocationManager.getAllocation(address(operator), operatorSet, strategies[i]).effectBlock;
if (effectBlock > latest) latest = effectBlock;
}
cheats.roll(latest + 1);
}

/// @dev Rolls forward by the default deallocation delay blocks.
function _rollBlocksForCompleteDeallocation() internal {
cheats.roll(block.number + allocationManager.DEALLOCATION_DELAY() + 1);
/// @dev Rolls forward by the default allocation delay blocks.
function _rollBlocksForCompleteAllocation(
User operator,
OperatorSet[] memory operatorSets,
IStrategy[] memory strategies
) internal {
uint256 latest;
for (uint i = 0; i < operatorSets.length; ++i) {
for (uint j = 0; j < strategies.length; ++j) {
uint effectBlock = allocationManager.getAllocation(address(operator), operatorSets[i], strategies[j]).effectBlock;
if (effectBlock > latest) latest = effectBlock;
}
}
cheats.roll(latest + 1);
}

/// @dev Uses timewarp modifier to get the operator set strategy allocations at the last snapshot.
Expand Down Expand Up @@ -1528,6 +1570,14 @@ abstract contract IntegrationBase is IntegrationDeployer {
return shares;
}

function _getPrevWithdrawableShares(User staker, IStrategy[] memory strategies) internal timewarp() returns (uint[] memory) {
return _getWithdrawableShares(staker, strategies);
}

function _getWithdrawableShares(User staker, IStrategy[] memory strategies) internal view returns (uint[] memory withdrawableShares) {
(withdrawableShares, ) = delegationManager.getWithdrawableShares(address(staker), strategies);
}

function _getActiveValidatorCount(User staker) internal view returns (uint) {
EigenPod pod = staker.pod();
return pod.activeValidatorCount();
Expand Down
62 changes: 59 additions & 3 deletions src/test/integration/IntegrationChecks.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,8 @@ contract IntegrationCheckUtils is IntegrationBase {
/*******************************************************************************
ALLOCATION MANAGER CHECKS
*******************************************************************************/

// TODO: improvement needed

function check_Withdrawal_AsTokens_State_AfterSlash(
User staker,
Expand All @@ -348,26 +350,80 @@ contract IntegrationCheckUtils is IntegrationBase {
) internal {
IERC20[] memory tokens = new IERC20[](withdrawal.strategies.length);

for (uint256 i; i < withdrawal.strategies.length; i++) {
for (uint i; i < withdrawal.strategies.length; i++) {
IStrategy strat = withdrawal.strategies[i];

bool isBeaconChainETHStrategy = strat == beaconChainETHStrategy;

tokens[i] = isBeaconChainETHStrategy ? NATIVE_ETH : withdrawal.strategies[i].underlyingToken();

if (slashingParams.strategies.contains(strat)) {
uint256 wadToSlash = slashingParams.wadsToSlash[slashingParams.strategies.indexOf(strat)];
uint wadToSlash = slashingParams.wadsToSlash[slashingParams.strategies.indexOf(strat)];

expectedTokens[i] -= expectedTokens[i]
.mulWadRoundUp(allocateParams.newMagnitudes[i].mulWadRoundUp(wadToSlash));

uint256 max = allocationManager.getMaxMagnitude(address(operator), strat);

withdrawal.scaledShares[i] -= withdrawal.scaledShares[i].calcSlashedAmount(WAD, max);

// Round down to the nearest gwei for beaconchain ETH strategy.
if (isBeaconChainETHStrategy) {
expectedTokens[i] -= expectedTokens[i] % 1 gwei;
}
}
}

check_Withdrawal_AsTokens_State(staker, operator, withdrawal, withdrawal.strategies, withdrawal.scaledShares, tokens, expectedTokens);
// 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_StakerDepositShares(staker, "staker shares should not have changed");
assert_Snap_Removed_StrategyShares(withdrawal.strategies, withdrawal.scaledShares, "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");
}
}

function check_Withdrawal_AsShares_State_AfterSlash(
User staker,
User operator,
IDelegationManagerTypes.Withdrawal memory withdrawal,
IAllocationManagerTypes.AllocateParams memory allocateParams,
IAllocationManagerTypes.SlashingParams memory slashingParams
) internal {
IERC20[] memory tokens = new IERC20[](withdrawal.strategies.length);

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

bool isBeaconChainETHStrategy = strat == beaconChainETHStrategy;

tokens[i] = isBeaconChainETHStrategy ? NATIVE_ETH : withdrawal.strategies[i].underlyingToken();

if (slashingParams.strategies.contains(strat)) {
uint256 max = allocationManager.getMaxMagnitude(address(operator), strat);

withdrawal.scaledShares[i] -= withdrawal.scaledShares[i].calcSlashedAmount(WAD, max);
}
}

// Common checks applicable to both user and non-user operator types
assert_WithdrawalNotPending(delegationManager.calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending");
assert_Snap_Unchanged_TokenBalances(staker, "staker should not have any change in underlying token balances");
assert_Snap_Added_Staker_DepositShares(staker, withdrawal.strategies, withdrawal.scaledShares, "staker should have received expected shares");
assert_Snap_Unchanged_StrategyShares(withdrawal.strategies, "strategies should have total shares unchanged");

// Additional checks or handling for the non-user operator scenario
if (operator != User(User(payable(0)))) {
if (operator != staker) {
assert_Snap_Unchanged_TokenBalances(operator, "operator should not have any change in underlying token balances");
}
}
}
}
Loading
Loading