Skip to content

Commit be5dd14

Browse files
authored
fix: ejection manager inclusive ejection (#462)
**Motivation:** Per Hexens Eigen2-2, The current rate limit logic allows ejection beyond the allowed limit. **Modifications:** Modify the ejection logic such that when the caller is the ejector, do not automatically eject the first operator regardless of limit. **Result:** Proper rate limit assertions.
1 parent f5adbca commit be5dd14

File tree

2 files changed

+41
-12
lines changed

2 files changed

+41
-12
lines changed

src/EjectionManager.sol

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,6 @@ contract EjectionManager is OwnableUpgradeable, EjectionManagerStorage {
6262
) {
6363
ratelimitHit = true;
6464

65-
stakeForEjection += operatorStake;
66-
++ejectedOperators;
67-
68-
slashingRegistryCoordinator.ejectOperator(
69-
slashingRegistryCoordinator.getOperatorFromId(operatorIds[i][j]),
70-
abi.encodePacked(quorumNumber)
71-
);
72-
73-
emit OperatorEjected(operatorIds[i][j], quorumNumber);
74-
7565
break;
7666
}
7767

test/unit/EjectionManagerUnit.t.sol

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer {
152152
}
153153

154154
function testEjectOperators_MultipleOperatorOutsideRatelimit() public {
155-
uint8 operatorsCanEject = 2;
155+
/// @dev Since the `ejectableStakePercent` is 10%, only 1 operator can be ejected
156+
uint8 operatorsCanEject = 1;
156157
uint8 operatorsToEject = 10;
157158
uint8 numOperators = 10;
158159
uint96 stake = 1 ether;
@@ -199,8 +200,46 @@ contract EjectionManagerUnitTests is MockAVSDeployer {
199200
}
200201
}
201202

203+
/// @dev Regression test for Hexens Slashing EG2-2
204+
/// @dev The quorum ejection params are set to 10%. Previously an operator would have been ejected due to
205+
/// @dev a bug that allowed an ejection to occur if there was at least 1 operator to eject, regardless of the limit.
206+
function testEjectOperators_regression_inclusiveRateLimit() public {
207+
/// @dev The quorum ejection params are set to 10%, which does not need to be updated
208+
uint8 numOperators = 1;
209+
uint96 stake = 1 ether;
210+
211+
_registerOperators(numOperators, stake);
212+
213+
bytes32[][] memory operatorIds = new bytes32[][](numQuorums);
214+
for (uint8 i = 0; i < numQuorums; i++) {
215+
operatorIds[i] = new bytes32[](numOperators);
216+
for (uint256 j = 0; j < numOperators; j++) {
217+
operatorIds[i][j] =
218+
registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j));
219+
}
220+
}
221+
222+
for (uint8 i = 0; i < numOperators; i++) {
223+
assertEq(
224+
uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))),
225+
uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED)
226+
);
227+
}
228+
229+
cheats.prank(ejector);
230+
ejectionManager.ejectOperators(operatorIds);
231+
232+
/// @dev The operator should not be ejected due to the rate limit
233+
for (uint8 i = 0; i < numOperators; i++) {
234+
assertEq(
235+
uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))),
236+
uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED)
237+
);
238+
}
239+
}
240+
202241
function testEjectOperators_NoEjectionForNoEjectableStake() public {
203-
uint8 operatorsCanEject = 2;
242+
uint8 operatorsCanEject = 1;
204243
uint8 operatorsToEject = 10;
205244
uint8 numOperators = 10;
206245
uint96 stake = 1 ether;

0 commit comments

Comments
 (0)