Skip to content

Commit

Permalink
feat: totalAlerts legacy (#156)
Browse files Browse the repository at this point in the history
* feat: support totalAlerts legacy

* fix: comment typo

---------

Co-authored-by: Jun Hao Tan <[email protected]>
  • Loading branch information
neutiyoo and bb111189 authored Jun 10, 2024
1 parent 8f51821 commit 3742267
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 38 deletions.
23 changes: 16 additions & 7 deletions contracts/src/core/MachServiceManagerRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,26 @@
pragma solidity =0.8.12;

import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
import {IMachServiceManager} from "../interfaces/IMachServiceManager.sol";
import {ITotalAlerts, ITotalAlertsLegacy} from "../interfaces/IMachServiceManager.sol";
import {ZeroAddress, AlreadyAdded, NotAdded} from "../error/Errors.sol";

/// @title MachServiceManagerRegistry
/// @notice This contract allows the owner to register service managers for specific rollup chain IDs and check if they have active alerts.
contract MachServiceManagerRegistry is OwnableUpgradeable {
// Mapping of rollup chain ID to service manager
mapping(uint256 => IMachServiceManager) public serviceManagers;
mapping(uint256 => address) public serviceManagers;

/// @notice Emitted when a service manager is registered
/// @param rollupChainId The rollup chain ID
/// @param serviceManager The registered service manager
/// @param sender The address that registered the service manager
event ServiceManagerRegistered(uint256 indexed rollupChainId, IMachServiceManager serviceManager, address sender);
event ServiceManagerRegistered(uint256 indexed rollupChainId, address serviceManager, address sender);

/// @notice Emitted when a service manager is deregistered
/// @param rollupChainId The rollup chain ID
/// @param serviceManager The deregistered service manager
/// @param sender The address that deregistered the service manager
event ServiceManagerDeregistered(uint256 indexed rollupChainId, IMachServiceManager serviceManager, address sender);
event ServiceManagerDeregistered(uint256 indexed rollupChainId, address serviceManager, address sender);

/// @notice Initializes the contract and sets the deployer as the owner
function initialize() external initializer {
Expand All @@ -39,7 +39,7 @@ contract MachServiceManagerRegistry is OwnableUpgradeable {
/// @param rollupChainId_ The rollup chain ID
/// @param serviceManager_ The service manager to be registered
/// @dev Reverts if the service manager address is zero or already registered
function registerServiceManager(uint256 rollupChainId_, IMachServiceManager serviceManager_) external onlyOwner {
function registerServiceManager(uint256 rollupChainId_, address serviceManager_) external onlyOwner {
if (address(serviceManager_) == address(0)) {
revert ZeroAddress();
}
Expand All @@ -54,7 +54,7 @@ contract MachServiceManagerRegistry is OwnableUpgradeable {
/// @param rollupChainId_ The rollup chain ID
/// @param serviceManager_ The service manager to be deregistered
/// @dev Reverts if the service manager is not already registered
function deregisterServiceManager(uint256 rollupChainId_, IMachServiceManager serviceManager_) external onlyOwner {
function deregisterServiceManager(uint256 rollupChainId_, address serviceManager_) external onlyOwner {
if (serviceManagers[rollupChainId_] != serviceManager_) {
revert NotAdded();
}
Expand All @@ -66,6 +66,15 @@ contract MachServiceManagerRegistry is OwnableUpgradeable {
/// @param rollupChainId_ The rollup chain ID
/// @return True if there are active alerts, false otherwise
function hasActiveAlerts(uint256 rollupChainId_) external view returns (bool) {
return serviceManagers[rollupChainId_].totalAlerts(rollupChainId_) > 0;
address target = serviceManagers[rollupChainId_];
if (target == address(0)) {
return false;
}

try ITotalAlerts(target).totalAlerts(rollupChainId_) returns (uint256 totalAlerts) {
return totalAlerts > 0;
} catch (bytes memory reason) {
return ITotalAlertsLegacy(target).totalAlerts() > 0;
}
}
}
11 changes: 11 additions & 0 deletions contracts/src/interfaces/IMachServiceManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ import {IServiceManager} from "eigenlayer-middleware/interfaces/IServiceManager.
import {BLSSignatureChecker} from "eigenlayer-middleware/BLSSignatureChecker.sol";
import {IMachOptimism} from "../interfaces/IMachOptimism.sol";

interface ITotalAlertsLegacy {
// Legacy
/// @notice Returns the length of total alerts
function totalAlerts() external view returns (uint256);
}

interface ITotalAlerts {
/// @notice Returns the length of total alerts
function totalAlerts(uint256 rollupChainId) external view returns (uint256);
}

/**
* @title Interface for the MachServiceManager contract.
* @author Altlayer, Inc.
Expand Down
111 changes: 80 additions & 31 deletions contracts/test/MachServiceManagerRegistry.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,46 @@ import "../src/interfaces/IMachServiceManager.sol";
import "../src/core/MachServiceManagerRegistry.sol";
import "../src/error/Errors.sol";

contract MockServiceManager is ITotalAlerts {
uint256 public alerts;

function setAlerts(uint256 _alerts) public {
alerts = _alerts;
}

function totalAlerts(uint256) external view override returns (uint256) {
return alerts;
}
}

contract MockServiceManagerLegacy is ITotalAlertsLegacy {
uint256 public alerts;

function setAlerts(uint256 _alerts) public {
alerts = _alerts;
}

function totalAlerts() external view override returns (uint256) {
return alerts;
}
}

contract MachServiceManagerRegistryTest is Test {
MachServiceManagerRegistry registry;
IMachServiceManager mockServiceManager;
MockServiceManager mockServiceManager;
MockServiceManagerLegacy mockServiceManagerLegacy;

event ServiceManagerRegistered(uint256 indexed rollupChainId, IMachServiceManager serviceManager, address sender);
event ServiceManagerDeregistered(uint256 indexed rollupChainId, IMachServiceManager serviceManager, address sender);
event ServiceManagerRegistered(uint256 indexed rollupChainId, address serviceManager, address sender);
event ServiceManagerDeregistered(uint256 indexed rollupChainId, address serviceManager, address sender);

function setUp() public {
// Deploy the registry
registry = new MachServiceManagerRegistry();
registry.initialize();

// Mocking the IMachServiceManager interface
mockServiceManager = IMachServiceManager(address(101));
// Deploy the mock service managers
mockServiceManager = new MockServiceManager();
mockServiceManagerLegacy = new MockServiceManagerLegacy();

// Ensure registry is owned by this test contract for testing purposes
registry.transferOwnership(address(this));
Expand All @@ -30,9 +56,9 @@ contract MachServiceManagerRegistryTest is Test {
uint256 rollupChainId = 1;

vm.expectEmit();
emit ServiceManagerRegistered(rollupChainId, mockServiceManager, address(this));
emit ServiceManagerRegistered(rollupChainId, address(mockServiceManager), address(this));

registry.registerServiceManager(rollupChainId, mockServiceManager);
registry.registerServiceManager(rollupChainId, address(mockServiceManager));

assertEq(
address(registry.serviceManagers(rollupChainId)), address(mockServiceManager), "Service manager mismatch"
Expand All @@ -43,16 +69,16 @@ contract MachServiceManagerRegistryTest is Test {
uint256 rollupChainId = 1;

vm.expectRevert(ZeroAddress.selector);
registry.registerServiceManager(rollupChainId, IMachServiceManager(address(0)));
registry.registerServiceManager(rollupChainId, address(0));
}

function test_RegisterServiceManager_RevertIfAlreadyAdded() public {
uint256 rollupChainId = 1;

registry.registerServiceManager(rollupChainId, mockServiceManager);
registry.registerServiceManager(rollupChainId, address(mockServiceManager));

vm.expectRevert(AlreadyAdded.selector);
registry.registerServiceManager(rollupChainId, mockServiceManager);
registry.registerServiceManager(rollupChainId, address(mockServiceManager));
}

function test_RegisterServiceManager_RevertIfNotOwner() public {
Expand All @@ -62,52 +88,75 @@ contract MachServiceManagerRegistryTest is Test {
registry.transferOwnership(address(0xdead));

vm.expectRevert("Ownable: caller is not the owner");
registry.registerServiceManager(rollupChainId, mockServiceManager);
registry.registerServiceManager(rollupChainId, address(mockServiceManager));
}

function test_HasActiveAlerts() public {
uint256 rollupChainId = 1;

// Mocking the behavior of totalAlerts to return a non-zero value
vm.mockCall(
address(mockServiceManager),
abi.encodeWithSelector(IMachServiceManager.totalAlerts.selector, rollupChainId),
abi.encode(1)
);
// Set alerts to a non-zero value
mockServiceManager.setAlerts(1);

registry.registerServiceManager(rollupChainId, mockServiceManager);
registry.registerServiceManager(rollupChainId, address(mockServiceManager));

bool hasAlerts = registry.hasActiveAlerts(rollupChainId);

assertTrue(hasAlerts, "Expected to have active alerts");
}

function test_HasActiveAlerts_NoServiceManager() public {
bool hasAlerts = registry.hasActiveAlerts(99); // no service manager registerd for the rollup ID 99
assertFalse(hasAlerts, "Expected to have no active alerts");
}

function test_HasActiveAlerts_NoAlerts() public {
uint256 rollupChainId = 1;

// Mocking the behavior of totalAlerts to return zero
vm.mockCall(
address(mockServiceManager),
abi.encodeWithSelector(IMachServiceManager.totalAlerts.selector, rollupChainId),
abi.encode(0)
);
// Set alerts to zero
mockServiceManager.setAlerts(0);

registry.registerServiceManager(rollupChainId, mockServiceManager);
registry.registerServiceManager(rollupChainId, address(mockServiceManager));

bool hasAlerts = registry.hasActiveAlerts(rollupChainId);

assertFalse(hasAlerts, "Expected to have no active alerts");
}

function test_HasActiveAlerts_LegacyAlerts() public {
uint256 rollupChainId = 1;

// Set alerts to a non-zero value (simulating legacy alerts)
mockServiceManagerLegacy.setAlerts(1);

registry.registerServiceManager(rollupChainId, address(mockServiceManagerLegacy));

bool hasAlerts = registry.hasActiveAlerts(rollupChainId);

assertTrue(hasAlerts, "Expected to have active alerts in legacy mode");
}

function test_HasActiveAlerts_LegacyNoAlerts() public {
uint256 rollupChainId = 1;

// Set alerts to zero (simulating no legacy alerts)
mockServiceManagerLegacy.setAlerts(0);

registry.registerServiceManager(rollupChainId, address(mockServiceManagerLegacy));

bool hasAlerts = registry.hasActiveAlerts(rollupChainId);

assertFalse(hasAlerts, "Expected to have no active alerts in legacy mode");
}

function test_DeregisterServiceManager() public {
uint256 rollupChainId = 1;

registry.registerServiceManager(rollupChainId, mockServiceManager);
registry.registerServiceManager(rollupChainId, address(mockServiceManager));

vm.expectEmit();
emit ServiceManagerDeregistered(rollupChainId, mockServiceManager, address(this));
emit ServiceManagerDeregistered(rollupChainId, address(mockServiceManager), address(this));

registry.deregisterServiceManager(rollupChainId, mockServiceManager);
registry.deregisterServiceManager(rollupChainId, address(mockServiceManager));

assertEq(address(registry.serviceManagers(rollupChainId)), address(0), "Service manager should be deregistered");
}
Expand All @@ -116,19 +165,19 @@ contract MachServiceManagerRegistryTest is Test {
uint256 rollupChainId = 1;

vm.expectRevert(NotAdded.selector);
registry.deregisterServiceManager(rollupChainId, mockServiceManager);
registry.deregisterServiceManager(rollupChainId, address(mockServiceManager));
}

function test_DeregisterServiceManager_RevertIfNotOwner() public {
uint256 rollupChainId = 1;

// Register a service manager
registry.registerServiceManager(rollupChainId, mockServiceManager);
registry.registerServiceManager(rollupChainId, address(mockServiceManager));

// Transfer ownership to another address for this test
registry.transferOwnership(address(0xdead));

vm.expectRevert("Ownable: caller is not the owner");
registry.deregisterServiceManager(rollupChainId, mockServiceManager);
registry.deregisterServiceManager(rollupChainId, address(mockServiceManager));
}
}

0 comments on commit 3742267

Please sign in to comment.