Skip to content

Commit 6c0027a

Browse files
committed
feat: erc20-esque avs
1 parent 02ae04e commit 6c0027a

11 files changed

Lines changed: 264 additions & 66 deletions

foundry.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"@openzeppelin-upgrades/=lib/openzeppelin-contracts-upgradeable/",
2323
"eigenlayer-contracts/=lib/eigenlayer-contracts/",
2424
"@openzeppelin-v5/=lib/openzeppelin-contracts-v5/",
25-
"@openzeppelin-upgrades-v5/=lib/openzeppelin-contracts-v5-upgradeable/",
25+
"@openzeppelin-upgrades-v5/=lib/openzeppelin-contracts-upgradeable-v5/",
2626
]
2727

2828
# Specifies the exact version of Solidity to use, overriding auto-detection.

src/poc/AVSRegistrar.sol

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,25 @@ import {
99
import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol";
1010

1111
import {AVSRegistrarStorage} from "./AVSRegistrarStorage.sol";
12+
import {Initializable} from "@openzeppelin-upgrades-v5/contracts/proxy/utils/Initializable.sol";
13+
import {ContextUpgradeable} from "@openzeppelin-upgrades-v5/contracts/utils/ContextUpgradeable.sol";
1214

13-
abstract contract AVSRegistrar is AVSRegistrarStorage {
15+
/// @notice A single-operator set AVS registrar
16+
abstract contract AVSRegistrar is Initializable, ContextUpgradeable, AVSRegistrarStorage {
1417
modifier onlyAllocationManager() {
1518
require(msg.sender == address(allocationManager), OnlyAllocationManager());
1619
_;
1720
}
1821

1922
constructor(
2023
address _allocationManager,
21-
address _avs
22-
) AVSRegistrarStorage(_allocationManager, _avs) {}
24+
address _avs,
25+
uint32 operatorSetId
26+
) AVSRegistrarStorage(_allocationManager, _avs, operatorSetId) {}
27+
28+
function __AVSRegistrar_init() internal onlyInitializing {}
29+
30+
function __AVSRegistrar_init_unchained() internal onlyInitializing {}
2331

2432
/// @inheritdoc IAVSRegistrar
2533
/// @dev EigenLayer Core checks that:
@@ -30,7 +38,12 @@ abstract contract AVSRegistrar is AVSRegistrarStorage {
3038
address avs,
3139
uint32[] calldata operatorSetIds,
3240
bytes calldata data
33-
) external virtual override onlyAllocationManager {}
41+
) external virtual override onlyAllocationManager {
42+
require(supportsAVS(avs), "Invalid AVS");
43+
require(operatorSetIds.length == 1, "Only accepts one operator set id");
44+
require(operatorSetIds[0] == operatorSetId, "Invalid operator set id");
45+
_afterRegisterOperator(operator, data);
46+
}
3447

3548
/// @inheritdoc IAVSRegistrar
3649
/// @dev EigenLayer Core checks that:
@@ -40,12 +53,25 @@ abstract contract AVSRegistrar is AVSRegistrarStorage {
4053
address operator,
4154
address avs,
4255
uint32[] calldata operatorSetIds
43-
) external virtual override onlyAllocationManager {}
56+
) external virtual override onlyAllocationManager {
57+
require(supportsAVS(avs), "Invalid AVS");
58+
require(operatorSetIds.length == 1, "Only accepts one operator set id");
59+
require(operatorSetIds[0] == operatorSetId, "Invalid operator set id");
60+
_afterDeregisterOperator(operator);
61+
}
4462

4563
/// @inheritdoc IAVSRegistrar
4664
function supportsAVS(
4765
address _avs
48-
) external view override returns (bool) {
66+
) public view override returns (bool) {
4967
return avs == _avs;
5068
}
69+
70+
function _afterRegisterOperator(address operator, bytes calldata data) internal virtual {}
71+
72+
function _afterDeregisterOperator(
73+
address operator
74+
) internal virtual {}
75+
76+
function _parseRegistrationData(bytes calldata data) internal view virtual returns (bytes memory);
5177
}

src/poc/AVSRegistrarStorage.sol

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,13 @@ abstract contract AVSRegistrarStorage is IAVSRegistrar {
1717
/// @notice The AVS the registrar is for.
1818
address public immutable avs;
1919

20-
constructor(address _allocationManager, address _avs) {
20+
/// @notice The operator set id the registrar is for.
21+
uint32 public immutable operatorSetId;
22+
23+
constructor(address _allocationManager, address _avs, uint32 _operatorSetId) {
2124
allocationManager = IAllocationManager(_allocationManager);
2225
avs = _avs;
26+
operatorSetId = _operatorSetId;
2327
}
2428

2529
// TODO: Move errors to the interface

src/poc/ECDSAAVS.sol

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.27;
3+
4+
import {ECDSARegistrar} from "./ECDSARegistrar.sol";
5+
import {AVSRegistrar} from "./AVSRegistrar.sol";
6+
import {SocketRegistry} from "./SocketRegistry.sol";
7+
8+
contract AVS is ECDSARegistrar, SocketRegistry {
9+
constructor(address allocationManager, address avs, uint32 operatorSetId) AVSRegistrar(allocationManager, avs, operatorSetId) {}
10+
11+
function initialize(uint256 ecdsaRegistrarStartIndex, uint256 ecdsaRegistrarEndIndex, uint256 socketRegistryStartIndex, uint256 socketRegistryEndIndex) public virtual initializer {
12+
__ECDSAAVS_init(ecdsaRegistrarStartIndex, ecdsaRegistrarEndIndex, socketRegistryStartIndex, socketRegistryEndIndex);
13+
}
14+
15+
function __ECDSAAVS_init(uint256 ecdsaRegistrarStartIndex, uint256 ecdsaRegistrarEndIndex, uint256 socketRegistryStartIndex, uint256 socketRegistryEndIndex) internal onlyInitializing {
16+
__ECDSARegistrar_init(ecdsaRegistrarStartIndex, ecdsaRegistrarEndIndex);
17+
__SocketRegistry_init(socketRegistryStartIndex, socketRegistryEndIndex);
18+
}
19+
20+
function _afterRegisterOperator(address operator, bytes calldata data) internal override(ECDSARegistrar, SocketRegistry) {
21+
super._afterRegisterOperator(operator, data);
22+
}
23+
24+
function _afterDeregisterOperator(address operator) internal override( ECDSARegistrar, SocketRegistry) {
25+
super._afterDeregisterOperator(operator);
26+
}
27+
28+
function _parseRegistrationData(bytes calldata data) internal view override(ECDSARegistrar, SocketRegistry) returns (bytes memory) {
29+
return super._parseRegistrationData(data);
30+
}
31+
}

src/poc/ECDSARegistrar.sol

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,68 @@
11
// SPDX-License-Identifier: BUSL-1.1
22
pragma solidity ^0.8.27;
33

4+
import {Initializable} from "@openzeppelin-upgrades-v5/contracts/proxy/utils/Initializable.sol";
5+
import {ContextUpgradeable} from "@openzeppelin-upgrades-v5/contracts/utils/ContextUpgradeable.sol";
6+
47
import {
58
IAllocationManager,
69
OperatorSet
710
} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
811

912
import {AVSRegistrar} from "./AVSRegistrar.sol";
1013
import {ECDSARegistrarStorage} from "./ECDSARegistrarStorage.sol";
14+
import {IECDSARegistrar} from "./interfaces/IECDSARegistrar.sol";
1115

12-
abstract contract ECDSARegistrar is ECDSARegistrarStorage, AVSRegistrar {
13-
14-
constructor(address _allocationManager, address _avs) AVSRegistrar(_allocationManager, _avs) {}
15-
16-
/// @inheritdoc AVSRegistrar
17-
function registerOperator(
18-
address operator,
19-
address avs,
20-
uint32[] calldata operatorSetIds,
21-
bytes calldata data
22-
) external virtual override onlyAllocationManager {
23-
ECDSARegistrarStorageStruct storage $ = _getECDSARegistrarStorage();
24-
$._operatorMetadata[operator] = OperatorMetadata({
25-
signingKey: data.signingKey
26-
});
16+
abstract contract ECDSARegistrar is AVSRegistrar, ECDSARegistrarStorage {
17+
function __ECDSARegistrar_init(uint256 startIndex, uint256 endIndex) public initializer {
18+
__ECDSARegistrar_init_unchained(startIndex, endIndex);
19+
}
2720

28-
_afterRegisterOperator(operator, avs, operatorSetIds, data);
21+
function __ECDSARegistrar_init_unchained(
22+
uint256 startIndex,
23+
uint256 endIndex
24+
) internal onlyInitializing {
25+
_getECDSARegistrarStorage().startIndex = startIndex;
26+
_getECDSARegistrarStorage().endIndex = endIndex;
2927
}
3028

29+
/**
30+
* @notice Overrides the afterRegisterOperator function to set the signing key for an operator
31+
* @param operator The operator to set the signing key for
32+
* @param data The data to set the signing key for
33+
*/
3134
function _afterRegisterOperator(
3235
address operator,
33-
address avs,
34-
uint32[] calldata operatorSetIds,
3536
bytes calldata data
36-
) internal virtual {}
37+
) internal virtual override {
38+
super._afterRegisterOperator(operator, data);
39+
40+
address signingKey = abi.decode(_parseRegistrationData(data), (address));
41+
_getECDSARegistrarStorage()._operatorSigningKey[operator] = signingKey;
42+
}
3743

44+
/**
45+
* @notice Overrides the afterDeregisterOperator function to clear the signing key for an operator
46+
* @param operator The operator to clear the signing key for
47+
*/
3848
function _afterDeregisterOperator(
39-
address operator,
40-
address avs,
41-
uint32[] calldata operatorSetIds
42-
) internal virtual {}
43-
}
49+
address operator
50+
) internal virtual override {
51+
super._afterDeregisterOperator(operator);
52+
53+
_getECDSARegistrarStorage()._operatorSigningKey[operator] = address(0);
54+
}
55+
56+
/// @inheritdoc IECDSARegistrar
57+
function getSigningKey(
58+
address operator
59+
) external view returns (address) {
60+
return _getECDSARegistrarStorage()._operatorSigningKey[operator];
61+
}
62+
63+
function _parseRegistrationData(
64+
bytes calldata data
65+
) internal virtual view override returns (bytes memory) {
66+
return data[_getECDSARegistrarStorage().startIndex:_getECDSARegistrarStorage().endIndex];
67+
}
68+
}

src/poc/ECDSARegistrarStorage.sol

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,25 @@ pragma solidity ^0.8.27;
44
import {IECDSARegistrar} from "./interfaces/IECDSARegistrar.sol";
55

66
abstract contract ECDSARegistrarStorage is IECDSARegistrar {
7-
87
/// @custom:storage-location erc7201:eigenlayermiddleware.storage.ECDSARegistrarStorage
98
struct ECDSARegistrarStorageStruct {
10-
mapping(address operator => OperatorMetadata metadata) _operatorMetadata;
9+
uint256 startIndex;
10+
uint256 endIndex;
11+
mapping(address operator => address signingKey) _operatorSigningKey;
1112
}
1213

1314
/// @dev The storage location for the ECDSARegistrarStorage struct
1415
/// TODO: update to proper storage slot
15-
bytes32 private constant ECDSARegistrarStorageLocation = 0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00;
16+
bytes32 private constant ECDSARegistrarStorageLocation =
17+
0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00;
1618

17-
function _getECDSARegistrarStorage() private pure returns (ECDSARegistrarStorageStruct storage $) {
19+
function _getECDSARegistrarStorage()
20+
internal
21+
pure
22+
returns (ECDSARegistrarStorageStruct storage $)
23+
{
1824
assembly {
1925
$.slot := ECDSARegistrarStorageLocation
2026
}
2127
}
22-
}
28+
}

src/poc/SocketRegistry.sol

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.27;
3+
4+
import {SocketRegistryStorage} from "./SocketRegistryStorage.sol";
5+
import {AVSRegistrar} from "./AVSRegistrar.sol";
6+
import {ISocketRegistry} from "./interfaces/ISocketRegistry.sol";
7+
import {OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol";
8+
9+
abstract contract SocketRegistry is AVSRegistrar, SocketRegistryStorage {
10+
function __SocketRegistry_init(
11+
uint256 startIndex,
12+
uint256 endIndex
13+
) internal onlyInitializing {
14+
__SocketRegistry_init_unchained(startIndex, endIndex);
15+
}
16+
17+
function __SocketRegistry_init_unchained(
18+
uint256 startIndex,
19+
uint256 endIndex
20+
) internal onlyInitializing {
21+
_getSocketRegistryStorage().startIndex = startIndex;
22+
_getSocketRegistryStorage().endIndex = endIndex;
23+
}
24+
25+
/// @inheritdoc ISocketRegistry
26+
function updateSocket(address operator, string memory socket) external {
27+
require(
28+
allocationManager.isMemberOfOperatorSet(
29+
operator, OperatorSet({avs: avs, id: operatorSetId})
30+
),
31+
"Operator not registered for operator set"
32+
);
33+
_updateSocket(operator, socket);
34+
}
35+
36+
/**
37+
* @notice Overrides the afterRegisterOperator function to update the socket
38+
* @param operator The operator to update the socket for
39+
* @param data The data to update the socket with
40+
*/
41+
function _afterRegisterOperator(
42+
address operator,
43+
bytes calldata data
44+
) internal virtual override {
45+
super._afterRegisterOperator(operator, data);
46+
string memory socket = abi.decode(_parseRegistrationData(data), (string));
47+
_updateSocket(operator, socket);
48+
}
49+
50+
/**
51+
* @notice Overrides the afterDeregisterOperator function to clear the socker of an operator
52+
* @param operator The operator to remove the socket from
53+
*/
54+
function _afterDeregisterOperator(
55+
address operator
56+
) internal virtual override {
57+
super._afterDeregisterOperator(operator);
58+
_updateSocket(operator, "");
59+
}
60+
61+
/// @inheritdoc ISocketRegistry
62+
function getSocket(
63+
address operator
64+
) external view returns (string memory) {
65+
return _getSocketRegistryStorage()._operatorSocket[operator];
66+
}
67+
68+
/// @dev Internal function to update the socket for an operator
69+
function _updateSocket(address operator, string memory socket) internal {
70+
_getSocketRegistryStorage()._operatorSocket[operator] = socket;
71+
}
72+
73+
function _parseRegistrationData(
74+
bytes calldata data
75+
) internal virtual view override returns (bytes memory) {
76+
return data[_getSocketRegistryStorage().startIndex:_getSocketRegistryStorage().endIndex];
77+
}
78+
}

src/poc/SocketRegistryStorage.sol

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.27;
3+
4+
import {ISocketRegistry} from "./interfaces/ISocketRegistry.sol";
5+
6+
abstract contract SocketRegistryStorage is ISocketRegistry {
7+
/// @custom:storage-location erc7201:eigenlayermiddleware.storage.SocketRegistrarStorage
8+
struct SocketRegistrarStorageStruct {
9+
uint256 startIndex;
10+
uint256 endIndex;
11+
mapping(address operator => string socket) _operatorSocket;
12+
}
13+
14+
/// @dev The storage location for the SocketRegistrarStorage struct
15+
/// TODO: update to proper storage slot
16+
bytes32 private constant SocketRegistrarStorageLocation =
17+
0x52c63247e1f47db19d5ce0460030c497f067ca4cebf71ba98eeadabe20bace00;
18+
19+
function _getSocketRegistryStorage()
20+
internal
21+
pure
22+
returns (SocketRegistrarStorageStruct storage $)
23+
{
24+
assembly {
25+
$.slot := SocketRegistrarStorageLocation
26+
}
27+
}
28+
}

src/poc/interfaces/IECDSARegistrar.sol

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,25 +6,14 @@ import {
66
ISignatureUtilsMixinTypes
77
} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtilsMixin.sol";
88

9-
/// @title ISignatureRegistrar
10-
/// @notice Interface for common getters on for SignatureRegistrars, namely ECDSA and BLS
9+
/// @title IECDSARegistrar
1110
interface IECDSARegistrar {
12-
13-
// TODO: Move to types/events/errors
14-
struct OperatorMetadata {
15-
address signingKey;
16-
}
17-
18-
/**
19-
* @notice Registers a new operator using a provided operators signature and signing key.
20-
* @param operatorSignature Contains the operator's signature, salt, and expiry.
21-
* @param signingKey The signing key associated with the operator
22-
*/
23-
function registerOperatorWithSig(address operator, ISignatureUtilsMixinTypes.SignatureWithSaltAndExpiry memory operatorSignature, address signingKey) external;
24-
2511
/**
26-
* @notice Deregisters an existing operator.
27-
* @param operator The operator to deregister
12+
* @notice Gets the signing key for an operator
13+
* @param operator The operator to get the signing key for
14+
* @return The signing key for the operator
2815
*/
29-
function deregisterOperator(address operator) external;
30-
}
16+
function getSigningKey(
17+
address operator
18+
) external view returns (address);
19+
}

0 commit comments

Comments
 (0)