|
| 1 | +## OperatorTableCalculator |
| 2 | + |
| 3 | +| File | Type | Notes | |
| 4 | +| -------- | -------- | |
| 5 | +| [`ECDSATableCalculatorBase.sol`](../../src/middlewareV2/tableCalculator/ECDSATableCalculatorBase.sol) | Abstract | Base functionality for ECDSA operator tables | |
| 6 | +| [`BN254TableCalculatorBase.sol`](../../src/middlewareV2/tableCalculator/BN254TableCalculatorBase.sol) | Abstract | Base functionality for BN254 operator tables | |
| 7 | + |
| 8 | +Interfaces: |
| 9 | + |
| 10 | +| File | Notes | |
| 11 | +| -------- | -------- | |
| 12 | +| [`IOperatorTableCalculator.sol`](../../lib/eigenlayer-contracts/src/contracts/interfaces/IOperatorTableCalculator.sol) | Base interface for all calculators (in core repo) | |
| 13 | +| [`IECDSATableCalculator.sol`](../../src/interfaces/IECDSATableCalculator.sol) | ECDSA-specific interface | |
| 14 | +| [`IBN254TableCalculator.sol`](../../src/interfaces/IBN254TableCalculator.sol) | BN254-specific interface | |
| 15 | + |
| 16 | +--- |
| 17 | + |
| 18 | +## Overview |
| 19 | + |
| 20 | +The OperatorTableCalculator contracts are responsible for calculating stake weights of operator. These stake weights are aggregated and transported using the [Eigenlayer Multichain Protocol](https://github.com/eigenfoundation/ELIPs/blob/main/ELIPs/ELIP-008.md). In order to utilize the multichain protocol, an AVS *MUST* deploy an `OperatorTableCalculator` and register it in the `CrossChainRegistry` in EigenLayer core. See our [core documentation](https://github.com/Layr-Labs/eigenlayer-contracts/tree/release-dev/multichain/docs/multichain#common-user-flows) for this process. |
| 21 | + |
| 22 | +The base contracts (`ECDSATableCalculatorBase` and `BN254TableCalculatorBase`) provide the core logic for table calculation to be consumed by EigenLayer core, while leaving weight calculation as an unimplemented method to be implemented by derived contracts. |
| 23 | + |
| 24 | +### Stake Weighting |
| 25 | + |
| 26 | +It is up to the AVS to define each operator's weights array in an operatorSet. Some examples include: |
| 27 | + |
| 28 | +- A single array evaluated purely on slashable stake `[slashable_stake]` |
| 29 | +- An array of 2 values can be used for evaluating on slashable and delegated stake `[slashable_stake, delegated_stake]` |
| 30 | +- An array of several values can be used for evaluating stake on multiple strategies `[slashable_stake_stETH, slashable_stake_USDC, slashable_stake_EIGEN]` |
| 31 | + |
| 32 | +In addition, an AVS can build custom calculation methodologies that include: |
| 33 | +- Capping the stake of an operator |
| 34 | +- Using oracles to price stake |
| 35 | + |
| 36 | +The [`ECDSATableCalculator`](../../src/middlewareV2/tableCalculator/ECDSATableCalculator.sol) and [`BN254TableCalculator`](../../src/middlewareV2/tableCalculator/BN254TableCalculator.sol) value slashable stake equally across all strategies. For example, if an operator allocates 100 stETH, 100 wETH, and 100 the calculator would return 300 for the stake weight of the operator. |
| 37 | + |
| 38 | + |
| 39 | +--- |
| 40 | + |
| 41 | +## ECDSATableCalculatorBase |
| 42 | + |
| 43 | +The `ECDSATableCalculatorBase` provides base functionality for calculating ECDSA operator tables. It handles operator key retrieval and table construction. |
| 44 | + |
| 45 | +### Core Functions |
| 46 | + |
| 47 | +#### `calculateOperatorTable` |
| 48 | + |
| 49 | +```solidity |
| 50 | +/** |
| 51 | + * @notice A struct that contains information about a single operator |
| 52 | + * @param pubkey The address of the signing ECDSA key of the operator and not the operator address itself. |
| 53 | + * This is read from the KeyRegistrar contract. |
| 54 | + * @param weights The weights of the operator for a single operatorSet |
| 55 | + * @dev The `weights` array can be defined as a list of arbitrary groupings. For example, |
| 56 | + * it can be [slashable_stake, delegated_stake, strategy_i_stake, ...] |
| 57 | + * @dev The `weights` array should be the same length for each operator in the operatorSet. |
| 58 | + */ |
| 59 | +struct ECDSAOperatorInfo { |
| 60 | + address pubkey; |
| 61 | + uint256[] weights; |
| 62 | +} |
| 63 | +
|
| 64 | +/** |
| 65 | + * @notice calculates the operatorInfos for a given operatorSet |
| 66 | + * @param operatorSet the operatorSet to calculate the operator table for |
| 67 | + * @return operatorInfos the list of operatorInfos for the given operatorSet |
| 68 | + * @dev The output of this function is converted to bytes via the `calculateOperatorTableBytes` function |
| 69 | + */ |
| 70 | +function calculateOperatorTable( |
| 71 | + OperatorSet calldata operatorSet |
| 72 | +) external view returns (ECDSAOperatorInfo[] memory operatorInfos); |
| 73 | +``` |
| 74 | + |
| 75 | +Calculates and returns an array of `ECDSAOperatorInfo` structs containing public keys and weights for all operators in the operatorSet who have registered ECDSA keys. |
| 76 | + |
| 77 | +*Effects*: |
| 78 | +* None (view function) |
| 79 | + |
| 80 | +*Process*: |
| 81 | +* Calls `_getOperatorWeights` to retrieve operator addresses and their weights |
| 82 | +* For each operator with a registered ECDSA key: |
| 83 | + * Retrieves the ECDSA address (public key) from the `KeyRegistrar` |
| 84 | + * Creates an `ECDSAOperatorInfo` struct with the public key and weights |
| 85 | +* Returns only operators with registered keys |
| 86 | + |
| 87 | +#### `calculateOperatorTableBytes` |
| 88 | + |
| 89 | +```solidity |
| 90 | +/** |
| 91 | + * @notice Calculates the operator table bytes for a given operatorSet |
| 92 | + * @param operatorSet The operatorSet to calculate the operator table for |
| 93 | + * @return operatorTableBytes The encoded operator table bytes |
| 94 | + */ |
| 95 | +function calculateOperatorTableBytes( |
| 96 | + OperatorSet calldata operatorSet |
| 97 | +) external view returns (bytes memory operatorTableBytes); |
| 98 | +``` |
| 99 | + |
| 100 | +Returns the ABI-encoded bytes representation of the operator table, which is used by the `CrossChainRegistry` to calculate the operatorTable. |
| 101 | + |
| 102 | +*Returns*: |
| 103 | +* ABI-encoded array of `ECDSAOperatorInfo` structs |
| 104 | + |
| 105 | +### Abstract Methods |
| 106 | + |
| 107 | +#### `_getOperatorWeights` |
| 108 | + |
| 109 | +```solidity |
| 110 | +/** |
| 111 | + * @notice Abstract function to get the operator weights for a given operatorSet |
| 112 | + * @param operatorSet The operatorSet to get the weights for |
| 113 | + * @return operators The addresses of the operators in the operatorSet |
| 114 | + * @return weights The weights for each operator in the operatorSet |
| 115 | + */ |
| 116 | +function _getOperatorWeights( |
| 117 | + OperatorSet calldata operatorSet |
| 118 | +) internal view virtual returns (address[] memory operators, uint256[][] memory weights); |
| 119 | +``` |
| 120 | + |
| 121 | +Must be implemented by derived contracts to define the weight calculation strategy. See [stakeWeighting](#stake-weighting) for more information. |
| 122 | + |
| 123 | +An example integration is in [`ECDSATableCalculator`](../../src/middlewareV2/tableCalculator/ECDSATableCalculator.sol) |
| 124 | + |
| 125 | +--- |
| 126 | + |
| 127 | +## BN254TableCalculatorBase |
| 128 | + |
| 129 | +The `BN254TableCalculatorBase` provides base functionality for calculating BN254 operator tables. |
| 130 | + |
| 131 | +### Core Functions |
| 132 | + |
| 133 | +#### `calculateOperatorTable` |
| 134 | + |
| 135 | +```solidity |
| 136 | +/** |
| 137 | + * @notice A struct that contains information about a single operator |
| 138 | + * @param pubkey The G1 public key of the operator. |
| 139 | + * @param weights The weights of the operator for a single operatorSet. |
| 140 | + * @dev The `weights` array can be defined as a list of arbitrary groupings. For example, |
| 141 | + * it can be [slashable_stake, delegated_stake, strategy_i_stake, ...] |
| 142 | + */ |
| 143 | +struct BN254OperatorInfo { |
| 144 | + BN254.G1Point pubkey; |
| 145 | + uint256[] weights; |
| 146 | +} |
| 147 | +
|
| 148 | +/** |
| 149 | + * @notice A struct that contains information about all operators for a given operatorSet |
| 150 | + * @param operatorInfoTreeRoot The root of the operatorInfo tree. Each leaf is a `BN254OperatorInfo` struct |
| 151 | + * @param numOperators The number of operators in the operatorSet. |
| 152 | + * @param aggregatePubkey The aggregate G1 public key of the operators in the operatorSet. |
| 153 | + * @param totalWeights The total weights of the operators in the operatorSet. |
| 154 | + * |
| 155 | + * @dev The operatorInfoTreeRoot is the root of a merkle tree that contains the operatorInfos for each operator in the operatorSet. |
| 156 | + * It is calculated in this function and used by the `IBN254CertificateVerifier` to verify stakes against the non-signing operators |
| 157 | + * |
| 158 | + * @dev Retrieval of the `aggregatePubKey` depends on maintaining a key registry contract, see `BN254TableCalculatorBase` for an example implementation. |
| 159 | + * |
| 160 | + * @dev The `totalWeights` array should be the same length as each individual `weights` array in `operatorInfos`. |
| 161 | + */ |
| 162 | +struct BN254OperatorSetInfo { |
| 163 | + bytes32 operatorInfoTreeRoot; |
| 164 | + uint256 numOperators; |
| 165 | + BN254.G1Point aggregatePubkey; |
| 166 | + uint256[] totalWeights; |
| 167 | +} |
| 168 | +
|
| 169 | +/** |
| 170 | + * @notice calculates the operatorInfos for a given operatorSet |
| 171 | + * @param operatorSet the operatorSet to calculate the operator table for |
| 172 | + * @return operatorSetInfo the operatorSetInfo for the given operatorSet |
| 173 | + * @dev The output of this function is converted to bytes via the `calculateOperatorTableBytes` function |
| 174 | + */ |
| 175 | +function calculateOperatorTable( |
| 176 | + OperatorSet calldata operatorSet |
| 177 | +) external view returns (BN254OperatorSetInfo memory operatorSetInfo); |
| 178 | +``` |
| 179 | + |
| 180 | +Calculates and returns a `BN254OperatorSetInfo` struct containing: |
| 181 | +- A merkle tree root of operator information |
| 182 | +- The total number of operators |
| 183 | +- An aggregate BN254 public key |
| 184 | +- Total weights across all operators |
| 185 | + |
| 186 | +*Effects*: |
| 187 | +* None (view function) |
| 188 | + |
| 189 | +*Process*: |
| 190 | +* Calls `_getOperatorWeights` to retrieve operator addresses and their weights |
| 191 | +* For each operator with a registered BN254 key: |
| 192 | + * Retrieves the BN254 G1 point from the `KeyRegistrar` |
| 193 | + * Adds the operator's weights to the total weights |
| 194 | + * Creates a merkle leaf from the operator info |
| 195 | + * Adds the G1 point to the aggregate public key |
| 196 | +* Constructs a merkle tree from all operator info leaves |
| 197 | +* Returns the complete operator set information |
| 198 | + |
| 199 | +BN254 tables take advantage of signature aggregation. As such, we add operator's weights to the total weights. We generate a merkle root that contains individual operator stakes (`BN254OperatorInfo`) to lower transport costs. See the core [`BN254CertificateVerifier`](https://github.com/Layr-Labs/eigenlayer-contracts/blob/release-dev/multichain/docs/multichain/destination/CertificateVerifier.md) for more information on the caching and verification scheme. |
| 200 | + |
| 201 | +#### `calculateOperatorTableBytes` |
| 202 | + |
| 203 | +```solidity |
| 204 | +/** |
| 205 | + * @notice Calculates the operator table bytes for a given operatorSet |
| 206 | + * @param operatorSet The operatorSet to calculate the operator table for |
| 207 | + * @return operatorTableBytes The encoded operator table bytes |
| 208 | + */ |
| 209 | +function calculateOperatorTableBytes( |
| 210 | + OperatorSet calldata operatorSet |
| 211 | +) external view returns (bytes memory operatorTableBytes); |
| 212 | +``` |
| 213 | + |
| 214 | +Returns the ABI-encoded bytes representation of the operator table, which is used by the `CrossChainRegistry` to calculate the operatorTable. |
| 215 | + |
| 216 | +*Returns*: |
| 217 | +* ABI-encoded `BN254OperatorSetInfo` struct |
| 218 | + |
| 219 | +#### `getOperatorInfos` |
| 220 | + |
| 221 | +```solidity |
| 222 | +/** |
| 223 | + * @notice Get the operatorInfos for a given operatorSet |
| 224 | + * @param operatorSet the operatorSet to get the operatorInfos for |
| 225 | + * @return operatorInfos the operatorInfos for the given operatorSet |
| 226 | + */ |
| 227 | +function getOperatorInfos( |
| 228 | + OperatorSet calldata operatorSet |
| 229 | +) external view returns (BN254OperatorInfo[] memory operatorInfos); |
| 230 | +``` |
| 231 | + |
| 232 | +Returns an array of `BN254OperatorInfo` structs for all operators in the operatorSet who have registered BN254 keys. |
| 233 | + |
| 234 | +*Effects*: |
| 235 | +* None (view function) |
| 236 | + |
| 237 | +### Abstract Methods |
| 238 | + |
| 239 | +#### `_getOperatorWeights` |
| 240 | + |
| 241 | +```solidity |
| 242 | +/** |
| 243 | + * @notice Abstract function to get the operator weights for a given operatorSet |
| 244 | + * @param operatorSet The operatorSet to get the weights for |
| 245 | + * @return operators The addresses of the operators in the operatorSet |
| 246 | + * @return weights The weights for each operator in the operatorSet |
| 247 | + */ |
| 248 | +function _getOperatorWeights( |
| 249 | + OperatorSet calldata operatorSet |
| 250 | +) internal view virtual returns (address[] memory operators, uint256[][] memory weights); |
| 251 | +``` |
| 252 | + |
| 253 | +Must be implemented by derived contracts to define the weight calculation strategy. Similar to ECDSA, weights are a 2D array supporting multiple weight types per operator. |
| 254 | + |
| 255 | +An example integration is defined in [`BN254TableCalculator`](../../src/middlewareV2/tableCalculator/BN254TableCalculator.sol). |
0 commit comments