diff --git a/src/EjectionManager.sol b/src/EjectionManager.sol index ba139977..3ae2ee74 100644 --- a/src/EjectionManager.sol +++ b/src/EjectionManager.sol @@ -74,16 +74,30 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable{ uint32 ejectedOperators; bool ratelimitHit; - for(uint8 j = 0; j < _operatorIds[i].length; ++j) { - uint256 operatorStake = stakeRegistry.getCurrentStake(_operatorIds[i][j], quorumNumber); + if(amountEjectable > 0){ + for(uint8 j = 0; j < _operatorIds[i].length; ++j) { + uint256 operatorStake = stakeRegistry.getCurrentStake(_operatorIds[i][j], quorumNumber); - //if caller is ejector enforce ratelimit - if( - isEjector[msg.sender] && - quorumEjectionParams[quorumNumber].rateLimitWindow > 0 && - stakeForEjection + operatorStake > amountEjectable - ){ - ratelimitHit = true; + //if caller is ejector enforce ratelimit + if( + isEjector[msg.sender] && + quorumEjectionParams[quorumNumber].rateLimitWindow > 0 && + stakeForEjection + operatorStake > amountEjectable + ){ + ratelimitHit = true; + + stakeForEjection += operatorStake; + ++ejectedOperators; + + registryCoordinator.ejectOperator( + registryCoordinator.getOperatorFromId(_operatorIds[i][j]), + abi.encodePacked(quorumNumber) + ); + + emit OperatorEjected(_operatorIds[i][j], quorumNumber); + + break; + } stakeForEjection += operatorStake; ++ejectedOperators; @@ -92,25 +106,13 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable{ registryCoordinator.getOperatorFromId(_operatorIds[i][j]), abi.encodePacked(quorumNumber) ); - + emit OperatorEjected(_operatorIds[i][j], quorumNumber); - - break; } - - stakeForEjection += operatorStake; - ++ejectedOperators; - - registryCoordinator.ejectOperator( - registryCoordinator.getOperatorFromId(_operatorIds[i][j]), - abi.encodePacked(quorumNumber) - ); - - emit OperatorEjected(_operatorIds[i][j], quorumNumber); } //record the stake ejected if ejector and ratelimit enforced - if(isEjector[msg.sender]){ + if(isEjector[msg.sender] && stakeForEjection > 0){ stakeEjectedForQuorum[quorumNumber].push(StakeEjection({ timestamp: block.timestamp, stakeEjected: stakeForEjection diff --git a/test/unit/EjectionManagerUnit.t.sol b/test/unit/EjectionManagerUnit.t.sol index f3d97531..6ec539fc 100644 --- a/test/unit/EjectionManagerUnit.t.sol +++ b/test/unit/EjectionManagerUnit.t.sol @@ -164,6 +164,55 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } + function testEjectOperators_NoEjectionForNoEjectableStake() public { + uint8 operatorsCanEject = 2; + uint8 operatorsToEject = 10; + uint8 numOperators = 10; + uint96 stake = 1 ether; + _registerOperaters(numOperators, stake); + + bytes32[][] memory operatorIds = new bytes32[][](numQuorums); + for (uint8 i = 0; i < numQuorums; i++) { + operatorIds[i] = new bytes32[](operatorsToEject); + for (uint j = 0; j < operatorsToEject; j++) { + operatorIds[i][j] = registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); + } + } + + for(uint8 i = 0; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.REGISTERED)); + } + + for(uint8 i = 0; i < numQuorums; i++) { + for(uint8 j = 0; j < operatorsCanEject; j++) { + cheats.expectEmit(true, true, true, true, address(ejectionManager)); + emit OperatorEjected(operatorIds[i][j], i); + } + } + + cheats.prank(ejector); + ejectionManager.ejectOperators(operatorIds); + + for(uint8 i = 0; i < operatorsCanEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); + } + + for(uint8 i = operatorsCanEject; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.REGISTERED)); + } + + cheats.prank(ejector); + ejectionManager.ejectOperators(operatorIds); + + for(uint8 i = 0; i < operatorsCanEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); + } + + for(uint8 i = operatorsCanEject; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.REGISTERED)); + } + } + function testEjectOperators_MultipleOperatorMultipleTimesInsideRatelimit() public { uint8 operatorsToEject = 4; uint8 numOperators = 100;