-
Notifications
You must be signed in to change notification settings - Fork 109
/
Copy pathRegistryCoordinator.sol
241 lines (213 loc) · 9.4 KB
/
RegistryCoordinator.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol";
import {IAllocationManager} from
"eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
import {IBLSApkRegistry, IBLSApkRegistryTypes} from "./interfaces/IBLSApkRegistry.sol";
import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol";
import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol";
import {IServiceManager} from "./interfaces/IServiceManager.sol";
import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol";
import {ISocketRegistry} from "./interfaces/ISocketRegistry.sol";
import {BitmapUtils} from "./libraries/BitmapUtils.sol";
import {SlashingRegistryCoordinator} from "./SlashingRegistryCoordinator.sol";
import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol";
import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
import {RegistryCoordinatorStorage} from "./RegistryCoordinatorStorage.sol";
/**
* @title A `RegistryCoordinator` that has four registries:
* 1) a `StakeRegistry` that keeps track of operators' stakes
* 2) a `BLSApkRegistry` that keeps track of operators' BLS public keys and aggregate BLS public keys for each quorum
* 3) an `IndexRegistry` that keeps track of an ordered list of operators for each quorum
* 4) a `SocketRegistry` that keeps track of operators' sockets (arbitrary strings)
*
* @author Layr Labs, Inc.
*/
contract RegistryCoordinator is RegistryCoordinatorStorage {
using BitmapUtils for *;
constructor(
IServiceManager _serviceManager,
IStakeRegistry _stakeRegistry,
IBLSApkRegistry _blsApkRegistry,
IIndexRegistry _indexRegistry,
ISocketRegistry _socketRegistry,
IAllocationManager _allocationManager,
IPauserRegistry _pauserRegistry
)
RegistryCoordinatorStorage(
_serviceManager,
_stakeRegistry,
_blsApkRegistry,
_indexRegistry,
_socketRegistry,
_allocationManager,
_pauserRegistry
)
{}
/**
*
* EXTERNAL FUNCTIONS
*
*/
/// @inheritdoc IRegistryCoordinator
function registerOperator(
bytes memory quorumNumbers,
string memory socket,
IBLSApkRegistryTypes.PubkeyRegistrationParams memory params,
SignatureWithSaltAndExpiry memory operatorSignature
) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) {
require(!isM2QuorumRegistrationDisabled, M2QuorumRegistrationIsDisabled());
require(
quorumNumbers.orderedBytesArrayToBitmap().isSubsetOf(m2QuorumBitmap()),
OnlyM2QuorumsAllowed()
);
// Check if the operator has registered before
bool operatorRegisteredBefore =
_operatorInfo[msg.sender].status == OperatorStatus.REGISTERED;
// register the operator with the registry coordinator
_registerOperator({
operator: msg.sender,
operatorId: _getOrCreateOperatorId(msg.sender, params),
quorumNumbers: quorumNumbers,
socket: socket,
checkMaxOperatorCount: true
});
// If the operator has never registered before, register them with the AVSDirectory
if (!operatorRegisteredBefore) {
serviceManager.registerOperatorToAVS(msg.sender, operatorSignature);
}
}
/// @inheritdoc IRegistryCoordinator
function registerOperatorWithChurn(
bytes calldata quorumNumbers,
string memory socket,
IBLSApkRegistryTypes.PubkeyRegistrationParams memory params,
OperatorKickParam[] memory operatorKickParams,
SignatureWithSaltAndExpiry memory churnApproverSignature,
SignatureWithSaltAndExpiry memory operatorSignature
) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) {
require(!isM2QuorumRegistrationDisabled, M2QuorumRegistrationIsDisabled());
require(
quorumNumbers.orderedBytesArrayToBitmap().isSubsetOf(m2QuorumBitmap()),
OnlyM2QuorumsAllowed()
);
// Check if the operator has registered before
bool operatorRegisteredBefore =
_operatorInfo[msg.sender].status == OperatorStatus.REGISTERED;
// register the operator with the registry coordinator with churn
_registerOperatorWithChurn({
operator: msg.sender,
operatorId: _getOrCreateOperatorId(msg.sender, params),
quorumNumbers: quorumNumbers,
socket: socket,
operatorKickParams: operatorKickParams,
churnApproverSignature: churnApproverSignature
});
// If the operator has never registered before, register them with the AVSDirectory
if (!operatorRegisteredBefore) {
serviceManager.registerOperatorToAVS(msg.sender, operatorSignature);
}
}
/// @inheritdoc IRegistryCoordinator
function deregisterOperator(
bytes memory quorumNumbers
) external override onlyWhenNotPaused(PAUSED_DEREGISTER_OPERATOR) {
// Check that the quorum numbers are M2 quorums
require(
quorumNumbers.orderedBytesArrayToBitmap().isSubsetOf(m2QuorumBitmap()),
OnlyM2QuorumsAllowed()
);
_deregisterOperator({operator: msg.sender, quorumNumbers: quorumNumbers});
}
/// @inheritdoc IRegistryCoordinator
function disableM2QuorumRegistration() external onlyOwner {
require(!isM2QuorumRegistrationDisabled, M2QuorumRegistrationIsDisabled());
isM2QuorumRegistrationDisabled = true;
emit M2QuorumRegistrationDisabled();
}
/**
*
* INTERNAL FUNCTIONS
*
*/
/// @dev override the _forceDeregisterOperator function to handle M2 quorum deregistration
function _forceDeregisterOperator(
address operator,
bytes memory quorumNumbers
) internal virtual override {
// filter out M2 quorums from the quorum numbers
uint256 operatorSetBitmap =
quorumNumbers.orderedBytesArrayToBitmap().minus(m2QuorumBitmap());
if (!operatorSetBitmap.isEmpty()) {
// call the parent _forceDeregisterOperator function for operator sets quorums
super._forceDeregisterOperator(operator, operatorSetBitmap.bitmapToBytesArray());
}
}
/// @dev Hook to prevent any new quorums from being created if operator sets are not enabled
function _beforeCreateQuorum(
uint8
) internal virtual override {
// If operator sets are not enabled, set the m2 quorum bitmap to the current m2 quorum bitmap
// and enable operator sets
if (!operatorSetsEnabled) {
_m2QuorumBitmap = m2QuorumBitmap();
operatorSetsEnabled = true;
}
}
/// @dev Hook to allow for any post-deregister logic
function _afterDeregisterOperator(
address operator,
bytes32,
bytes memory,
uint192 newBitmap
) internal virtual override {
// Bitmap representing all quorums including M2 and OperatorSet quorums
uint256 totalQuorumBitmap = _getTotalQuorumBitmap();
// Bitmap representing only OperatorSet quorums. Equal to 0 if operatorSets not enabled
uint256 operatorSetQuorumBitmap = totalQuorumBitmap.minus(m2QuorumBitmap());
// Operators updated M2 quorum bitmap, clear all the bits of operatorSetQuorumBitmap which gives the
// operator's M2 quorum bitmap.
uint256 operatorM2QuorumBitmap = newBitmap.minus(operatorSetQuorumBitmap);
// If the operator is no longer registered for any M2 quorums, update their status and deregister
// them from the AVS via the EigenLayer core contracts
if (operatorM2QuorumBitmap.isEmpty()) {
serviceManager.deregisterOperatorFromAVS(operator);
}
}
/// @notice Return bitmap representing all quorums(Legacy M2 and OperatorSet) quorums
function _getTotalQuorumBitmap() internal view returns (uint256) {
// This creates a number where all bits up to quorumCount are set to 1
// For example:
// quorumCount = 3 -> 0111 (7 in decimal)
// quorumCount = 5 -> 011111 (31 in decimal)
// This is a safe operation since we limit MAX_QUORUM_COUNT to 192
return (1 << quorumCount) - 1;
}
/// @notice Returns true if the quorum number is an M2 quorum
/// @dev We use bitwise and to check if the quorum number is an M2 quorum
function _isM2Quorum(
uint8 quorumNumber
) internal view returns (bool) {
return m2QuorumBitmap().isSet(quorumNumber);
}
/**
*
* VIEW FUNCTIONS
*
*/
/// @dev Returns a bitmap with all bits set up to `quorumCount`. Used for bit-masking quorum numbers
/// and differentiating between operator sets and M2 quorums
function m2QuorumBitmap() public view returns (uint256) {
// If operator sets are enabled, return the current m2 quorum bitmap
if (operatorSetsEnabled) {
return _m2QuorumBitmap;
}
return _getTotalQuorumBitmap();
}
/// @notice Returns true if the quorum number is an M2 quorum
function isM2Quorum(
uint8 quorumNumber
) external view returns (bool) {
return _isM2Quorum(quorumNumber);
}
}