Skip to content

Commit a26e346

Browse files
committed
feat: avs registrar (#484)
**Motivation:** We want to update the AVS registrar to be minimal & modular. **Modifications:** Add a new `AVSRegistrar` with first class support with the `KeyRegistrar`. We also have the following modules: 1. `SocketRegistry` 2. `AllowList` The above modules are _abstract_ and are inherited by `AVSRegistrars` in the `presets` folder: `AVSRegistrarWithAllowlist` and `AVSRegistrarWithSocket`. **Result:** Simple AVSRegistrar. Note that we are still pending on the `KeyRegistrar` interface update: Layr-Labs/eigenlayer-contracts#1421
1 parent 5e85218 commit a26e346

21 files changed

+1557
-1
lines changed

lib/eigenlayer-contracts

Submodule eigenlayer-contracts updated 98 files
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.27;
3+
4+
interface IAVSRegistrarErrors {
5+
/// @notice Thrown when a key is not registered
6+
error KeyNotRegistered();
7+
/// @notice Thrown when the caller is not the allocation manager
8+
error NotAllocationManager();
9+
}
10+
11+
interface IAVSRegistrarEvents {
12+
/// @notice Emitted when a new operator is registered
13+
event OperatorRegistered(address indexed operator, uint32[] operatorSetIds);
14+
15+
/// @notice Emitted when an operator is deregistered
16+
event OperatorDeregistered(address indexed operator, uint32[] operatorSetIds);
17+
}
18+
19+
/// @notice Since we have already defined a public interface, we add the events and errors here
20+
interface IAVSRegistrarInternal is IAVSRegistrarErrors, IAVSRegistrarEvents {}

src/interfaces/IAllowlist.sol

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity >=0.5.0;
3+
4+
import {OperatorSet} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol";
5+
6+
interface IAllowlistErrors {
7+
/// @notice Thrown when the operator is already in the allowlist
8+
error OperatorAlreadyInAllowlist();
9+
/// @notice Thrown when the operator is not in the allowlist
10+
error OperatorNotInAllowlist();
11+
}
12+
13+
interface IAllowlistEvents {
14+
/// @notice Emitted when an operator is added to the allowlist
15+
event OperatorAddedToAllowlist(OperatorSet indexed operatorSet, address indexed operator);
16+
/// @notice Emitted when an operator is removed from the allowlist
17+
event OperatorRemovedFromAllowlist(OperatorSet indexed operatorSet, address indexed operator);
18+
}
19+
20+
interface IAllowlist is IAllowlistErrors, IAllowlistEvents {
21+
/**
22+
* @notice Adds an operator to the allowlist
23+
* @param operatorSet The operator set to add the operator to
24+
* @param operator The operator to add to the allowlist
25+
* @dev Only callable by the owner
26+
*/
27+
function addOperatorToAllowlist(OperatorSet memory operatorSet, address operator) external;
28+
29+
/**
30+
* @notice Removes an operator from the allowlist
31+
* @param operatorSet The operator set to remove the operator from
32+
* @param operator The operator to remove from the allowlist
33+
* @dev If an operator is removed from the allowlist and is already registered, the avs
34+
* must then handle state changes appropriately (ie. eject the operator)
35+
* @dev Only callable by the owner
36+
*/
37+
function removeOperatorFromAllowlist(
38+
OperatorSet memory operatorSet,
39+
address operator
40+
) external;
41+
42+
/**
43+
* @notice Checks if an operator is in the allowlist
44+
* @param operatorSet The operator set to check the operator in
45+
* @param operator The operator to check
46+
* @return True if the operator is in the allowlist, false otherwise
47+
*/
48+
function isOperatorAllowed(
49+
OperatorSet memory operatorSet,
50+
address operator
51+
) external view returns (bool);
52+
53+
/**
54+
* @notice Returns all operators in the allowlist
55+
* @param operatorSet The operator set to get the allowed operators from
56+
* @return An array of all operators in the allowlist
57+
* @dev This function should be used with caution, as it can be expensive to call on-chain
58+
*/
59+
function getAllowedOperators(
60+
OperatorSet memory operatorSet
61+
) external view returns (address[] memory);
62+
}

src/interfaces/IKeyRegistrar.sol

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.27;
3+
4+
import "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol";
5+
6+
/// @notice A dummy interface for the KeyRegistrar
7+
interface IKeyRegistrar {
8+
enum CurveType {
9+
ECDSA,
10+
BN254
11+
}
12+
13+
function checkAndUpdateKey(
14+
OperatorSet calldata operatorSet,
15+
address operator
16+
) external returns (bool);
17+
18+
function removeKey(OperatorSet calldata operatorSet, address operator) external;
19+
20+
function isRegistered(
21+
OperatorSet calldata operatorSet,
22+
address operator
23+
) external view returns (bool);
24+
}

src/interfaces/ISocketRegistryV2.sol

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.27;
3+
4+
interface ISocketRegistryErrors {
5+
/// @notice Thrown when the caller is not the operator
6+
error CallerNotOperator();
7+
8+
/// @notice Thrown when the data length mismatch
9+
error DataLengthMismatch();
10+
}
11+
12+
interface ISocketRegistryEvents {
13+
/// @notice Emitted when an operator socket is set
14+
event OperatorSocketSet(address indexed operator, string socket);
15+
}
16+
17+
interface ISocketRegistry is ISocketRegistryErrors, ISocketRegistryEvents {
18+
/**
19+
* @notice Gets the socket for an operator.
20+
* @param operator The operator to get the socket for.
21+
* @return The socket for the operator.
22+
*/
23+
function getOperatorSocket(
24+
address operator
25+
) external view returns (string memory);
26+
27+
/**
28+
* @notice Updates the socket for an operator.
29+
* @param operator The operator to set the socket for.
30+
* @param socket The socket to set for the operator.
31+
* @dev This function can only be called by the operator themselves.
32+
*/
33+
function updateSocket(address operator, string memory socket) external;
34+
}
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.27;
3+
4+
import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol";
5+
import {IAllocationManager} from
6+
"eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
7+
import {
8+
OperatorSetLib,
9+
OperatorSet
10+
} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol";
11+
import {
12+
IKeyRegistrarTypes,
13+
IKeyRegistrar
14+
} from "eigenlayer-contracts/src/contracts/interfaces/IKeyRegistrar.sol";
15+
16+
import {AVSRegistrarStorage} from "./AVSRegistrarStorage.sol";
17+
18+
import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
19+
20+
/// @notice A minimal AVSRegistrar contract that is used to register/deregister operators for an AVS
21+
contract AVSRegistrar is Initializable, AVSRegistrarStorage {
22+
using OperatorSetLib for OperatorSet;
23+
24+
modifier onlyAllocationManager() {
25+
require(msg.sender == address(allocationManager), NotAllocationManager());
26+
_;
27+
}
28+
29+
constructor(
30+
address _avs,
31+
IAllocationManager _allocationManager,
32+
IKeyRegistrar _keyRegistrar
33+
) AVSRegistrarStorage(_avs, _allocationManager, _keyRegistrar) {
34+
_disableInitializers();
35+
}
36+
37+
/// @inheritdoc IAVSRegistrar
38+
function registerOperator(
39+
address operator,
40+
address avs,
41+
uint32[] calldata operatorSetIds,
42+
bytes calldata data
43+
) external virtual onlyAllocationManager {
44+
_beforeRegisterOperator(operator, operatorSetIds, data);
45+
46+
// Check that the operator has a valid key and update key if needed
47+
_validateOperatorKeys(operator, operatorSetIds);
48+
49+
_afterRegisterOperator(operator, operatorSetIds, data);
50+
51+
emit OperatorRegistered(operator, operatorSetIds);
52+
}
53+
54+
/// @inheritdoc IAVSRegistrar
55+
function deregisterOperator(
56+
address operator,
57+
address avs,
58+
uint32[] calldata operatorSetIds
59+
) external virtual onlyAllocationManager {
60+
_beforeDeregisterOperator(operator, operatorSetIds);
61+
62+
_afterDeregisterOperator(operator, operatorSetIds);
63+
64+
emit OperatorDeregistered(operator, operatorSetIds);
65+
}
66+
67+
/// @inheritdoc IAVSRegistrar
68+
function supportsAVS(
69+
address _avs
70+
) public view virtual returns (bool) {
71+
return _avs == avs;
72+
}
73+
74+
/*
75+
*
76+
* INTERNAL FUNCTIONS
77+
*
78+
*/
79+
80+
/**
81+
* @notice Validates that the operator has registered a key for the given operator sets
82+
* @param operator The operator to validate
83+
* @param operatorSetIds The operator sets to validate
84+
* @dev This function assumes the operator has already registered a key in the Key Registrar
85+
*/
86+
function _validateOperatorKeys(address operator, uint32[] calldata operatorSetIds) internal {
87+
for (uint32 i = 0; i < operatorSetIds.length; i++) {
88+
OperatorSet memory operatorSet = OperatorSet({avs: avs, id: operatorSetIds[i]});
89+
require(keyRegistrar.checkKey(operatorSet, operator), KeyNotRegistered());
90+
}
91+
}
92+
93+
/**
94+
* @notice Hook called before the operator is registered
95+
* @param operator The operator to register
96+
* @param operatorSetIds The operator sets to register
97+
* @param data The data to register
98+
*/
99+
function _beforeRegisterOperator(
100+
address operator,
101+
uint32[] calldata operatorSetIds,
102+
bytes calldata data
103+
) internal virtual {}
104+
105+
/**
106+
* @notice Hook called after the operator is registered
107+
* @param operator The operator to register
108+
* @param operatorSetIds The operator sets to register
109+
* @param data The data to register
110+
*/
111+
function _afterRegisterOperator(
112+
address operator,
113+
uint32[] calldata operatorSetIds,
114+
bytes calldata data
115+
) internal virtual {}
116+
117+
/**
118+
* @notice Hook called before the operator is deregistered
119+
* @param operator The operator to deregister
120+
* @param operatorSetIds The operator sets to deregister
121+
*/
122+
function _beforeDeregisterOperator(
123+
address operator,
124+
uint32[] calldata operatorSetIds
125+
) internal virtual {}
126+
127+
/**
128+
* @notice Hook called after the operator is deregistered
129+
* @param operator The operator to deregister
130+
* @param operatorSetIds The operator sets to deregister
131+
*/
132+
function _afterDeregisterOperator(
133+
address operator,
134+
uint32[] calldata operatorSetIds
135+
) internal virtual {}
136+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.27;
3+
4+
import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol";
5+
import {IKeyRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IKeyRegistrar.sol";
6+
import {IAVSRegistrarInternal} from "../../interfaces/IAVSRegistrarInternal.sol";
7+
import {IAllocationManager} from
8+
"eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
9+
10+
/// @notice A minimal storage contract for the AVSRegistrar
11+
abstract contract AVSRegistrarStorage is IAVSRegistrar, IAVSRegistrarInternal {
12+
/**
13+
*
14+
* CONSTANTS AND IMMUTABLES
15+
*
16+
*/
17+
18+
/// @notice The AVS that this registrar is for
19+
/// @dev In practice, the AVS address in EigenLayer core is address that initialized the Metadata URI.
20+
address public immutable avs;
21+
22+
/// @notice The allocation manager in EigenLayer core
23+
IAllocationManager public immutable allocationManager;
24+
25+
/// @notice Pointer to the EigenLayer core Key Registrar
26+
IKeyRegistrar public immutable keyRegistrar;
27+
28+
constructor(address _avs, IAllocationManager _allocationManager, IKeyRegistrar _keyRegistrar) {
29+
avs = _avs;
30+
allocationManager = _allocationManager;
31+
keyRegistrar = _keyRegistrar;
32+
}
33+
34+
/**
35+
* @dev This empty reserved space is put in place to allow future versions to add new
36+
* variables without shifting down storage in the inheritance chain.
37+
* See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
38+
*/
39+
uint256[50] private __GAP;
40+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.27;
3+
4+
import {IAllowlist} from "../../../interfaces/IAllowlist.sol";
5+
import {AllowlistStorage} from "./AllowlistStorage.sol";
6+
7+
import {OwnableUpgradeable} from
8+
"openzeppelin-contracts-upgradeable/contracts/access/OwnableUpgradeable.sol";
9+
import {EnumerableSetUpgradeable} from
10+
"openzeppelin-contracts-upgradeable/contracts/utils/structs/EnumerableSetUpgradeable.sol";
11+
12+
import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol";
13+
import {
14+
OperatorSet,
15+
OperatorSetLib
16+
} from "eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol";
17+
18+
abstract contract Allowlist is OwnableUpgradeable, AllowlistStorage {
19+
using OperatorSetLib for OperatorSet;
20+
using EnumerableSetUpgradeable for EnumerableSetUpgradeable.AddressSet;
21+
22+
function initialize(
23+
address _owner
24+
) public virtual initializer {
25+
_initializeAllowlist(_owner);
26+
}
27+
28+
function _initializeAllowlist(
29+
address _owner
30+
) internal onlyInitializing {
31+
__Ownable_init();
32+
_transferOwnership(_owner);
33+
}
34+
35+
/// @inheritdoc IAllowlist
36+
function addOperatorToAllowlist(
37+
OperatorSet memory operatorSet,
38+
address operator
39+
) external onlyOwner {
40+
require(_allowedOperators[operatorSet.key()].add(operator), OperatorAlreadyInAllowlist());
41+
emit OperatorAddedToAllowlist(operatorSet, operator);
42+
}
43+
44+
/// @inheritdoc IAllowlist
45+
function removeOperatorFromAllowlist(
46+
OperatorSet memory operatorSet,
47+
address operator
48+
) external onlyOwner {
49+
require(_allowedOperators[operatorSet.key()].remove(operator), OperatorNotInAllowlist());
50+
emit OperatorRemovedFromAllowlist(operatorSet, operator);
51+
}
52+
53+
/// @inheritdoc IAllowlist
54+
function isOperatorAllowed(
55+
OperatorSet memory operatorSet,
56+
address operator
57+
) public view returns (bool) {
58+
return _allowedOperators[operatorSet.key()].contains(operator);
59+
}
60+
61+
/// @inheritdoc IAllowlist
62+
function getAllowedOperators(
63+
OperatorSet memory operatorSet
64+
) external view returns (address[] memory) {
65+
return _allowedOperators[operatorSet.key()].values();
66+
}
67+
}

0 commit comments

Comments
 (0)