Skip to content

Commit c4582a3

Browse files
Feat/operator sets (#579)
* feat: operator set scaffold * fix: impl/storage compile errors; pending updating of tests * chore: `forge fmt` * fix: `OperatorSet` struct misuse * fix: comment * chore: verbose use of `OperatorSet` * test: `registerOperatorToOperatorSet` * feat: `registerOperatorToOperatorSets` Enables registering multiple operator sets in a single call. * chore: `forge fmt` * feat: interface changes * fix: operator set digest * fix: `OPERATOR_SET_REGISTRATION_TYPEHASH` * chore: `forge fmt` * test: wrong avs using signature * fix: optimize for SSTOREs * test: `deregisterOperatorFromOperatorSets` * chore: rename `operatorSetStrategies` * test: `addStrategiesToOperatorSet` * test: `removeStrategiesFromOperatorSet` * test: more coverage * chore: improve natspec * WIP: simp mode * WIP: simp mode * WIP: simp mode - includes interface change, specifically the `StandbyParams` structure. `id` isn't needed for storage. * test: simp mode * test: simp mode * test: simp mode * refactor: simp mode storage * Revert "refactor: simp mode storage" This reverts commit 3b0450e. * Reapply "refactor: simp mode storage" This reverts commit 5f90d78. * feat: simp mode * fix(optimize): salt cancellation - remove check * test: improvements * test: improvements * fix: move `isOperatorSetAVS` update out of loop ooops * fix: standby update typehash * test: cleanup * fix: move mutation out of loop * nit: cleanup * fix: remove unused events --------- Co-authored-by: clandestine.eth <[email protected]>
1 parent b6df4da commit c4582a3

File tree

8 files changed

+927
-122
lines changed

8 files changed

+927
-122
lines changed

script/deploy/devnet/M2_Deploy_From_Scratch.s.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ contract Deployer_M2 is Script, Test {
196196
// Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs
197197
delegationImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager);
198198
strategyManagerImplementation = new StrategyManager(delegation, eigenPodManager, slasher);
199-
avsDirectoryImplementation = new AVSDirectory(delegation);
199+
avsDirectoryImplementation = new AVSDirectory(delegation, strategyManager);
200200
slasherImplementation = new Slasher(strategyManager, delegation);
201201
eigenPodManagerImplementation = new EigenPodManager(
202202
ethPOSDeposit,

script/deploy/holesky/M2_Deploy_From_Scratch.s.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser {
8181
);
8282

8383
eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation));
84-
avsDirectoryImplementation = new AVSDirectory(delegationManager);
84+
avsDirectoryImplementation = new AVSDirectory(delegationManager, strategyManager);
8585
delegationManagerImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager);
8686
strategyManagerImplementation = new StrategyManager(delegationManager, eigenPodManager, slasher);
8787
slasherImplementation = new Slasher(strategyManager, delegationManager);

script/deploy/mainnet/M2_Mainnet_Upgrade.s.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ contract M2_Mainnet_Upgrade is ExistingDeploymentParser {
4545
*/
4646
function _deployImplementationContracts() internal {
4747
// 1. Deploy New TUPS
48-
avsDirectoryImplementation = new AVSDirectory(delegationManager);
48+
avsDirectoryImplementation = new AVSDirectory(delegationManager, strategyManager);
4949
avsDirectory = AVSDirectory(
5050
address(
5151
new TransparentUpgradeableProxy(

src/contracts/core/AVSDirectory.sol

Lines changed: 278 additions & 47 deletions
Large diffs are not rendered by default.

src/contracts/core/AVSDirectoryStorage.sol

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@ pragma solidity ^0.8.12;
44
import "../interfaces/IAVSDirectory.sol";
55
import "../interfaces/IStrategyManager.sol";
66
import "../interfaces/IDelegationManager.sol";
7-
import "../interfaces/ISlasher.sol";
8-
import "../interfaces/IEigenPodManager.sol";
97

108
abstract contract AVSDirectoryStorage is IAVSDirectory {
119
/// @notice The EIP-712 typehash for the contract's domain
@@ -16,31 +14,55 @@ abstract contract AVSDirectoryStorage is IAVSDirectory {
1614
bytes32 public constant OPERATOR_AVS_REGISTRATION_TYPEHASH =
1715
keccak256("OperatorAVSRegistration(address operator,address avs,bytes32 salt,uint256 expiry)");
1816

17+
/// @notice The EIP-712 typehash for the `OperatorSetRegistration` struct used by the contract
18+
bytes32 public constant OPERATOR_SET_REGISTRATION_TYPEHASH =
19+
keccak256("OperatorSetRegistration(address avs,uint32[] operatorSetIds,bytes32 salt,uint256 expiry)");
20+
21+
/// @notice The EIP-712 typehash for the `StandbyParams` struct used by the contract
22+
bytes32 public constant OPERATOR_STANDBY_UPDATE =
23+
keccak256("OperatorStandbyUpdate(StandbyParam[] standbyParams,bytes32 salt,uint256 expiry)");
24+
1925
/// @notice The DelegationManager contract for EigenLayer
2026
IDelegationManager public immutable delegation;
2127

28+
/// @notice The StrategyManager contract for EigenLayer
29+
IStrategyManager public immutable strategyManager;
30+
2231
/**
2332
* @notice Original EIP-712 Domain separator for this contract.
2433
* @dev The domain separator may change in the event of a fork that modifies the ChainID.
2534
* Use the getter function `domainSeparator` to get the current domain separator for this contract.
2635
*/
2736
bytes32 internal _DOMAIN_SEPARATOR;
28-
37+
2938
/// @notice Mapping: AVS => operator => enum of operator status to the AVS
3039
mapping(address => mapping(address => OperatorAVSRegistrationStatus)) public avsOperatorStatus;
3140

3241
/// @notice Mapping: operator => 32-byte salt => whether or not the salt has already been used by the operator.
33-
/// @dev Salt is used in the `registerOperatorToAVS` function.
42+
/// @dev Salt is used in the `registerOperatorToAVS` and `registerOperatorToOperatorSet` function.
3443
mapping(address => mapping(bytes32 => bool)) public operatorSaltIsSpent;
3544

36-
constructor(IDelegationManager _delegation) {
45+
/// @notice Mapping: AVS => whether or not the AVS uses operator set
46+
mapping(address => bool) public isOperatorSetAVS;
47+
48+
/// @notice Mapping: avs => operator => operatorSetID => whether the operator is registered for the operator set
49+
mapping(address => mapping(address => mapping(uint32 => bool))) public isOperatorInOperatorSet;
50+
51+
/// @notice Mapping: avs => operator => number of operator sets the operator is registered for the AVS
52+
mapping(address => mapping(address => uint256)) public operatorAVSOperatorSetCount;
53+
54+
/// @notice Mapping: avs = operator => operatorSetId => Whether the given operator set in standby mode or not
55+
mapping(address => mapping(address => mapping(uint32 => bool))) public onStandby;
56+
57+
constructor(IDelegationManager _delegation, IStrategyManager _strategyManager) {
3758
delegation = _delegation;
59+
strategyManager = _strategyManager;
3860
}
3961

4062
/**
4163
* @dev This empty reserved space is put in place to allow future versions to add new
4264
* variables without shifting down storage in the inheritance chain.
4365
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
4466
*/
45-
uint256[47] private __gap;
67+
uint256[43] private __gap;
4668
}

src/contracts/interfaces/IAVSDirectory.sol

Lines changed: 126 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -2,58 +2,143 @@
22
pragma solidity >=0.5.0;
33

44
import "./ISignatureUtils.sol";
5+
import "./IStrategy.sol";
56

67
interface IAVSDirectory is ISignatureUtils {
7-
/// @notice Enum representing the status of an operator's registration with an AVS
8+
/// @notice Enum representing the registration status of an operator with an AVS.
89
enum OperatorAVSRegistrationStatus {
9-
UNREGISTERED, // Operator not registered to AVS
10-
REGISTERED // Operator registered to AVS
10+
UNREGISTERED, // Operator is not registered with the AVS.
11+
REGISTERED // Operator is registered with the AVS.
12+
13+
}
14+
15+
struct OperatorSet {
16+
address avs;
17+
uint32 id;
18+
}
19+
20+
struct StandbyParam {
21+
OperatorSet operatorSet;
22+
bool onStandby;
1123
}
1224

1325
/**
14-
* @notice Emitted when @param avs indicates that they are updating their MetadataURI string
15-
* @dev Note that these strings are *never stored in storage* and are instead purely emitted in events for off-chain indexing
26+
* @notice Emitted when an operator's registration status with an AVS is updated.
27+
* Specifically, when an operator enters its first operator set for an AVS, or
28+
* when it is removed from the last operator set.
1629
*/
30+
event OperatorAVSRegistrationStatusUpdated(
31+
address indexed operator, address indexed avs, OperatorAVSRegistrationStatus status
32+
);
33+
34+
/// @notice Emitted when an operator is added to an operator set.
35+
event OperatorAddedToOperatorSet(address operator, OperatorSet operatorSet);
36+
37+
/// @notice Emitted when an operator is removed from an operator set.
38+
event OperatorRemovedFromOperatorSet(address operator, OperatorSet operatorSet);
39+
40+
/// @notice Emitted when an AVS updates their metadata URI (Uniform Resource Identifier).
41+
/// @dev The URI is never stored; it is simply emitted through an event for off-chain indexing.
1742
event AVSMetadataURIUpdated(address indexed avs, string metadataURI);
1843

19-
/// @notice Emitted when an operator's registration status for an AVS is updated
20-
event OperatorAVSRegistrationStatusUpdated(address indexed operator, address indexed avs, OperatorAVSRegistrationStatus status);
44+
/// @notice Emitted when an operator updates their standby parameters.
45+
event StandbyParamUpdated(address operator, OperatorSet operatorSet, bool onStandby);
2146

2247
/**
23-
* @notice Called by an avs to register an operator with the avs.
24-
* @param operator The address of the operator to register.
25-
* @param operatorSignature The signature, salt, and expiry of the operator's signature.
48+
* @notice Updates the standby parameters for an operator across multiple operator sets.
49+
* Allows the AVS to add the operator to a given operator set if they are not already registered.
50+
*
51+
* @param operator The address of the operator for which the standby parameters are being updated.
52+
* @param standbyParams The new standby parameters for the operator.
53+
* @param signature If non-empty, the signature of the operator authorizing the modification.
54+
* If empty, the `msg.sender` must be the operator.
55+
*/
56+
function updateStandbyParams(
57+
address operator,
58+
StandbyParam[] calldata standbyParams,
59+
SignatureWithSaltAndExpiry calldata signature
60+
) external;
61+
62+
/**
63+
* @notice Called by the AVS's service manager contract to register an operator with the AVS.
64+
*
65+
* @param operator The address of the operator to register.
66+
* @param operatorSignature The signature, salt, and expiry of the operator's signature.
67+
*
68+
* @dev msg.sender must be the AVS.
69+
* @dev Only used by legacy M2 AVSs that have not integrated with operator sets.
2670
*/
2771
function registerOperatorToAVS(
2872
address operator,
2973
ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature
3074
) external;
3175

3276
/**
33-
* @notice Called by an avs to deregister an operator with the avs.
34-
* @param operator The address of the operator to deregister.
77+
* @notice Called by an AVS to deregister an operator from the AVS.
78+
*
79+
* @param operator The address of the operator to deregister.
80+
*
81+
* @dev Only used by legacy M2 AVSs that have not integrated with operator sets.
3582
*/
3683
function deregisterOperatorFromAVS(address operator) external;
3784

3885
/**
39-
* @notice Called by an AVS to emit an `AVSMetadataURIUpdated` event indicating the information has updated.
40-
* @param metadataURI The URI for metadata associated with an AVS
41-
* @dev Note that the `metadataURI` is *never stored * and is only emitted in the `AVSMetadataURIUpdated` event
86+
* @notice Called by AVSs to add an operator to an operator set.
87+
*
88+
* @param operator The address of the operator to be added to the operator set.
89+
* @param operatorSetIds The IDs of the operator sets.
90+
* @param signature The signature of the operator on their intent to register.
91+
*
92+
* @dev msg.sender is used as the AVS.
93+
* @dev The operator must not have a pending deregistration from the operator set.
94+
* @dev If this is the first operator set in the AVS that the operator is
95+
* registering for, a OperatorAVSRegistrationStatusUpdated event is emitted with
96+
* a REGISTERED status.
97+
*/
98+
function registerOperatorToOperatorSets(
99+
address operator,
100+
uint32[] calldata operatorSetIds,
101+
ISignatureUtils.SignatureWithSaltAndExpiry memory signature
102+
) external;
103+
104+
/**
105+
* @notice Called by AVSs or operators to remove an operator from an operator set.
106+
*
107+
* @param operator The address of the operator to be removed from the operator set.
108+
* @param operatorSetIds The IDs of the operator sets.
109+
*
110+
* @dev msg.sender is used as the AVS.
111+
* @dev The operator must be registered for the msg.sender AVS and the given operator set.
112+
* @dev If this removes the operator from all operator sets for the msg.sender AVS,
113+
* then an OperatorAVSRegistrationStatusUpdated event is emitted with a DEREGISTERED status.
114+
*/
115+
function deregisterOperatorFromOperatorSets(address operator, uint32[] calldata operatorSetIds) external;
116+
117+
// VIEW
118+
119+
/**
120+
* @notice Called by an AVS to emit an `AVSMetadataURIUpdated` event indicating the information has updated.
121+
*
122+
* @param metadataURI The URI for metadata associated with an AVS.
123+
*
124+
* @dev Note that the `metadataURI` is *never stored* and is only emitted in the `AVSMetadataURIUpdated` event.
42125
*/
43126
function updateAVSMetadataURI(string calldata metadataURI) external;
44127

45128
/**
46-
* @notice Returns whether or not the salt has already been used by the operator.
47-
* @dev Salts is used in the `registerOperatorToAVS` function.
129+
* @notice Returns whether the salt has already been used by the operator or not.
130+
*
131+
* @dev The salt is used in the `registerOperatorToAVS` function.
48132
*/
49133
function operatorSaltIsSpent(address operator, bytes32 salt) external view returns (bool);
50134

51135
/**
52-
* @notice Calculates the digest hash to be signed by an operator to register with an AVS
53-
* @param operator The account registering as an operator
54-
* @param avs The AVS the operator is registering to
55-
* @param salt A unique and single use value associated with the approver signature.
56-
* @param expiry Time after which the approver's signature becomes invalid
136+
* @notice Calculates the digest hash to be signed by an operator to register with an AVS.
137+
*
138+
* @param operator The account registering as an operator.
139+
* @param avs The AVS the operator is registering with.
140+
* @param salt A unique and single-use value associated with the approver's signature.
141+
* @param expiry The time after which the approver's signature becomes invalid.
57142
*/
58143
function calculateOperatorAVSRegistrationDigestHash(
59144
address operator,
@@ -62,6 +147,24 @@ interface IAVSDirectory is ISignatureUtils {
62147
uint256 expiry
63148
) external view returns (bytes32);
64149

65-
/// @notice The EIP-712 typehash for the Registration struct used by the contract
150+
/**
151+
* @notice Calculates the digest hash to be signed by an operator to register with an operator set.
152+
*
153+
* @param avs The AVS that operator is registering to operator sets for.
154+
* @param operatorSetIds An array of operator set IDs the operator is registering to.
155+
* @param salt A unique and single use value associated with the approver signature.
156+
* @param expiry Time after which the approver's signature becomes invalid.
157+
*/
158+
function calculateOperatorSetRegistrationDigestHash(
159+
address avs,
160+
uint32[] memory operatorSetIds,
161+
bytes32 salt,
162+
uint256 expiry
163+
) external view returns (bytes32);
164+
165+
/// @notice The EIP-712 typehash for the Registration struct used by the contract.
66166
function OPERATOR_AVS_REGISTRATION_TYPEHASH() external view returns (bytes32);
167+
168+
/// @notice The EIP-712 typehash for the OperatorSetRegistration struct used by the contract.
169+
function OPERATOR_SET_REGISTRATION_TYPEHASH() external view returns (bytes32);
67170
}

src/test/integration/IntegrationDeployer.t.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser {
270270
delegationManager
271271
);
272272
delayedWithdrawalRouterImplementation = new DelayedWithdrawalRouter(eigenPodManager);
273-
avsDirectoryImplementation = new AVSDirectory(delegationManager);
273+
avsDirectoryImplementation = new AVSDirectory(delegationManager, strategyManager);
274274

275275
// Third, upgrade the proxy contracts to point to the implementations
276276
uint256 withdrawalDelayBlocks = 7 days / 12 seconds;
@@ -408,7 +408,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser {
408408
delegationManager
409409
);
410410
delayedWithdrawalRouterImplementation = new DelayedWithdrawalRouter(eigenPodManager);
411-
avsDirectoryImplementation = new AVSDirectory(delegationManager);
411+
avsDirectoryImplementation = new AVSDirectory(delegationManager, strategyManager);
412412

413413
// Second, upgrade the proxy contracts to point to the implementations
414414
// DelegationManager
@@ -518,7 +518,7 @@ abstract contract IntegrationDeployer is ExistingDeploymentParser {
518518
delegationManager
519519
);
520520
delayedWithdrawalRouterImplementation = new DelayedWithdrawalRouter(eigenPodManager);
521-
avsDirectoryImplementation = new AVSDirectory(delegationManager);
521+
avsDirectoryImplementation = new AVSDirectory(delegationManager, strategyManager);
522522

523523
// Second, upgrade the proxy contracts to point to the implementations
524524
// DelegationManager

0 commit comments

Comments
 (0)