From 0f1a5ca23f5df64a50998282e10b61bc813ca740 Mon Sep 17 00:00:00 2001 From: QUAQ Date: Fri, 5 Jan 2024 13:12:55 -0600 Subject: [PATCH] sm interface --- contracts/lib/eigenlayer-contracts | 2 +- contracts/lib/eigenlayer-middleware | 2 +- contracts/src/Imports.sol | 6 +- contracts/src/core/EigenDAServiceManager.sol | 128 ++++++++++++------ .../src/core/EigenDAServiceManagerStorage.sol | 3 + .../src/interfaces/IEigenDAServiceManager.sol | 2 +- contracts/test/MockRollup.t.sol | 4 +- contracts/test/unit/EigenDABlobUtils.t.sol | 4 +- .../test/unit/EigenDAServiceManagerUnit.t.sol | 8 +- 9 files changed, 102 insertions(+), 57 deletions(-) diff --git a/contracts/lib/eigenlayer-contracts b/contracts/lib/eigenlayer-contracts index 2965deb6c4..8d5058c9c0 160000 --- a/contracts/lib/eigenlayer-contracts +++ b/contracts/lib/eigenlayer-contracts @@ -1 +1 @@ -Subproject commit 2965deb6c4fccbe2e2d98c7502d125d741e26393 +Subproject commit 8d5058c9c08c8d98126cf9a6c4a9d6667a8b962c diff --git a/contracts/lib/eigenlayer-middleware b/contracts/lib/eigenlayer-middleware index 9ec2158332..98f884454d 160000 --- a/contracts/lib/eigenlayer-middleware +++ b/contracts/lib/eigenlayer-middleware @@ -1 +1 @@ -Subproject commit 9ec215833253d9a386cb6e11f26db2929b214186 +Subproject commit 98f884454d9e9de1e344bb6fba9a2cd3915e5b57 diff --git a/contracts/src/Imports.sol b/contracts/src/Imports.sol index 7cd851f9e2..17ea848f2a 100644 --- a/contracts/src/Imports.sol +++ b/contracts/src/Imports.sol @@ -1,5 +1,5 @@ // Imports used for compiling for bindings for clients -import "eigenlayer-middleware/BLSOperatorStateRetriever.sol"; -import "eigenlayer-middleware/BLSPublicKeyCompendium.sol"; -import "eigenlayer-middleware/BLSRegistryCoordinatorWithIndices.sol"; +import "eigenlayer-middleware/OperatorStateRetriever.sol"; +import "eigenlayer-middleware/BLSApkRegistry.sol"; +import "eigenlayer-middleware/RegistryCoordinator.sol"; diff --git a/contracts/src/core/EigenDAServiceManager.sol b/contracts/src/core/EigenDAServiceManager.sol index e8a544266d..48c220ee30 100644 --- a/contracts/src/core/EigenDAServiceManager.sol +++ b/contracts/src/core/EigenDAServiceManager.sol @@ -11,13 +11,17 @@ import {Pausable} from "eigenlayer-core/contracts/permissions/Pausable.sol"; import {IStrategyManager} from "eigenlayer-core/contracts/interfaces/IStrategyManager.sol"; import {ISlasher} from "eigenlayer-core/contracts/interfaces/ISlasher.sol"; import {IPauserRegistry} from "eigenlayer-core/contracts/interfaces/IPauserRegistry.sol"; -import {BLSSignatureChecker, IBLSRegistryCoordinatorWithIndices} from "eigenlayer-middleware/BLSSignatureChecker.sol"; +import {ISignatureUtils} from "eigenlayer-core/contracts/interfaces/ISignatureUtils.sol"; + +import {BLSSignatureChecker, IRegistryCoordinator} from "eigenlayer-middleware/BLSSignatureChecker.sol"; import {IServiceManager} from "eigenlayer-middleware/interfaces/IServiceManager.sol"; +import {IStakeRegistry} from "eigenlayer-middleware/interfaces/IStakeRegistry.sol"; +import {BitmapUtils} from "eigenlayer-middleware/libraries/BitmapUtils.sol"; import {EigenDAServiceManagerStorage} from "./EigenDAServiceManagerStorage.sol"; import {EigenDAHasher} from "../libraries/EigenDAHasher.sol"; -/** +/**b * @title Primary entrypoint for procuring services from EigenDA. * @author Layr Labs, Inc. * @notice This contract is used for: @@ -51,7 +55,7 @@ contract EigenDAServiceManager is Initializable, OwnableUpgradeable, EigenDAServ } constructor( - IBLSRegistryCoordinatorWithIndices _registryCoordinator, + IRegistryCoordinator _registryCoordinator, IStrategyManager _strategyManager, IDelegationManager _delegationMananger, ISlasher _slasher @@ -134,47 +138,35 @@ contract EigenDAServiceManager is Initializable, OwnableUpgradeable, EigenDAServ batchId = batchIdMemory + 1; } - /// @notice Called in the event of challenge resolution, in order to forward a call to the Slasher, which 'freezes' the `operator`. - function freezeOperator(address /*operator*/) external { - revert("EigenDAServiceManager.freezeOperator: not implemented"); - // require( - // msg.sender == address(eigenDAChallenge) - // || msg.sender == address(eigenDABombVerifier), - // "EigenDAServiceManager.freezeOperator: Only challenge resolvers can slash operators" - // ); - // slasher.freezeOperator(operator); - } - /** - * @notice Called by the Registry in the event of a new registration, to forward a call to the Slasher - * @param operator The operator whose stake is being updated - * @param serveUntilBlock The block until which the stake accounted for in the first update is slashable by this middleware - */ - function recordFirstStakeUpdate(address operator, uint32 serveUntilBlock) external onlyRegistryCoordinator { - // slasher.recordFirstStakeUpdate(operator, serveUntilBlock); + * @notice Forwards a call to EigenLayer's DelegationManager contract to confirm operator registration with the AVS + * @param operator The address of the operator to register. + * @param operatorSignature The signature, salt, and expiry of the operator's signature. + */ + function registerOperatorToAVS( + address operator, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external { + delegationManager.registerOperatorToAVS(operator, operatorSignature); } - /** - * @notice Called by the registryCoordinator, in order to forward a call to the Slasher, informing it of a stake update - * @param operator The operator whose stake is being updated - * @param updateBlock The block at which the update is being made - * @param serveUntilBlock The block until which the stake withdrawn from the operator in this update is slashable by this middleware - * @param prevElement The value of the previous element in the linked list of stake updates (generated offchain) + /** + * @notice Forwards a call to EigenLayer's DelegationManager contract to confirm operator deregistration from the AVS + * @param operator The address of the operator to deregister. */ - function recordStakeUpdate(address operator, uint32 updateBlock, uint32 serveUntilBlock, uint256 prevElement) external onlyRegistryCoordinator { - // slasher.recordStakeUpdate(operator, updateBlock, serveUntilBlock, prevElement); + function deregisterOperatorFromAVS(address operator) external { + delegationManager.deregisterOperatorFromAVS(operator); } /** - * @notice Called by the registryCoordinator in the event of deregistration, to forward a call to the Slasher - * @param operator The operator being deregistered - * @param serveUntilBlock The block until which the stake delegated to the operator is slashable by this middleware - */ - function recordLastStakeUpdateAndRevokeSlashingAbility(address operator, uint32 serveUntilBlock) external onlyRegistryCoordinator { - // slasher.recordLastStakeUpdateAndRevokeSlashingAbility(operator, serveUntilBlock); + * @notice Sets the metadata URI for the AVS + * @param _metadataURI is the metadata URI for the AVS + */ + function setMetadataURI(string memory _metadataURI) external onlyOwner() { + metadataURI = _metadataURI; } - // VIEW FUNCTIONS + /// @notice Returns the current batchId function taskNumber() external view returns (uint32) { return batchId; } @@ -184,8 +176,68 @@ contract EigenDAServiceManager is Initializable, OwnableUpgradeable, EigenDAServ return uint32(block.number) + STORE_DURATION_BLOCKS + BLOCK_STALE_MEASURE; } - /// @dev need to override function here since its defined in both these contracts - function owner() public view override(OwnableUpgradeable, IServiceManager) returns (address) { - return OwnableUpgradeable.owner(); + /** + * @notice Returns the list of strategies that the operator has potentially restaked on the AVS + * @param operator The address of the operator to get restaked strategies for + * @dev This function is intended to be called off-chain + * @dev No guarantee is made on whether the operator has shares for a strategy in a quorum or uniqueness + * of each element in the returned array. The off-chain service should do that validation separately + */ + function getOperatorRestakedStrategies(address operator) external view returns (address[] memory) { + bytes32 operatorId = registryCoordinator.getOperatorId(operator); + uint256 quorumBitmap = registryCoordinator.getCurrentQuorumBitmap(operatorId); + bytes memory quorumBytesArray = BitmapUtils.bitmapToBytesArray(quorumBitmap); + + uint256 strategiesLength; + for (uint i = 0; i < quorumBytesArray.length; i++) { + uint8 quorumNumber = uint8(quorumBytesArray[i]); + strategiesLength += stakeRegistry.strategyParamsLength(quorumNumber); + } + + address[] memory restakedStrategies = new address[](strategiesLength); + uint256 index; + for (uint i = 0; i < quorumBytesArray.length; i++) { + uint8 quorumNumber = uint8(quorumBytesArray[i]); + uint256 strategyParamsLength = stakeRegistry.strategyParamsLength(quorumNumber); + for (uint j = 0; j < strategyParamsLength; j++) { + IStakeRegistry.StrategyParams memory strategyParams = stakeRegistry.strategyParamsByIndex(quorumNumber, j); + restakedStrategies[index] = address(strategyParams.strategy); + ++index; + } + } + + return restakedStrategies; + } + + /** + * @notice Returns the list of strategies that the AVS supports for restaking + * @dev This function is intended to be called off-chain + * @dev No guarantee is made on uniqueness of each element in the returned array. + * The off-chain service should do that validabution separately + */ + function getRestakeableStrategies() external view returns (address[] memory) { + uint256 quorumBitmap; + uint256 strategiesLength; + for (uint8 i = 0; i < type(uint8).max; i++) { + if(stakeRegistry.minimumStakeForQuorum(i) > 0) { + quorumBitmap = BitmapUtils.setBit(quorumBitmap, i); + strategiesLength += stakeRegistry.strategyParamsLength(i); + } + } + + bytes memory quorumBytesArray = BitmapUtils.bitmapToBytesArray(quorumBitmap); + address[] memory restakedStrategies = new address[](strategiesLength); + uint256 index; + for (uint i = 0; i < quorumBytesArray.length; i++) { + uint8 quorumNumber = uint8(quorumBytesArray[i]); + uint256 strategyParamsLength = stakeRegistry.strategyParamsLength(quorumNumber); + for (uint j = 0; j < strategyParamsLength; j++) { + IStakeRegistry.StrategyParams memory strategyParams = stakeRegistry.strategyParamsByIndex(quorumNumber, j); + restakedStrategies[index] = address(strategyParams.strategy); + ++index; + } + } + + return restakedStrategies; } } \ No newline at end of file diff --git a/contracts/src/core/EigenDAServiceManagerStorage.sol b/contracts/src/core/EigenDAServiceManagerStorage.sol index 14f7e0c01c..335e8ea104 100644 --- a/contracts/src/core/EigenDAServiceManagerStorage.sol +++ b/contracts/src/core/EigenDAServiceManagerStorage.sol @@ -35,4 +35,7 @@ abstract contract EigenDAServiceManagerStorage is IEigenDAServiceManager { /// @notice mapping between the batchId to the hash of the metadata of the corresponding Batch mapping(uint32 => bytes32) public batchIdToBatchMetadataHash; + + /// @notice metadata URI for the EigenDA AVS + string public metadataURI; } diff --git a/contracts/src/interfaces/IEigenDAServiceManager.sol b/contracts/src/interfaces/IEigenDAServiceManager.sol index bdd3a665ff..5250b90779 100644 --- a/contracts/src/interfaces/IEigenDAServiceManager.sol +++ b/contracts/src/interfaces/IEigenDAServiceManager.sol @@ -10,7 +10,7 @@ import {BN254} from "eigenlayer-middleware/libraries/BN254.sol"; interface IEigenDAServiceManager is IServiceManager, IDelayedService { // EVENTS - /**b + /** * @notice Emitted when a Batch is confirmed. * @param batchHeaderHash The hash of the batch header * @param batchId The ID for the Batch inside of the specified duration (i.e. *not* the globalBatchId) diff --git a/contracts/test/MockRollup.t.sol b/contracts/test/MockRollup.t.sol index d14e791008..c3cf6693ab 100644 --- a/contracts/test/MockRollup.t.sol +++ b/contracts/test/MockRollup.t.sol @@ -69,9 +69,7 @@ contract MockRollupTest is BLSMockAVSDeployer { abi.encodeWithSelector( EigenDAServiceManager.initialize.selector, pauserRegistry, - serviceManagerOwner, - feePerBytePerTime, - serviceManagerOwner + registryCoordinatorOwner ) ) ) diff --git a/contracts/test/unit/EigenDABlobUtils.t.sol b/contracts/test/unit/EigenDABlobUtils.t.sol index 7dbe3fbf81..9bbb2cb64a 100644 --- a/contracts/test/unit/EigenDABlobUtils.t.sol +++ b/contracts/test/unit/EigenDABlobUtils.t.sol @@ -60,9 +60,7 @@ contract EigenDABlobUtilsUnit is BLSMockAVSDeployer { abi.encodeWithSelector( EigenDAServiceManager.initialize.selector, pauserRegistry, - serviceManagerOwner, - feePerBytePerTime, - serviceManagerOwner + registryCoordinatorOwner ) ) ) diff --git a/contracts/test/unit/EigenDAServiceManagerUnit.t.sol b/contracts/test/unit/EigenDAServiceManagerUnit.t.sol index 034742108c..bef1a6d942 100644 --- a/contracts/test/unit/EigenDAServiceManagerUnit.t.sol +++ b/contracts/test/unit/EigenDAServiceManagerUnit.t.sol @@ -47,7 +47,7 @@ contract EigenDAServiceManagerUnit is BLSMockAVSDeployer { abi.encodeWithSelector( EigenDAServiceManager.initialize.selector, pauserRegistry, - serviceManagerOwner + registryCoordinatorOwner ) ) ) @@ -155,12 +155,6 @@ contract EigenDAServiceManagerUnit is BLSMockAVSDeployer { assertEq(eigenDAServiceManager.batchId(), batchIdToConfirm + 1); } - function testFreezeOperator_Revert() public { - cheats.expectRevert(bytes("EigenDAServiceManager.freezeOperator: not implemented")); - eigenDAServiceManager.freezeOperator(address(0)); - } - - function _getHeaderandNonSigners(uint256 _nonSigners, uint256 _pseudoRandomNumber, uint8 _threshold) internal returns (IEigenDAServiceManager.BatchHeader memory, BLSSignatureChecker.NonSignerStakesAndSignature memory) { // register a bunch of operators uint256 quorumBitmap = 1;