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: enumerable allowlist #172

Merged
merged 1 commit into from
Aug 22, 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
2 changes: 1 addition & 1 deletion contracts/script/CreateAVSRewardsSubmission.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ contract CreateAVSRewardsSubmission is Script {
);

IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions =
new IRewardsCoordinator.RewardsSubmission[](1) ;
new IRewardsCoordinator.RewardsSubmission[](1);

AltLayerInu rewardToken = new AltLayerInu();
uint256 amount = 1000000 ether;
Expand Down
53 changes: 22 additions & 31 deletions contracts/src/core/MachServiceManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -127,39 +127,23 @@ contract MachServiceManager is
// Admin Functions //
//////////////////////////////////////////////////////////////////////////////

/**
* @inheritdoc IMachServiceManager
*/
function allowOperators(address[] calldata operators) external onlyWhitelister {
for (uint256 i; i < operators.length; ++i) {
function setAllowlist(address[] calldata operators, bool[] calldata status) external onlyWhitelister {
require(operators.length == status.length, "Input arrays length mismatch");

for (uint256 i = 0; i < operators.length; ++i) {
address operator = operators[i];

if (operator == address(0)) {
revert ZeroAddress();
}
if (allowlist[operator]) {
revert AlreadyInAllowlist();
}

allowlist[operator] = true;
emit OperatorAllowed(operator);
}
}

/**
* @inheritdoc IMachServiceManager
*/
function disallowOperators(address[] calldata operators) external onlyWhitelister {
for (uint256 i; i < operators.length; ++i) {
address operator = operators[i];

if (!allowlist[operator]) {
revert NotAdded();
if (status[i]) {
_allowlist.add(operator);
} else {
_allowlist.remove(operator);
}

allowlist[operator] = false;
emit OperatorDisallowed(operator);
}
emit AllowlistUpdated(operators, status);
}

/**
Expand Down Expand Up @@ -244,16 +228,13 @@ contract MachServiceManager is
address operator,
ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature
) public override(ServiceManagerBase, IServiceManagerUI) whenNotPaused onlyRegistryCoordinator {
if (allowlistEnabled && !allowlist[operator]) {
if (allowlistEnabled && !isOperatorAllowed(operator)) {
revert NotAdded();
}
// we don't check if this operator has registered or not as AVSDirectory has such checking already
_operators.add(operator);
// Stake requirement for quorum is checked in StakeRegistry.sol
// https://github.com/Layr-Labs/eigenlayer-middleware/blob/dev/src/RegistryCoordinator.sol#L488
// https://github.com/Layr-Labs/eigenlayer-middleware/blob/dev/src/StakeRegistry.sol#L84
_avsDirectory.registerOperatorToAVS(operator, operatorSignature);
emit OperatorAdded(operator);
}

/**
Expand All @@ -265,9 +246,7 @@ contract MachServiceManager is
whenNotPaused
onlyRegistryCoordinator
{
_operators.remove(operator);
_avsDirectory.deregisterOperatorFromAVS(operator);
emit OperatorRemoved(operator);
}

//////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -385,6 +364,18 @@ contract MachServiceManager is
return output;
}

function isOperatorAllowed(address operator) public view returns (bool) {
return _allowlist.contains(operator);
}

function getAllowlistSize() public view returns (uint256) {
return _allowlist.length();
}

function getAllowlistAtIndex(uint256 index) public view returns (address) {
return _allowlist.at(index);
}

//////////////////////////////////////////////////////////////////////////////
// Internal Functions //
//////////////////////////////////////////////////////////////////////////////
Expand Down
16 changes: 8 additions & 8 deletions contracts/src/core/MachServiceManagerStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,10 @@ abstract contract MachServiceManagerStorage {
// Slot 1
mapping(uint256 => EnumerableSet.Bytes32Set) internal _messageHashes;

// Slot 2, 3
/// @notice Ethereum addresses of currently register operators
EnumerableSet.AddressSet internal _operators;

// Slot 4
/// @notice Set of operators that are allowed to register
mapping(address => bool) public allowlist;
// Slot 2, 3, 4
bytes32 private __DEPRECATED_SLOT2;
bytes32 private __DEPRECATED_SLOT3;
bytes32 private __DEPRECATED_SLOT4;

// Slot 5
/// @notice address that is permissioned to confirm alerts
Expand All @@ -50,7 +47,10 @@ abstract contract MachServiceManagerStorage {
/// @notice Role for whitelisting operators
address public whitelister;

/// @notice Set of operators that are allowed to register
EnumerableSet.AddressSet internal _allowlist;

// storage gap for upgradeability
// slither-disable-next-line shadowing-state
uint256[44] private __GAP;
uint256[42] private __GAP;
}
24 changes: 1 addition & 23 deletions contracts/src/interfaces/IMachServiceManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,7 @@ interface IMachServiceManager is IServiceManager {
uint256 rollupChainID;
}

/**
* @notice Emitted when an operator is added to the MachServiceManagerAVS.
* @param operator The address of the operator
*/
event OperatorAdded(address indexed operator);

/**
* @notice Emitted when an operator is removed from the MachServiceManagerAVS.
* @param operator The address of the operator
*/
event OperatorRemoved(address indexed operator);
event AllowlistUpdated(address[] operators, bool[] status);

/**
* @notice Emitted when the alert confirmer is changed.
Expand Down Expand Up @@ -110,18 +100,6 @@ interface IMachServiceManager is IServiceManager {
*/
event AlertRemoved(bytes32 messageHash, address sender);

/**
* @notice Add operators to the allowlist.
* @param operator The operators to add
*/
function allowOperators(address[] calldata operator) external;

/**
* @notice Remove operators from the allowlist.
* @param operator The operators to remove
*/
function disallowOperators(address[] calldata operator) external;

/**
* @notice Enable the allowlist.
*/
Expand Down
95 changes: 31 additions & 64 deletions contracts/test/MachServiceManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import "../src/interfaces/IMachServiceManager.sol";
import "../src/core/MachServiceManager.sol";

contract MachServiceManagerTest is BLSAVSDeployer {
event OperatorAllowed(address operator);
event OperatorDisallowed(address operator);
event AllowlistUpdated(address[] operators, bool[] status);

event AllowlistEnabled();
event AllowlistDisabled();
event AlertConfirmerChanged(address previousAddress, address newAddress);
Expand Down Expand Up @@ -77,79 +77,46 @@ contract MachServiceManagerTest is BLSAVSDeployer {
serviceManager.setWhitelister(address(42));
}

function test_AllowOperators() public {
function test_SetAllowlist() public {
address[] memory operators = new address[](2);
bool[] memory status = new bool[](2);
operators[0] = address(0x102);
operators[1] = address(0x103);
status[0] = true;
status[1] = true;

vm.startPrank(proxyAdminOwner);
address[] memory operators = new address[](1);
operators[0] = defaultOperator;
assertFalse(serviceManager.allowlist(defaultOperator), "mismatch");
vm.expectEmit();
emit OperatorAllowed(defaultOperator);
serviceManager.allowOperators(operators);
assertTrue(serviceManager.allowlist(defaultOperator), "mismatch");
vm.expectEmit(true, true, true, true);
emit AllowlistUpdated(operators, status);
serviceManager.setAllowlist(operators, status);
vm.stopPrank();

assertTrue(serviceManager.isOperatorAllowed(operators[0]));
assertTrue(serviceManager.isOperatorAllowed(operators[1]));
}

function test_AllowOperators_RevertIfNotWhitelister() public {
vm.expectRevert(NotWhitelister.selector);
address[] memory operators = new address[](1);
operators[0] = defaultOperator;
serviceManager.allowOperators(operators);
address[] memory operators = new address[](2);
bool[] memory status = new bool[](2);
operators[0] = address(0x102);
operators[1] = address(0x103);
status[0] = true;
status[1] = true;
serviceManager.setAllowlist(operators, status);
(operators);
}

function test_AllowOperators_RevertIfZeroAddress() public {
vm.startPrank(proxyAdminOwner);
vm.expectRevert(ZeroAddress.selector);
address[] memory operators = new address[](1);
serviceManager.allowOperators(operators);
vm.stopPrank();
}

function test_AllowOperators_RevertIfAlreadyInAllowlist() public {
test_AllowOperators();
vm.startPrank(proxyAdminOwner);
vm.expectRevert(AlreadyInAllowlist.selector);

address[] memory operators = new address[](1);
operators[0] = defaultOperator;
serviceManager.allowOperators(operators);
vm.stopPrank();
}

function test_DisllowOperators() public {
test_AllowOperators();
vm.startPrank(proxyAdminOwner);

address[] memory operators = new address[](1);
operators[0] = defaultOperator;

assertTrue(serviceManager.allowlist(defaultOperator), "Operator should be in allowlist before removal");

vm.expectEmit();
emit OperatorDisallowed(defaultOperator);

serviceManager.disallowOperators(operators);

assertFalse(serviceManager.allowlist(defaultOperator), "Operator should not be in allowlist after removal");
vm.stopPrank();
}

function test_DisllowOperators_RevertIfNotWhitelister() public {
address[] memory operators = new address[](1);
operators[0] = defaultOperator;

vm.expectRevert(NotWhitelister.selector);
serviceManager.disallowOperators(operators);
}

function test_DisllowOperators_RevertIfNotAdded() public {
address[] memory operators = new address[](1);
operators[0] = address(0xdead);

vm.startPrank(proxyAdminOwner);
assertFalse(serviceManager.allowlist(operators[0]), "Operator should not be in allowlist");

vm.expectRevert(NotAdded.selector);
serviceManager.disallowOperators(operators);
address[] memory operators = new address[](2);
bool[] memory status = new bool[](2);
operators[0] = address(0x0);
operators[1] = address(0x103);
status[0] = true;
status[1] = true;
serviceManager.setAllowlist(operators, status);
vm.stopPrank();
}

Expand Down