Skip to content

Commit

Permalink
Merge pull request #30 from chainbound/nico/feat/iservicemanager-impl
Browse files Browse the repository at this point in the history
feat(el): impl IServiceManager on the middleware
  • Loading branch information
merklefruit authored Jan 24, 2025
2 parents 561fae0 + 1a975fd commit 13a4890
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 23 deletions.
89 changes: 69 additions & 20 deletions smart-contracts/src/contracts/EigenLayerMiddlewareV1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ contract EigenLayerMiddlewareV1 is OwnableUpgradeable, UUPSUpgradeable, IAVSRegi
address newImplementation
) internal override onlyOwner {}

// ========= modifiers ========= //
// ========= Modifiers ========= //

/// @notice Modifier to check if the caller is the AllocationManager
modifier onlyAllocationManager() {
Expand Down Expand Up @@ -220,15 +220,15 @@ contract EigenLayerMiddlewareV1 is OwnableUpgradeable, UUPSUpgradeable, IAVSRegi
return _strategyWhitelist.wasActiveAt(_now(), strategy);
}

// ========= [pre-slashing only] AVS Registration functions ========= //
// ========= [pre-ELIP-002] IServiceManager functions ========= //

/// @notice Register an operator through the AVS Directory
/// @param rpcEndpoint The RPC URL of the operator
/// @param extraData Arbitrary data the operator can provide as part of registration
/// @param operatorSignature The signature of the operator
/// @dev This function is used before the ELIP-002 (slashing) EigenLayer upgrade to register operators.
/// @dev Operators must use this function to register before the upgrade. After the upgrade, this will be removed.
function registerThroughAVSDirectory(
function registerOperatorToAVS(
string memory rpcEndpoint,
string memory extraData,
ISignatureUtils.SignatureWithSaltAndExpiry calldata operatorSignature
Expand All @@ -244,16 +244,78 @@ contract EigenLayerMiddlewareV1 is OwnableUpgradeable, UUPSUpgradeable, IAVSRegi
/// @notice Deregister an operator through the AVS Directory
/// @dev This function is used before the ELIP-002 (slashing) EigenLayer upgrade to deregister operators.
/// @dev Operators must use this function to deregister before the upgrade. After the upgrade, this will be removed.
function deregisterThroughAVSDirectory() public {
function deregisterOperatorFromAVS() public {
address operator = msg.sender;

require(DELEGATION_MANAGER.isOperator(msg.sender), NotOperator());
require(DELEGATION_MANAGER.isOperator(operator), NotOperator());

AVS_DIRECTORY.deregisterOperatorFromAVS(operator);
OPERATORS_REGISTRY.pauseOperator(msg.sender);
OPERATORS_REGISTRY.pauseOperator(operator);
}

/// @notice Update the metadata URI for this AVS
/// @param contractName The name of the contract to update the metadata URI for
/// @param metadataURI The new metadata URI
function updateAVSMetadataURI(string calldata contractName, string calldata metadataURI) public onlyOwner {
bytes32 contractNameHash = keccak256(abi.encodePacked(contractName));

if (contractNameHash == keccak256("ALLOCATION_MANAGER")) {
ALLOCATION_MANAGER.updateAVSMetadataURI(address(this), metadataURI);
} else if (contractNameHash == keccak256("AVS_DIRECTORY")) {
AVS_DIRECTORY.updateAVSMetadataURI(metadataURI);
}
}

/// @notice Get the strategies that an operator has restaked in
/// @param operator The operator address to get the restaked strategies for
/// @return The restaked strategy addresses
function getOperatorRestakedStrategies(
address operator
) public returns (address[] memory) {
// Only take strategies that are active at <timestamp>
IStrategy[] memory activeStrategies = _getActiveStrategiesAt(_now());

address[] memory restakedStrategies = new address[](activeStrategies.length);

// get the shares of the operator across all strategies
uint256[] memory shares = DELEGATION_MANAGER.getOperatorShares(operator, activeStrategies);

// get the collateral tokens and amounts for the operator across all strategies
uint256 restakedCount = 0;
for (uint256 i = 0; i < activeStrategies.length; i++) {
if (activeStrategies[i].sharesToUnderlyingView(shares[i]) > 0) {
restakedStrategies[restakedCount] = address(activeStrategies[i]);
restakedCount++;
}
}

address[] memory result = new address[](restakedCount);
for (uint256 i = 0; i < restakedCount; i++) {
result[i] = restakedStrategies[i];
}

return result;
}

/// @notice Get the strategies that an operator can restake in
/// @param operator The operator address to get the restakeable strategies for
/// @return The restakeable strategy addresses
function getRestakeableStrategies(
address operator
) public view returns (address[] memory) {
// All operators can use all whitelisted, active strategies.
IStrategy[] memory strategies = getActiveWhitelistedStrategies();

// cast to address[] to match the return type
address[] memory result = new address[](strategies.length);
for (uint256 i = 0; i < strategies.length; i++) {
result[i] = address(strategies[i]);
}

return result;
}

// ========= AVS Registrar functions ========= //
// ========= [post-ELIP-002] IAVSRegistrar functions ========= //

/// @notice Allows the AllocationManager to hook into the middleware to validate operator registration
/// @param operator The address of the operator
Expand Down Expand Up @@ -369,19 +431,6 @@ contract EigenLayerMiddlewareV1 is OwnableUpgradeable, UUPSUpgradeable, IAVSRegi
ALLOCATION_MANAGER.removeStrategiesFromOperatorSet(address(this), operatorSetId, strategies);
}

/// @notice Update the metadata URI for this AVS
/// @param contractName The name of the contract to update the metadata URI for
/// @param metadataURI The new metadata URI
function updateAVSMetadataURI(string calldata contractName, string calldata metadataURI) public onlyOwner {
bytes32 contractNameHash = keccak256(abi.encodePacked(contractName));

if (contractNameHash == keccak256("ALLOCATION_MANAGER")) {
ALLOCATION_MANAGER.updateAVSMetadataURI(address(this), metadataURI);
} else if (contractNameHash == keccak256("AVS_DIRECTORY")) {
AVS_DIRECTORY.updateAVSMetadataURI(metadataURI);
}
}

/// @notice Update the AllocationManager address
/// @param newAllocationManager The new AllocationManager address
function updateAllocationManagerAddress(
Expand Down
16 changes: 14 additions & 2 deletions smart-contracts/test/holesky/EigenLayerMiddlewareV1.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,18 @@ contract EigenLayerMiddlewareV1Test is Test {
// weth should have 100e18 balance
assertEq(collaterals[1], address(holeskyWeth));
assertEq(amounts[1], 100 ether);

// Check the operator's restaked strategies
address[] memory restakedStrategies = middleware.getOperatorRestakedStrategies(operator);
assertEq(restakedStrategies.length, 1);
assertEq(restakedStrategies[0], address(holeskyWethStrategy));
}

function testReadRestakeableStrategies() public view {
address[] memory strategies = middleware.getRestakeableStrategies(operator);
assertEq(strategies.length, 2);
assertEq(strategies[0], address(holeskyStEthStrategy));
assertEq(strategies[1], address(holeskyWethStrategy));
}

function testCannotAddAlreadyWhitelistedStrategy() public {
Expand Down Expand Up @@ -242,7 +254,7 @@ contract EigenLayerMiddlewareV1Test is Test {
middleware.updateAllocationManagerAddress(address(0));

// When the AllocationManager is set to 0x0, the only way to opt-in
// is through the middeware.registerThroughAVSDirectory() method.
// is through the middeware.registerOperatorToAVS() method.

uint32 allocationDelay = 1;
address delegationApprover = address(0x0); // this is optional, skip it
Expand Down Expand Up @@ -276,6 +288,6 @@ contract EigenLayerMiddlewareV1Test is Test {

vm.prank(operator);
vm.expectRevert(EigenLayerMiddlewareV1.NotOperator.selector);
middleware.registerThroughAVSDirectory("http://stopjava.com", "operator1", operatorSignature);
middleware.registerOperatorToAVS("http://stopjava.com", "operator1", operatorSignature);
}
}
2 changes: 1 addition & 1 deletion smart-contracts/test/mainnet/EigenLayerMiddlewareV1.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ contract EigenLayerMiddlewareV1Test is Test {
ISignatureUtils.SignatureWithSaltAndExpiry(operatorRawSignature, bytes32(0), UINT256_MAX);

vm.prank(signer);
middleware.registerThroughAVSDirectory(rpcEndpoint, extraData, operatorSignature);
middleware.registerOperatorToAVS(rpcEndpoint, extraData, operatorSignature);

vm.warp(block.timestamp + 1 days);

Expand Down

0 comments on commit 13a4890

Please sign in to comment.