Skip to content

Commit b1f5f47

Browse files
authored
chore: KeyRegistrar clarifications (#1551)
**Motivation:** Docs were out of date in some places. Redundant functions were present **Modifications:** - Clarify docs/natspec - Remove `checkKey` in favor of `isKeyRegistered` - Remove old test file - Add sequence diagrams - Add documentation on errors/events **Result:** Cleaner code
1 parent c5b3b8d commit b1f5f47

File tree

5 files changed

+74
-980
lines changed

5 files changed

+74
-980
lines changed

docs/permissions/KeyRegistrar.md

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Keys are stored in a 2-way mapping:
1414
1. (operator, operatorSet) to key
1515
2. keyHash to operator address
1616

17+
See [usage patterns](#usage-patterns) below on user flows.
18+
1719
---
1820

1921
## Operator Set Configuration
@@ -59,10 +61,12 @@ Key registration is segmented by curve type: ECDSA and BN254.
5961
* @notice Registers a cryptographic key for an operator with a specific operator set
6062
* @param operator Address of the operator to register key for
6163
* @param operatorSet The operator set to register the key for
62-
* @param pubkey Public key bytes
63-
* @param signature Signature proving ownership (only needed for BN254 keys)
64+
* @param pubkey Public key bytes. For ECDSA, this is the address of the key. For BN254, this is the G1 and G2 key combined (see `encodeBN254KeyData`)
65+
* @param signature Signature proving ownership. For ECDSA this is a signature of the `getECDSAKeyRegistrationMessageHash`. For BN254 this is a signature of the `getBN254KeyRegistrationMessageHash`.
6466
* @dev Can be called by operator directly or by addresses they've authorized via PermissionController
6567
* @dev Reverts if key is already registered
68+
* @dev There exist no restriction on the state of the operator with respect to the operatorSet. That is, an operator
69+
* does not have to be registered for the operator in the `AllocationManager` to register a key for it
6670
*/
6771
function registerKey(
6872
address operator,
@@ -72,11 +76,11 @@ function registerKey(
7276
) external;
7377
```
7478

75-
There are restrictions on the state of the operator with respect to the operatorSet. That is, an operator does not have to be registered for the operator in the `AllocationManager` to register a key for it.
79+
There ARE NO restrictions on the state of the operator with respect to the operatorSet. That is, an operator does not have to be registered for the operator in the `AllocationManager` to register a key for it.
7680

7781
For ECDSA keys:
7882
- `pubkey`: 20 bytes representing the Ethereum address
79-
- `signature`: EIP-712 signature from the key's private key
83+
- `signature`: EIP-712 signature from the key's private key. Signature is over [`getECDSAKeyRegistrationMessageHash`](#getecdsakeyregistrationmessagehash)
8084

8185
*Effects*:
8286
* Registers the key for the operator in the specified operator set
@@ -201,7 +205,7 @@ Returns the message hash that must be signed over for BN254 key registration.
201205
* @notice Deregisters a cryptographic key for an operator with a specific operator set
202206
* @param operator Address of the operator to deregister key for
203207
* @param operatorSet The operator set to deregister the key from
204-
* @dev Can be called by avs directly or by addresses they've authorized via PermissionController
208+
* @dev Can be called by operator directly or by addresses they've authorized via PermissionController
205209
* @dev Reverts if key was not registered
206210
* @dev Keys remain in global key registry to prevent reuse
207211
*/
@@ -216,9 +220,46 @@ Removes an operator's key from the specified operator set. Note that the key rem
216220
* The key remains in the global registry
217221

218222
*Requirements*:
219-
* Caller MUST be authorized for the AVS (via PermissionController)
223+
* Caller MUST be authorized for the operator (via PermissionController)
220224
* The operator MUST not be slashable for the AVS, to prevent off-chain race conditions
221225
* The operator set MUST be configured
222226
* The operator MUST have a registered key for this operator set
223227

224228
---
229+
230+
## Usage patterns
231+
The `KeyRegistrar` introduces new operator/avs registration patterns. Note that these registration patterns are **only for AVSs who have opted to use the new [middlewareV2](https://github.com/Layr-Labs/eigenlayer-middleware/tree/dev/docs/middlewareV2) contract architecture.**
232+
233+
### Operator/AVS Registration
234+
235+
```mermaid
236+
sequenceDiagram
237+
participant OP as Operator
238+
participant KR as KeyRegistrar
239+
participant AM as AllocationManager
240+
participant AVR as AVSRegistrar
241+
242+
OP->>KR: Tx1: registerKey
243+
OP->>AM: Tx2: registerForOperatorSets
244+
AM-->>AVR: registerForOperatorSets
245+
AVR-->>KR: isRegistered
246+
```
247+
248+
249+
### Deregistration/Key Rotation
250+
251+
Deregistration takes a dependency on the `AllocationManager`. In particular, operators are only allowed to deregister their key from an operatorSet if they are not slashable by said operatorSet.
252+
253+
To rotate a key, an operator must deregister from the operatorSet, wait until it is not slashable, deregister its key, and then register a new key. If the operator was not slashable, it can rotate its key without a delay.
254+
255+
```mermaid
256+
sequenceDiagram
257+
participant OP as Operator
258+
participant AM as AllocationManager
259+
participant KR as KeyRegistrar
260+
261+
OP->>AM: Tx1: deregisterFromOperatorSets
262+
Note over OP: Wait 14 days<br>(if previously allocated)
263+
OP->>KR: Tx2: deregisterKey
264+
OP->>KR: Tx3: registerKey
265+
```

src/contracts/interfaces/IKeyRegistrar.sol

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,25 @@ import {BN254} from "../libraries/BN254.sol";
66
import "./ISemVerMixin.sol";
77

88
interface IKeyRegistrarErrors {
9-
/// Key Management
9+
/// @notice Error thrown when a key is already registered
1010
error KeyAlreadyRegistered();
11+
/// @notice Error thrown when the key format is invalid
1112
error InvalidKeyFormat();
13+
/// @notice Error thrown when the address is zero
1214
error ZeroAddress();
15+
/// @notice Error thrown when the public key is zero
1316
error ZeroPubkey();
17+
/// @notice Error thrown when the curve type is invalid
1418
error InvalidCurveType();
19+
/// @notice Error thrown when the keypair is invalid
1520
error InvalidKeypair();
21+
/// @notice Error thrown when the configuration is already set
1622
error ConfigurationAlreadySet();
23+
/// @notice Error thrown when the operator set is not configured
1724
error OperatorSetNotConfigured();
25+
/// @notice Error thrown when the key is not found
1826
error KeyNotFound(OperatorSet operatorSet, address operator);
27+
/// @notice Error thrown when the operator is still slashable when trying to deregister a key
1928
error OperatorStillSlashable(OperatorSet operatorSet, address operator);
2029
}
2130

@@ -35,9 +44,13 @@ interface IKeyRegistrarTypes {
3544
}
3645

3746
interface IKeyRegistrarEvents is IKeyRegistrarTypes {
47+
/// @notice Emitted when a key is registered
3848
event KeyRegistered(OperatorSet operatorSet, address indexed operator, CurveType curveType, bytes pubkey);
49+
/// @notice Emitted when a key is deregistered
3950
event KeyDeregistered(OperatorSet operatorSet, address indexed operator, CurveType curveType);
51+
/// @notice Emitted when the aggregate BN254 key is updated
4052
event AggregateBN254KeyUpdated(OperatorSet operatorSet, BN254.G1Point newAggregateKey);
53+
/// @notice Emitted when an operator set is configured
4154
event OperatorSetConfigured(OperatorSet operatorSet, CurveType curveType);
4255
}
4356

@@ -54,8 +67,8 @@ interface IKeyRegistrar is IKeyRegistrarErrors, IKeyRegistrarEvents, ISemVerMixi
5467
* @notice Registers a cryptographic key for an operator with a specific operator set
5568
* @param operator Address of the operator to register key for
5669
* @param operatorSet The operator set to register the key for
57-
* @param pubkey Public key bytes
58-
* @param signature Signature proving ownership (only needed for BN254 keys)
70+
* @param pubkey Public key bytes. For ECDSA, this is the address of the key. For BN254, this is the G1 and G2 key combined (see `encodeBN254KeyData`)
71+
* @param signature Signature proving ownership. For ECDSA this is a signature of the `getECDSAKeyRegistrationMessageHash`. For BN254 this is a signature of the `getBN254KeyRegistrationMessageHash`.
5972
* @dev Can be called by operator directly or by addresses they've authorized via PermissionController
6073
* @dev Reverts if key is already registered
6174
* @dev There exist no restriction on the state of the operator with respect to the operatorSet. That is, an operator
@@ -79,29 +92,19 @@ interface IKeyRegistrar is IKeyRegistrarErrors, IKeyRegistrarEvents, ISemVerMixi
7992
*/
8093
function deregisterKey(address operator, OperatorSet memory operatorSet) external;
8194

82-
/**
83-
* @notice Checks if an operator has a registered key
84-
* @param operatorSet The operator set to check and update
85-
* @param operator Address of the operator
86-
* @return whether the operator has a registered key
87-
* @dev This function is called by the AVSRegistrar when an operator registers for an AVS
88-
* @dev Only authorized callers for the AVS can call this function
89-
* @dev Reverts if operator doesn't have a registered key for this operator set
90-
*/
91-
function checkKey(OperatorSet memory operatorSet, address operator) external view returns (bool);
92-
9395
/**
9496
* @notice Checks if a key is registered for an operator with a specific operator set
9597
* @param operatorSet The operator set to check
9698
* @param operator Address of the operator
97-
* @return True if the key is registered
99+
* @return True if the key is registered, false otherwise
100+
* @dev If the operatorSet is not configured, this function will return false
98101
*/
99102
function isRegistered(OperatorSet memory operatorSet, address operator) external view returns (bool);
100103

101104
/**
102-
* @notice Gets the configuration for an operator set
103-
* @param operatorSet The operator set to get configuration for
104-
* @return The operator set configuration
105+
* @notice Gets the curve type for an operator set
106+
* @param operatorSet The operator set to get the curve type for
107+
* @return The curve type, either ECDSA, BN254, or NONE
105108
*/
106109
function getOperatorSetCurveType(
107110
OperatorSet memory operatorSet
@@ -113,6 +116,7 @@ interface IKeyRegistrar is IKeyRegistrarErrors, IKeyRegistrarEvents, ISemVerMixi
113116
* @param operator Address of the operator
114117
* @return g1Point The BN254 G1 public key
115118
* @return g2Point The BN254 G2 public key
119+
* @dev Reverts if the operatorSet is not configured for BN254
116120
*/
117121
function getBN254Key(
118122
OperatorSet memory operatorSet,
@@ -123,15 +127,17 @@ interface IKeyRegistrar is IKeyRegistrarErrors, IKeyRegistrarEvents, ISemVerMixi
123127
* @notice Gets the ECDSA public key for an operator with a specific operator set as bytes
124128
* @param operatorSet The operator set to get the key for
125129
* @param operator Address of the operator
126-
* @return pubkey The ECDSA public key
130+
* @return pubkey The ECDSA public key in bytes format
131+
* @dev Reverts if the operatorSet is not configured for ECDSA
127132
*/
128133
function getECDSAKey(OperatorSet memory operatorSet, address operator) external view returns (bytes memory);
129134

130135
/**
131136
* @notice Gets the ECDSA public key for an operator with a specific operator set
132137
* @param operatorSet The operator set to get the key for
133138
* @param operator Address of the operator
134-
* @return pubkey The ECDSA public key
139+
* @return pubkey The ECDSA public key in address format
140+
* @dev Reverts if the operatorSet is not configured for ECDSA
135141
*/
136142
function getECDSAAddress(OperatorSet memory operatorSet, address operator) external view returns (address);
137143

@@ -149,6 +155,7 @@ interface IKeyRegistrar is IKeyRegistrarErrors, IKeyRegistrarEvents, ISemVerMixi
149155
* @param operatorSet The operator set to get the key hash for
150156
* @param operator Address of the operator
151157
* @return keyHash The key hash
158+
* @dev Reverts if the operatorSet is not configured
152159
*/
153160
function getKeyHash(OperatorSet memory operatorSet, address operator) external view returns (bytes32);
154161

src/contracts/permissions/KeyRegistrar.sol

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -246,15 +246,6 @@ contract KeyRegistrar is KeyRegistrarStorage, PermissionControllerMixin, Signatu
246246
*
247247
*/
248248

249-
/// @inheritdoc IKeyRegistrar
250-
function checkKey(OperatorSet memory operatorSet, address operator) external view returns (bool) {
251-
CurveType curveType = _operatorSetCurveTypes[operatorSet.key()];
252-
require(curveType != CurveType.NONE, OperatorSetNotConfigured());
253-
254-
KeyInfo memory keyInfo = _operatorKeyInfo[operatorSet.key()][operator];
255-
return keyInfo.isRegistered;
256-
}
257-
258249
/// @inheritdoc IKeyRegistrar
259250
function isRegistered(OperatorSet memory operatorSet, address operator) public view returns (bool) {
260251
return _operatorKeyInfo[operatorSet.key()][operator].isRegistered;

src/test/unit/KeyRegistrarUnit.t.sol

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -674,59 +674,6 @@ contract KeyRegistrarUnitTests_deregisterKey is KeyRegistrarUnitTests {
674674
}
675675
}
676676

677-
/**
678-
* @title KeyRegistrarUnitTests_checkKey
679-
* @notice Unit tests for KeyRegistrar.checkKey
680-
*/
681-
contract KeyRegistrarUnitTests_checkKey is KeyRegistrarUnitTests {
682-
function test_checkKey_ECDSA() public {
683-
OperatorSet memory operatorSet = _createOperatorSet(avs1, DEFAULT_OPERATOR_SET_ID);
684-
685-
vm.prank(avs1);
686-
keyRegistrar.configureOperatorSet(operatorSet, CurveType.ECDSA);
687-
688-
bytes memory signature = _generateECDSASignature(operator1, operatorSet, ecdsaAddress1, ecdsaPrivKey1);
689-
690-
vm.prank(operator1);
691-
keyRegistrar.registerKey(operator1, operatorSet, ecdsaKey1, signature);
692-
693-
bool hasKey = keyRegistrar.checkKey(operatorSet, operator1);
694-
assertTrue(hasKey);
695-
}
696-
697-
function test_checkKey_BN254() public {
698-
OperatorSet memory operatorSet = _createOperatorSet(avs1, DEFAULT_OPERATOR_SET_ID);
699-
700-
vm.prank(avs1);
701-
keyRegistrar.configureOperatorSet(operatorSet, CurveType.BN254);
702-
703-
bytes memory signature = _generateBN254Signature(operator1, operatorSet, bn254Key1, bn254PrivKey1);
704-
705-
vm.prank(operator1);
706-
keyRegistrar.registerKey(operator1, operatorSet, bn254Key1, signature);
707-
708-
bool hasKey = keyRegistrar.checkKey(operatorSet, operator1);
709-
assertTrue(hasKey);
710-
}
711-
712-
function test_checkKey_notRegistered() public {
713-
OperatorSet memory operatorSet = _createOperatorSet(avs1, DEFAULT_OPERATOR_SET_ID);
714-
715-
vm.prank(avs1);
716-
keyRegistrar.configureOperatorSet(operatorSet, CurveType.ECDSA);
717-
718-
bool hasKey = keyRegistrar.checkKey(operatorSet, operator1);
719-
assertFalse(hasKey);
720-
}
721-
722-
function test_revert_operatorSetNotConfigured() public {
723-
OperatorSet memory operatorSet = _createOperatorSet(avs1, DEFAULT_OPERATOR_SET_ID);
724-
725-
vm.expectRevert(OperatorSetNotConfigured.selector);
726-
keyRegistrar.checkKey(operatorSet, operator1);
727-
}
728-
}
729-
730677
/**
731678
* @title KeyRegistrarUnitTests_ViewFunctions
732679
* @notice Unit tests for KeyRegistrar view functions

0 commit comments

Comments
 (0)