Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 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
178 changes: 112 additions & 66 deletions src/ServiceManagerBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ pragma solidity ^0.8.12;
import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol";
import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol";
import {IRewardsCoordinator} from
"eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol";

import {IOperatorSetManager, IStrategy} from "./interfaces/IOperatorSetManager.sol"; // should be later changed to be import from core
import {ServiceManagerBaseStorage} from "./ServiceManagerBaseStorage.sol";
Expand Down Expand Up @@ -76,24 +77,18 @@ abstract contract ServiceManagerBase is OwnableUpgradeable, ServiceManagerBaseSt

/// TODO: natspec
function addStrategiesToOperatorSet(
uint32 operatorSetID,
IStrategy[] calldata strategies
) external onlyStakeRegistry {
_operatorSetManager.addStrategiesToOperatorSet(
operatorSetID,
strategies
);
uint32 operatorSetID,
IStrategy[] calldata strategies
) external onlyStakeRegistry {
_operatorSetManager.addStrategiesToOperatorSet(operatorSetID, strategies);
}

/// TODO: natspec
function removeStrategiesFromOperatorSet(
uint32 operatorSetID,
IStrategy[] calldata strategies
) external onlyStakeRegistry {
_operatorSetManager.removeStrategiesFromOperatorSet(
operatorSetID,
strategies
);
uint32 operatorSetID,
IStrategy[] calldata strategies
) external onlyStakeRegistry {
_operatorSetManager.removeStrategiesFromOperatorSet(operatorSetID, strategies);
}

/// @notice migrates all existing operators and strategies to operator sets
Expand All @@ -112,14 +107,62 @@ abstract contract ServiceManagerBase is OwnableUpgradeable, ServiceManagerBaseSt
strategies[j] = strategy;
}

_operatorSetManager.addStrategiesToOperatorSet(
uint32(i),
strategies
);
_operatorSetManager.addStrategiesToOperatorSet(uint32(i), strategies);
emit OperatorSetStrategiesMigrated(uint32(i), strategies);
}
isStrategiesMigrated = true;
}

/**
* @notice the operator needs to provide a signature over the operatorSetIds they will be registering
* for. This can be called externally by getOperatorSetIds
*/
function migrateOperatorToOperatorSets(
address operator,
ISignatureUtils.SignatureWithSaltAndExpiry memory signature
) external {
require(
!isOperatorMigrated[operator],
"ServiceManagerBase.migrateOperatorToOperatorSets: already migrated"
);
uint32[] memory operatorSetIds = getOperatorSetIds(operator);

_operatorSetManager.registerOperatorToOperatorSets(operator, operatorSetIds, signature);
emit OperatorMigratedToOperatorSets(operator, operatorSetIds);
}

/**
* @notice Once strategies have been migrated and operators have been migrated to operator sets.
* The ServiceManager owner can eject any operators that have yet to completely migrate fully to operator sets.
* This final step of the migration process will ensure the full migration of all operators to operator sets.
* @param operators The list of operators to eject for the given OperatorSet
* @param operatorSet The OperatorSet to eject the operators from
* @dev The RegistryCoordinator MUST set this ServiceManager contract to be the ejector address for this call to succeed
*/
function ejectNonmigratedOperators(
address[] calldata operators,
IOperatorSetManager.OperatorSet calldata operatorSet
) external onlyOwner {
require(
operatorSet.avs == address(this),
"ServiceManagerBase.ejectNonmigratedOperators: operatorSet is not for this AVS"
);
require(
operatorSet.id < _registryCoordinator.quorumCount(),
"ServiceManagerBase.ejectNonmigratedOperators: operatorSet does not exist"
);
for (uint256 i = 0; i < operators.length; ++i) {
require(
!_operatorSetManager.isOperatorInOperatorSet(operators[i], operatorSet),
"ServiceManagerBase.removeNonmigratedOperators: operator already registered to operator set"
);
bytes32 operatorId = _registryCoordinator.getOperatorId(operators[i]);
uint192 quorumBitmap = _registryCoordinator.getCurrentQuorumBitmap(operatorId);
bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap);
_registryCoordinator.ejectOperator(operators[i], quorumNumbers);
}
}

/**
* @notice Updates the metadata URI for the AVS
* @param _metadataURI is the metadata URI for the AVS
Expand All @@ -140,15 +183,15 @@ abstract contract ServiceManagerBase is OwnableUpgradeable, ServiceManagerBaseSt
* @dev This function will revert if the `rewardsSubmission` is malformed,
* e.g. if the `strategies` and `weights` arrays are of non-equal lengths
*/
function createAVSRewardsSubmission(IRewardsCoordinator.RewardsSubmission[] calldata rewardsSubmissions)
public
virtual
onlyRewardsInitiator
{
function createAVSRewardsSubmission(
IRewardsCoordinator.RewardsSubmission[] calldata rewardsSubmissions
) public virtual onlyRewardsInitiator {
for (uint256 i = 0; i < rewardsSubmissions.length; ++i) {
// transfer token to ServiceManager and approve RewardsCoordinator to transfer again
// in createAVSRewardsSubmission() call
rewardsSubmissions[i].token.transferFrom(msg.sender, address(this), rewardsSubmissions[i].amount);
rewardsSubmissions[i].token.transferFrom(
msg.sender, address(this), rewardsSubmissions[i].amount
);
uint256 allowance =
rewardsSubmissions[i].token.allowance(address(this), address(_rewardsCoordinator));
rewardsSubmissions[i].token.approve(
Expand All @@ -172,57 +215,48 @@ abstract contract ServiceManagerBase is OwnableUpgradeable, ServiceManagerBaseSt
}

/**
* @notice Called by this AVS's RegistryCoordinator to register an operator for its registering operatorSets
*
* @param operator the address of the operator to be added to the operator set
* @param quorumNumbers quorums/operatorSetIds to add the operator to
* @param signature the signature of the operator on their intent to register
* @dev msg.sender is used as the AVS
* @dev operator must not have a pending a deregistration from the operator set
* @dev if this is the first operator set in the AVS that the operator is
* registering for, a OperatorAVSRegistrationStatusUpdated event is emitted with
* a REGISTERED status
*/
function registerOperatorToOperatorSets(
address operator,
bytes calldata quorumNumbers,
ISignatureUtils.SignatureWithSaltAndExpiry memory signature
) external onlyRegistryCoordinator {
* @notice Called by this AVS's RegistryCoordinator to register an operator for its registering operatorSets
*
* @param operator the address of the operator to be added to the operator set
* @param quorumNumbers quorums/operatorSetIds to add the operator to
* @param signature the signature of the operator on their intent to register
* @dev msg.sender is used as the AVS
* @dev operator must not have a pending a deregistration from the operator set
* @dev if this is the first operator set in the AVS that the operator is
* registering for, a OperatorAVSRegistrationStatusUpdated event is emitted with
* a REGISTERED status
*/
function registerOperatorToOperatorSets(
address operator,
bytes calldata quorumNumbers,
ISignatureUtils.SignatureWithSaltAndExpiry memory signature
) external onlyRegistryCoordinator {
uint32[] memory operatorSetIds = quorumsToOperatorSetIds(quorumNumbers);
_operatorSetManager.registerOperatorToOperatorSets(
operator,
operatorSetIds,
signature
);
_operatorSetManager.registerOperatorToOperatorSets(operator, operatorSetIds, signature);
}

/**
* @notice Called by this AVS's RegistryCoordinator to deregister an operator for its operatorSets
*
* @param operator the address of the operator to be removed from the
* operator set
* @param quorumNumbers the quorumNumbers/operatorSetIds to deregister the operator for
*
* @dev msg.sender is used as the AVS
* @dev operator must be registered for msg.sender AVS and the given
* operator set
* @notice Called by this AVS's RegistryCoordinator to deregister an operator for its operatorSets
*
* @param operator the address of the operator to be removed from the
* operator set
* @param quorumNumbers the quorumNumbers/operatorSetIds to deregister the operator for
*
* @dev msg.sender is used as the AVS
* @dev operator must be registered for msg.sender AVS and the given
* operator set
* @dev if this removes operator from all operator sets for the msg.sender AVS
* then an OperatorAVSRegistrationStatusUpdated event is emitted with a DEREGISTERED
* status
*/
function deregisterOperatorFromOperatorSets(
address operator,
*/
function deregisterOperatorFromOperatorSets(
address operator,
bytes calldata quorumNumbers
) external onlyRegistryCoordinator {
) external onlyRegistryCoordinator {
uint32[] memory operatorSetIds = quorumsToOperatorSetIds(quorumNumbers);
_operatorSetManager.deregisterOperatorFromOperatorSets(
operator,
operatorSetIds
);
_operatorSetManager.deregisterOperatorFromOperatorSets(operator, operatorSetIds);
}



/**
* @notice Sets the rewards initiator address
* @param newRewardsInitiator The new rewards initiator address
Expand Down Expand Up @@ -310,7 +344,11 @@ abstract contract ServiceManagerBase is OwnableUpgradeable, ServiceManagerBaseSt
}

/// @notice converts the quorumNumbers array to operatorSetIds array
function quorumsToOperatorSetIds(bytes calldata quorumNumbers) internal pure returns (uint32[] memory) {
function quorumsToOperatorSetIds(bytes memory quorumNumbers)
internal
pure
returns (uint32[] memory)
{
uint256 quorumCount = quorumNumbers.length;
uint32[] memory operatorSetIds = new uint32[](quorumCount);
for (uint256 i = 0; i < quorumCount; i++) {
Expand All @@ -319,6 +357,14 @@ abstract contract ServiceManagerBase is OwnableUpgradeable, ServiceManagerBaseSt
return operatorSetIds;
}

/// @notice Returns the operator set IDs for the given operator address by querying the RegistryCoordinator
function getOperatorSetIds(address operator) public view returns (uint32[] memory) {
bytes32 operatorId = _registryCoordinator.getOperatorId(operator);
uint192 operatorBitmap = _registryCoordinator.getCurrentQuorumBitmap(operatorId);
bytes memory operatorQuorums = BitmapUtils.bitmapToBytesArray(operatorBitmap);
return quorumsToOperatorSetIds(operatorQuorums);
}

/// @notice Returns the EigenLayer OperatorSetManager contract.
function operatorSetManager() external view override returns (address) {
return address(_operatorSetManager);
Expand Down
4 changes: 3 additions & 1 deletion src/ServiceManagerBaseStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ abstract contract ServiceManagerBaseStorage is IServiceManager {

bool internal isStrategiesMigrated;

mapping(address => bool) isOperatorMigrated;

/// @notice Sets the (immutable) `_avsDirectory`, `_rewardsCoordinator`, `_registryCoordinator`, and `_stakeRegistry` addresses
constructor(
IOperatorSetManager __operatorSetManager,
Expand All @@ -49,5 +51,5 @@ abstract contract ServiceManagerBaseStorage is IServiceManager {
}

// storage gap for upgradeability
uint256[49] private __GAP;
uint256[47] private __GAP;
}
Loading