Skip to content

Commit 6cebc82

Browse files
bowenli860xClandestine
authored andcommitted
feat: require avs register metadata in allocation manager (#1025)
require avs register metadata in allocation manager before they can create operatorset --------- Co-authored-by: clandestine.eth <[email protected]>
1 parent 452d530 commit 6cebc82

File tree

7 files changed

+143
-79
lines changed

7 files changed

+143
-79
lines changed

docs/core/AllocationManager.md

Lines changed: 102 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ Libraries and Mixins:
2222

2323
## Overview
2424

25-
The `AllocationManager` manages registration and deregistration of operators to operator sets, handles allocation and slashing of operators' slashable stake, and is the entry point an AVS uses to slash an operator. The `AllocationManager's` responsibilities are broken down into the following concepts:
25+
The `AllocationManager` manages AVS metadata registration, registration and deregistration of operators to operator sets, handles allocation and slashing of operators' slashable stake, and is the entry point an AVS uses to slash an operator. The `AllocationManager's` responsibilities are broken down into the following concepts:
26+
27+
* [AVS Metadata](#avs-metadata)
2628
* [Operator Sets](#operator-sets)
2729
* [Allocations and Slashing](#allocations-and-slashing)
2830
* [Config](#config)
@@ -38,6 +40,104 @@ The `AllocationManager` manages registration and deregistration of operators to
3840

3941
---
4042

43+
## AVS Metadata
44+
45+
AVSs must register their metadata to declare themselves who they are as the first step, before they can create operator sets or register operators into operator sets. `AllocationManager` keeps track of AVSs that have registered metadata.
46+
47+
**Methods:**
48+
* [`updateAVSMetadataURI`](#updateavsmetadatauri)
49+
50+
51+
#### `updateAVSMetadataURI`
52+
53+
```solidity
54+
/**
55+
* @notice Called by an AVS to emit an `AVSMetadataURIUpdated` event indicating the information has updated.
56+
*
57+
* @param metadataURI The URI for metadata associated with an AVS.
58+
*
59+
* @dev Note that the `metadataURI` is *never stored* and is only emitted in the `AVSMetadataURIUpdated` event.
60+
*/
61+
function updateAVSMetadataURI(
62+
address avs,
63+
string calldata metadataURI
64+
)
65+
external
66+
checkCanCall(avs)
67+
```
68+
69+
_Note: this method can be called directly by an AVS, or by a caller authorized by the AVS. See [`PermissionController.md`](../permissions/PermissionController.md) for details._
70+
71+
Below is the format AVSs should use when updating their metadata URI initially. This is not validated onchain.
72+
73+
```json
74+
{
75+
"name": "AVS",
76+
"website": "https.avs.xyz/",
77+
"description": "Some description about",
78+
"logo": "http://github.com/logo.png",
79+
"twitter": "https://twitter.com/avs",
80+
}
81+
```
82+
83+
84+
Later on, once AVSs have created operator sets, content in their metadata URI can be updated subsequently.
85+
86+
```json
87+
{
88+
"name": "AVS",
89+
"website": "https.avs.xyz/",
90+
"description": "Some description about",
91+
"logo": "http://github.com/logo.png",
92+
"twitter": "https://twitter.com/avs",
93+
"operatorSets": [
94+
{
95+
"name": "ETH Set",
96+
"id": "1", // Note: we use this param to match the opSet id in the Allocation Manager
97+
"description": "The ETH operatorSet for AVS",
98+
"software": [
99+
{
100+
"name": "NetworkMonitor",
101+
"description": "",
102+
"url": "https://link-to-binary-or-github.com"
103+
},
104+
{
105+
"name": "ValidatorClient",
106+
"description": "",
107+
"url": "https://link-to-binary-or-github.com"
108+
}
109+
],
110+
"slashingConditions": ["Condition A", "Condition B"]
111+
},
112+
{
113+
"name": "EIGEN Set",
114+
"id": "2", // Note: we use this param to match the opSet id in the Allocation Manager
115+
"description": "The EIGEN operatorSet for AVS",
116+
"software": [
117+
{
118+
"name": "NetworkMonitor",
119+
"description": "",
120+
"url": "https://link-to-binary-or-github.com"
121+
},
122+
{
123+
"name": "ValidatorClient",
124+
"description": "",
125+
"url": "https://link-to-binary-or-github.com"
126+
}
127+
],
128+
"slashingConditions": ["Condition A", "Condition B"]
129+
}
130+
]
131+
}
132+
```
133+
134+
*Effects*:
135+
* Emits an `AVSMetadataURIUpdated` event for use in offchain services
136+
137+
*Requirements*:
138+
* Caller MUST be authorized, either as the AVS itself or an admin/appointee (see [`PermissionController.md`](../permissions/PermissionController.md))
139+
140+
41141
## Operator Sets
42142

43143
Operator sets, as described in [ELIP-002](https://github.com/eigenfoundation/ELIPs/blob/main/ELIPs/ELIP-002.md#operator-sets), are useful for AVSs to configure operator groupings which can be assigned different tasks, rewarded based on their strategy allocations, and slashed according to different rules. Operator sets are defined in [`libraries/OperatorSetLib.sol`](../../src/contracts/libraries/OperatorSetLib.sol):
@@ -145,6 +245,7 @@ Optionally, the `avs` can provide a list of `strategies`, specifying which strat
145245

146246
*Requirements*:
147247
* Caller MUST be authorized, either as the AVS itself or an admin/appointee (see [`PermissionController.md`](../permissions/PermissionController.md))
248+
* AVS MUST have registered metadata
148249
* For each `CreateSetParams` element:
149250
* Each `params.operatorSetId` MUST NOT already exist in `_operatorSets[avs]`
150251

@@ -665,7 +766,6 @@ Once slashing is processed for a strategy, [slashed stake is burned via the `Del
665766
**Methods:**
666767
* [`setAllocationDelay`](#setallocationdelay)
667768
* [`setAVSRegistrar`](#setavsregistrar)
668-
* [`updateAVSMetadataURI`](#updateavsmetadatauri)
669769

670770
#### `setAllocationDelay`
671771

@@ -756,79 +856,3 @@ Note that when an operator registers, registration will FAIL if the call to `IAV
756856

757857
*Requirements*:
758858
* Caller MUST be authorized, either as the AVS itself or an admin/appointee (see [`PermissionController.md`](../permissions/PermissionController.md))
759-
760-
#### `updateAVSMetadataURI`
761-
762-
```solidity
763-
/**
764-
* @notice Called by an AVS to emit an `AVSMetadataURIUpdated` event indicating the information has updated.
765-
*
766-
* @param metadataURI The URI for metadata associated with an AVS.
767-
*
768-
* @dev Note that the `metadataURI` is *never stored* and is only emitted in the `AVSMetadataURIUpdated` event.
769-
*/
770-
function updateAVSMetadataURI(
771-
address avs,
772-
string calldata metadataURI
773-
)
774-
external
775-
checkCanCall(avs)
776-
```
777-
778-
_Note: this method can be called directly by an AVS, or by a caller authorized by the AVS. See [`PermissionController.md`](../permissions/PermissionController.md) for details._
779-
780-
Below is the format AVSs should use when updating their metadata URI. This is not validated onchain.
781-
782-
```json
783-
{
784-
"name": "AVS",
785-
"website": "https.avs.xyz/",
786-
"description": "Some description about",
787-
"logo": "http://github.com/logo.png",
788-
"twitter": "https://twitter.com/avs",
789-
"operatorSets": [
790-
{
791-
"name": "ETH Set",
792-
"id": "1", // Note: we use this param to match the opSet id in the Allocation Manager
793-
"description": "The ETH operatorSet for AVS",
794-
"software": [
795-
{
796-
"name": "NetworkMonitor",
797-
"description": "",
798-
"url": "https://link-to-binary-or-github.com"
799-
},
800-
{
801-
"name": "ValidatorClient",
802-
"description": "",
803-
"url": "https://link-to-binary-or-github.com"
804-
}
805-
],
806-
"slashingConditions": ["Condition A", "Condition B"]
807-
},
808-
{
809-
"name": "EIGEN Set",
810-
"id": "2", // Note: we use this param to match the opSet id in the Allocation Manager
811-
"description": "The EIGEN operatorSet for AVS",
812-
"software": [
813-
{
814-
"name": "NetworkMonitor",
815-
"description": "",
816-
"url": "https://link-to-binary-or-github.com"
817-
},
818-
{
819-
"name": "ValidatorClient",
820-
"description": "",
821-
"url": "https://link-to-binary-or-github.com"
822-
}
823-
],
824-
"slashingConditions": ["Condition A", "Condition B"]
825-
}
826-
]
827-
}
828-
```
829-
830-
*Effects*:
831-
* Emits an `AVSMetadataURIUpdated` event for use in offchain services
832-
833-
*Requirements*:
834-
* Caller MUST be authorized, either as the AVS itself or an admin/appointee (see [`PermissionController.md`](../permissions/PermissionController.md))

src/contracts/core/AllocationManager.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,11 +330,18 @@ contract AllocationManager is
330330

331331
/// @inheritdoc IAllocationManager
332332
function updateAVSMetadataURI(address avs, string calldata metadataURI) external checkCanCall(avs) {
333+
if (!_avsRegisteredMetadata[avs]) {
334+
_avsRegisteredMetadata[avs] = true;
335+
}
336+
333337
emit AVSMetadataURIUpdated(avs, metadataURI);
334338
}
335339

336340
/// @inheritdoc IAllocationManager
337341
function createOperatorSets(address avs, CreateSetParams[] calldata params) external checkCanCall(avs) {
342+
// Check that the AVS exists and has registered metadata
343+
require(_avsRegisteredMetadata[avs], NonexistentAVSMetadata());
344+
338345
for (uint256 i = 0; i < params.length; i++) {
339346
OperatorSet memory operatorSet = OperatorSet(avs, params[i].operatorSetId);
340347

src/contracts/core/AllocationManagerStorage.sol

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ abstract contract AllocationManagerStorage is IAllocationManager {
8989
/// These must be completed in order to free up magnitude for future allocation
9090
mapping(address operator => mapping(IStrategy strategy => DoubleEndedQueue.Bytes32Deque)) internal deallocationQueue;
9191

92+
/// @dev Lists the AVSs who has registered metadata and claimed itself as an AVS
93+
/// @notice bool is not used and is always true if the avs has registered metadata
94+
mapping(address avs => bool) internal _avsRegisteredMetadata;
95+
9296
// Construction
9397

9498
constructor(IDelegationManager _delegation, uint32 _DEALLOCATION_DELAY, uint32 _ALLOCATION_CONFIGURATION_DELAY) {
@@ -102,5 +106,5 @@ abstract contract AllocationManagerStorage is IAllocationManager {
102106
* variables without shifting down storage in the inheritance chain.
103107
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
104108
*/
105-
uint256[37] private __gap;
109+
uint256[36] private __gap;
106110
}

src/contracts/interfaces/IAllocationManager.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ interface IAllocationManagerErrors {
2727

2828
/// @dev Thrown when an invalid operator is provided.
2929
error InvalidOperator();
30+
/// @dev Thrown when an invalid avs whose metadata is not registered is provided.
31+
error NonexistentAVSMetadata();
3032
/// @dev Thrown when an operator's allocation delay has yet to be set.
3133
error UninitializedAllocationDelay();
3234
/// @dev Thrown when attempting to slash an operator when they are not slashable.

src/test/integration/IntegrationBase.t.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ abstract contract IntegrationBase is IntegrationDeployer, TypeImporter {
147147
function _newRandomAVS() internal returns (AVS avs, OperatorSet[] memory operatorSets) {
148148
string memory avsName = string.concat("avs", numAVSs.toString());
149149
avs = _genRandAVS(avsName);
150+
avs.updateAVSMetadataURI("https://example.com");
150151
operatorSets = avs.createOperatorSets(_randomStrategies());
151152
++numAVSs;
152153
}

src/test/integration/users/AVS.t.sol

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,18 @@ contract AVS is Logger, IAllocationManagerTypes, IAVSRegistrar {
7171
/// AllocationManager
7272
/// -----------------------------------------------------------------------
7373

74+
function updateAVSMetadataURI(
75+
string memory uri
76+
) public createSnapshot {
77+
print.method("updateAVSMetadataURI");
78+
79+
console.log("Setting AVS metadata URI to: %s", uri);
80+
_tryPrankAppointee_AllocationManager(IAllocationManager.updateAVSMetadataURI.selector);
81+
allocationManager.updateAVSMetadataURI(address(this), uri);
82+
83+
print.gasUsed();
84+
}
85+
7486
function createOperatorSets(
7587
IStrategy[][] memory strategies
7688
) public createSnapshot returns (OperatorSet[] memory operatorSets) {

src/test/unit/AllocationManagerUnit.t.sol

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ contract AllocationManagerUnitTests is EigenLayerUnitTestSetup, IAllocationManag
7171
defaultStrategies = strategyMock.toArray();
7272
defaultOperatorSet = OperatorSet(defaultAVS, 0);
7373

74+
cheats.prank(defaultAVS);
75+
allocationManager.updateAVSMetadataURI(defaultAVS, "https://example.com");
76+
77+
7478
_createOperatorSet(defaultOperatorSet, defaultStrategies);
7579
_registerOperator(defaultOperator);
7680
_setAllocationDelay(defaultOperator, DEFAULT_OPERATOR_ALLOCATION_DELAY);
@@ -3856,13 +3860,23 @@ contract AllocationManagerUnitTests_createOperatorSets is AllocationManagerUnitT
38563860
);
38573861
}
38583862

3863+
function testRevert_createOperatorSets_NonexistentAVSMetadata(Randomness r) public rand(r) {
3864+
address avs = r.Address();
3865+
cheats.expectRevert(NonexistentAVSMetadata.selector);
3866+
cheats.prank(avs);
3867+
allocationManager.createOperatorSets(avs, CreateSetParams(defaultOperatorSet.id, defaultStrategies).toArray());
3868+
}
3869+
38593870
function testFuzz_createOperatorSets_Correctness(
38603871
Randomness r
38613872
) public rand(r) {
38623873
address avs = r.Address();
38633874
uint256 numOpSets = r.Uint256(1, FUZZ_MAX_OP_SETS);
38643875
uint256 numStrategies = r.Uint256(1, FUZZ_MAX_STRATS);
38653876

3877+
cheats.prank(avs);
3878+
allocationManager.updateAVSMetadataURI(avs, "https://example.com");
3879+
38663880
CreateSetParams[] memory createSetParams = new CreateSetParams[](numOpSets);
38673881

38683882
for (uint256 i; i < numOpSets; ++i) {

0 commit comments

Comments
 (0)