Skip to content
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

feat: add ejection to the ALM flows for quourms #351

Open
wants to merge 6 commits into
base: feat/slashing-release-branch
Choose a base branch
from
Open
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
35 changes: 35 additions & 0 deletions src/RegistryCoordinator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -480,6 +480,41 @@ contract RegistryCoordinator is
operatorInfo.status == OperatorStatus.REGISTERED && !quorumsToRemove.isEmpty()
&& quorumsToRemove.isSubsetOf(currentBitmap)
) {
// If using operator sets, call out to AllocationManager to eject operator
if (isUsingOperatorSets()) {
// Count non-M2 quorums to size array
uint256 operatorSetIdCount;
for (uint256 i = 0; i < quorumNumbers.length; i++) {
if (!isM2Quorum[uint8(quorumNumbers[i])]) {
operatorSetIdCount++;
}
}

// Get operator sets for quorums being removed
uint32[] memory operatorSetIds = new uint32[](quorumNumbers.length);
uint256 operatorSetIndex = 0;
for (uint256 i = 0; i < quorumNumbers.length; i++) {
if (!isM2Quorum[uint8(quorumNumbers[i])]) {
operatorSetIds[operatorSetIndex] = uint8(quorumNumbers[i]);
operatorSetIndex++;
}
}

assembly {
mstore(operatorSetIds, operatorSetIdCount)
}

IAllocationManagerTypes.DeregisterParams memory params =
IAllocationManagerTypes.DeregisterParams({
operator: operator,
avs: address(serviceManager),
operatorSetIds: operatorSetIds
});
serviceManager.ejectOperators(params);


}

_deregisterOperator({operator: operator, quorumNumbers: quorumNumbers});
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/ServiceManagerBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage {
}));
}

function ejectOperators(IAllocationManagerTypes.DeregisterParams memory params) external onlyRegistryCoordinator {
_allocationManager.deregisterFromOperatorSets(params);
}

/**
* @notice Sets the rewards initiator address
* @param newRewardsInitiator The new rewards initiator address
Expand Down
6 changes: 6 additions & 0 deletions src/interfaces/IServiceManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ interface IServiceManager is IServiceManagerUI {

function slashOperator(IAllocationManagerTypes.SlashingParams memory params) external;

/**
* @notice Ejects operators from operator sets
* @param params The deregistration parameters containing operator address, AVS address and operator set IDs
*/
function ejectOperators(IAllocationManagerTypes.DeregisterParams memory params) external;

// EVENTS
event RewardsInitiatorUpdated(address prevRewardsInitiator, address newRewardsInitiator);
event SlasherUpdated(address prevSlasher, address newSlasher);
Expand Down
1 change: 1 addition & 0 deletions test/mocks/ECDSAServiceManagerMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,5 @@ contract ECDSAServiceManagerMock is ECDSAServiceManagerBase {
function slashOperator(IAllocationManagerTypes.SlashingParams memory params) external override {
// Mock implementation - no actual slashing occurs
}
function ejectOperators(IAllocationManagerTypes.DeregisterParams memory params) external{}
}
125 changes: 56 additions & 69 deletions test/unit/RegistryCoordinatorUnit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2165,69 +2165,6 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT
registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data);
}

function test_registerHook_WithChurn() public {
_deployMockEigenLayerAndAVS(0);
// Enable operator sets first
cheats.prank(registryCoordinatorOwner);
registryCoordinator.enableOperatorSets();

// Create quorum params
IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({
maxOperatorCount: 10,
kickBIPsOfOperatorStake: 1000,
kickBIPsOfTotalStake: 100
});

uint96 minimumStake = 100;
IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1);
strategyParams[0] = IStakeRegistry.StrategyParams({
strategy: IStrategy(address(1)),
multiplier: 10000
});

// Create total delegated stake quorum
cheats.prank(registryCoordinatorOwner);
registryCoordinator.createTotalDelegatedStakeQuorum(
operatorSetParams,
0,
strategyParams
);

uint32[] memory operatorSetIds = new uint32[](1);
operatorSetIds[0] = 0;

string memory socket = "socket";
IBLSApkRegistry.PubkeyRegistrationParams memory params;
// TODO:
// params = IBLSApkRegistry.PubkeyRegistrationParams({
// pubkeyG1: defaultPubKey,
// pubkeyG2: defaultPubKeyG2,
// pubkeySignature: defaultPubKeySignature
// });

IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = new IRegistryCoordinator.OperatorKickParam[](1);
operatorKickParams[0] = IRegistryCoordinator.OperatorKickParam({
operator: address(0x1),
quorumNumber: 0
});

ISignatureUtils.SignatureWithSaltAndExpiry memory churnApproverSignature;
ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature;

bytes memory registerParams = abi.encode(
socket,
params,
operatorKickParams,
churnApproverSignature,
operatorSignature
);

// Prank as allocation manager and call register hook
address allocationManager = address(serviceManager.allocationManager());
cheats.prank(allocationManager);
registryCoordinator.registerOperator(defaultOperator, operatorSetIds, registerParams);
}

function test_updateStakesForQuorum() public {
vm.skip(true);
_deployMockEigenLayerAndAVS(0);
Expand Down Expand Up @@ -2311,7 +2248,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT
cheats.stopPrank();
}

function test_registerHook_Reverts_WhenNotALM() public {
function test_registerHook_Reverts_WhenNotALM() public {

_deployMockEigenLayerAndAVS(0);
// Enable operator sets first
Expand Down Expand Up @@ -2414,12 +2351,62 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT

}

function test_DeregisterHook_Reverts_WhenM2Quorum() public {
vm.skip(true);
}
function test_ejectOperator_fromOperatorSetQuorum() public {
_deployMockEigenLayerAndAVS(0);
cheats.prank(registryCoordinatorOwner);
registryCoordinator.enableOperatorSets();

function test_registerHook_Reverts_WhenM2Quorum() public {
vm.skip(true);
IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({
maxOperatorCount: 10,
kickBIPsOfOperatorStake: 1000,
kickBIPsOfTotalStake: 100
});

uint96 minimumStake = 100;
IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1);
strategyParams[0] = IStakeRegistry.StrategyParams({
strategy: IStrategy(address(1)),
multiplier: 10000
});

cheats.prank(registryCoordinatorOwner);
registryCoordinator.createTotalDelegatedStakeQuorum(
operatorSetParams,
0,
strategyParams
);

// Register operator using operatorSetIds
uint32[] memory operatorSetIds = new uint32[](1);
operatorSetIds[0] = 0;

string memory socket = "socket";
IBLSApkRegistry.PubkeyRegistrationParams memory params;
bytes memory data = abi.encode(socket, params);

address allocationManager = address(serviceManager.allocationManager());
cheats.startPrank(allocationManager);
registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data);
cheats.stopPrank();

// Convert operator set ID to quorum bytes for ejection
bytes memory quorumNumbers = new bytes(1);
quorumNumbers[0] = bytes1(uint8(0)); // Quorum 0

// Set ejector address
address ejector = address(0x123);
cheats.prank(registryCoordinatorOwner);
registryCoordinator.setEjector(ejector);

// Eject operator
/// TODO: Mocked state issue
cheats.prank(ejector);
registryCoordinator.ejectOperator(defaultOperator, quorumNumbers);

// Verify operator is deregistered
IRegistryCoordinator.OperatorInfo memory operatorInfo = registryCoordinator.getOperator(defaultOperator);
assertEq(uint8(operatorInfo.status), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED));
assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0);
}

}
Loading