Skip to content

Commit 2809671

Browse files
stevennevinsypatil12steven8sunyuan0x0aa0
authored
fixes(m2-mainnet): combined pr for all m2-mainnet fixs (#162)
* update: change core submodule branch * fix: make commit hook executable again (#160) Co-authored-by: steven <[email protected]> * ci: add ci to run on PRs to m2-mainnet-fixes (#159) Co-authored-by: steven <[email protected]> * refactor: update minWithdrawalDelayBLocks variable (#152) * refactor: minWithdrawalDelayBLocks from core * fix: core contracts commit and tests * feat: add avs directory to service manager * fix: rebase off updated bls sig checker; update integration tests * Add AVS Directory Support to Service Manager (#156) * update: change core submodule branch * feat: add avs directory to service manager * fix: rebase off updated bls sig checker; update integration tests * fix: core contracts commit and tests * feat: add avs directory to service manager * fix: rebase off updated bls sig checker; update integration tests * fix: conflicts --------- Co-authored-by: 8sunyuan <[email protected]> * fix: submodule commit * fix: rebase changes * Add AVS Directory Support to Service Manager (#156) * update: change core submodule branch * feat: add avs directory to service manager * fix: rebase off updated bls sig checker; update integration tests * fix: core contracts commit and tests * feat: add avs directory to service manager * fix: rebase off updated bls sig checker; update integration tests * fix: conflicts --------- Co-authored-by: 8sunyuan <[email protected]> * fix: submodule commit * fix: rebase changes * Add AVS Directory Support to Service Manager (#156) * update: change core submodule branch * feat: add avs directory to service manager * fix: rebase off updated bls sig checker; update integration tests * fix: core contracts commit and tests * feat: add avs directory to service manager * fix: rebase off updated bls sig checker; update integration tests * fix: conflicts --------- Co-authored-by: 8sunyuan <[email protected]> * fix: submodule commit * docs: AVSRegistry -> AVSDirectory --------- Co-authored-by: Yash Patil <[email protected]> * fix: churner (#157) * fix: submodule (#164) * test: fix flaky tests by removing bogosort (#163) * test: fix flaky tests by removing bogosort * test: fix flaky test by rejecting empty addr inputs * chore: storage gaps and nits (#155) * chore: add storage gaps to BLSSignatureChecker and ServiceManagerBase * chore: ServiceManagerBase to abstract and create mock * chore: use onlyInitializing in Base and initializer in mock * chore: add storage gaps to BLSSignatureChecker and ServiceManagerBase * chore: ServiceManagerBase to abstract and create mock * chore: use onlyInitializing in Base and initializer in mock * fix: core submodules --------- Co-authored-by: steven <[email protected]> * chore: eigenlayer-contracts (#168) * test/refactor: gas scenarios for updateOperators (#170) * test: gas scenarios for updateOperators * refactor: using one call for operatorShares * test: updateOperators 200 operators * test: gas scenarios for updateOperators * refactor: using one call for operatorShares * test: updateOperators 200 operators * fix: comments * chore: less restrictive license for library code (#177) MIT instead of BSL-MIT mix * docs: update README to point at deployment info (#178) * feat: minor gas optimization (#183) slightly less memory ops in `orderedBytesArrayToBitmap` fnc * fix: include missing fields in TYPEHASH defintion (#182) * fix: include missing fields in TYPEHASH defintion the `salt` and `expiry` fields were missing from the `OPERATOR_CHURN_APPROVAL_TYPEHASH` def * fix: correct definition of OperatorKickParam inside of typehash def * docs: fix grammer and inaccurate naming (#179) * fix: prevent use of current block as reference block number (#181) * chore: clean up loops to iterate downward and remove unneeded checks (#180) * chore: clean up loops to iterate downward and remove unneeded checks * docs: clarifying comments around quorum existence checks * docs: clarify usage of msgHash (#184) --------- Co-authored-by: Yash Patil <[email protected]> Co-authored-by: steven <[email protected]> Co-authored-by: Michael Sun <[email protected]> Co-authored-by: quaq <[email protected]> Co-authored-by: Alex <[email protected]> Co-authored-by: ChaoticWalrus <[email protected]>
1 parent 6e95af9 commit 2809671

38 files changed

+1769
-207
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ on:
99
branches:
1010
- master
1111
- m2-mainnet
12+
- m2-mainnet-fixes
1213
pull_request:
1314

1415
env:

.gitmodules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[submodule "lib/eigenlayer-contracts"]
55
path = lib/eigenlayer-contracts
66
url = https://github.com/Layr-labs/eigenlayer-contracts
7-
branch = m2-mainnet
7+
branch = m2-mainnet-fixes
88
[submodule "lib/ds-test"]
99
path = lib/ds-test
1010
url = https://github.com/dapphub/ds-test

.husky/commit-msg

100644100755
File mode changed.

README.md

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,12 @@
55

66
EigenLayer is a set of smart contracts deployed on Ethereum that enable restaking of assets to secure new services called AVSs (actively validated services). The core contracts that enable these features can be found in the [`eigenlayer-contracts` repo][core-repo].
77

8-
This repo contains smart contracts used to create an AVS that interacts with the EigenLayer core contracts.
8+
This repo contains smart contracts used to create an AVS that interacts with the EigenLayer core contracts. Because these contracts are meant to be used by any AVS, there is no single deployment. However, you can see EigenDA's deployment info on our [docs site](https://docs.eigenlayer.xyz/eigenda/deployed-contracts).
99

1010
## Getting Started
1111

1212
* [Documentation](#documentation)
1313
* [Building and Running Tests](#building-and-running-tests)
14-
* [Deployments](#deployments)
1514

1615
## Documentation
1716

@@ -39,28 +38,4 @@ foundryup
3938

4039
forge build
4140
forge test
42-
```
43-
44-
## Deployments
45-
46-
The contracts in this repo are meant to be deployed by each AVS that wants to use them. The addresses listed below refer to EigenDA's deployment, and are included as an example.
47-
48-
### Current Mainnet Deployment
49-
50-
No contracts have been deployed to mainnet yet.
51-
52-
### Current Testnet Deployment
53-
54-
The current testnet deployment is from our M2 beta release, which is a slightly older version of this repo. You can view the deployed contract addresses below, or check out the [`v0.1.0`](https://github.com/Layr-Labs/eigenlayer-middleware/tree/v0.1.0-m2-goerli) branch in "Releases".
55-
56-
57-
| Name | Solidity | Proxy | Implementation | Notes |
58-
| -------- | -------- | -------- | -------- | -------- |
59-
| RegistryCoordinator | [`BLSRegistryCoordinatorWithIndices.sol`](https://github.com/Layr-Labs/eigenlayer-middleware/blob/v0.1.0-m2-goerli/src/BLSRegistryCoordinatorWithIndices.sol) | [`0x0b30...4C0B`](https://goerli.etherscan.io/address/0x0b30a3427765f136754368a4500bAca8d2a54C0B) | [`0x9A70...a0e4`](https://goerli.etherscan.io/address/0x9A70ED111FaFEC41856202536AFAA38841a9a0e4) | Proxy: [OpenZeppelin [email protected]](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) |
60-
| StakeRegistry | [`StakeRegistry.sol`](https://github.com/Layr-Labs/eigenlayer-middleware/blob/v0.1.0-m2-goerli/src/StakeRegistry.sol) | [`0x5a83...A206`](https://goerli.etherscan.io/address/0x5a834d58D22742503D8f92dd2f28c866C166A206) | [`0x8741...5B98`](https://goerli.etherscan.io/address/0x8741e3a24d9517Aa19E63122A34680a9A85F5B98) | Proxy: [OpenZeppelin [email protected]](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) |
61-
| IndexRegistry | [`IndexRegistry.sol`](https://github.com/Layr-Labs/eigenlayer-middleware/blob/v0.1.0-m2-goerli/src/IndexRegistry.sol) | [`0xa8A1...BDF7`](https://goerli.etherscan.io/address/0xa8A14B97d556cEc3f4384C186fB99d72F015BDF7) | [`0x8cd4...8117`](https://goerli.etherscan.io/address/0x8cd4c39B713B026319e35f20B7f19baE28648117) | Proxy: [OpenZeppelin [email protected]](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) |
62-
| BLSApkRegistry | [`BLSPubkeyRegistry.sol`](https://github.com/Layr-Labs/eigenlayer-middleware/blob/v0.1.0-m2-goerli/src/BLSPubkeyRegistry.sol) | [`0xD8fC...BEcA`](https://goerli.etherscan.io/address/0xD8fCD5c9103962DE37E375EF9dB62cCf39D5BEcA) | [`0x4C9D...aFb8`](https://goerli.etherscan.io/address/0x4C9D23fd901d3d98e75BdcC6a8AC9bA81d8DaFb8) | Proxy: [OpenZeppelin [email protected]](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) |
63-
| BLSPubkeyCompendium <br />(deprecated) | [`BLSPublicKeyCompendium.sol`](https://github.com/Layr-Labs/eigenlayer-middleware/blob/v0.1.0-m2-goerli/src/BLSPublicKeyCompendium.sol) | - | [`0xc81d...1b19`](https://goerli.etherscan.io/address/0xc81d3963087fe09316cd1e032457989c7ac91b19) | |
64-
| OperatorStateRetriever | [`BLSOperatorStateRetriever.sol`](https://github.com/Layr-Labs/eigenlayer-middleware/blob/v0.1.0-m2-goerli/src/BLSOperatorStateRetriever.sol) | - | [`0x737d...a3a3`](https://goerli.etherscan.io/address/0x737dd62816a9392e84fa21c531af77c00816a3a3) | |
65-
| ProxyAdmin | [OpenZeppelin [email protected]](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/ProxyAdmin.sol) | - | [`0xbe85...aF3e`](https://goerli.etherscan.io/address/0xbe85B38b6086A45350947DD6dA6d78cc2E4BaF3e) | |
66-
| EigenDAServiceManager | [`eigenda/EigenDAServiceManager.sol`](https://github.com/Layr-Labs/eigenda/blob/f599513723a17ad7bd5693287f75325007deec19/contracts/EigenDAServiceManager.sol#L4831) | [`0x9FcE...0010`](https://goerli.etherscan.io/address/0x9FcE30E01a740660189bD8CbEaA48Abd36040010) | [`0x1261...9606`](https://goerli.etherscan.io/address/0x12612f42bc1f09680c3d0c8dae72d5cd534c9606) | Proxy: [OpenZeppelin [email protected]](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) |
41+
```

docs/BLSSignatureChecker.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ struct QuorumStakeTotals {
6262
The goal of this method is to allow an AVS to validate a BLS signature formed from the aggregate pubkey ("apk") of Operators registered in one or more quorums at some `referenceBlockNumber`.
6363

6464
Some notes on method parameters:
65+
* `msgHash` is the hash being signed by the apk. Note that the caller is responsible for ensuring `msgHash` is a hash! If someone can provide arbitrary input, it may be possible to tamper with signature verification.
6566
* `referenceBlockNumber` is the reason each registry contract keeps historical states: so that lookups can be performed on each registry's info at a particular block. This is important because Operators may sign some data on behalf of an AVS, then deregister from one or more of the AVS's quorums. Historical states allow signature validation to be performed against a "fixed point" in AVS/quorum history.
6667
* `quorumNumbers` is used to perform signature validation across one *or more* quorums. Also, Operators may be registered for more than one quorum - and for each quorum an Operator is registered for, that Operator's pubkey is included in that quorum's apk within the `BLSApkRegistry`. This means that, when calculating an apk across multiple `quorumNumbers`, Operators registered for more than one of these quorums will have their pubkey included more than once in the total apk.
6768
* `params` contains both a signature from all signing Operators, as well as several fields that identify registered, non-signing Operators. While non-signing Operators haven't contributed to the signature, but need to be accounted for because, as Operators registered for one or more signing quorums, their public keys are included in that quorum's apk. Essentially, in order to validate the signature, nonsigners' public keys need to be subtracted out from the total apk to derive the apk that actually signed the message.
@@ -87,11 +88,11 @@ This method performs the following steps. Note that each step involves lookups o
8788
* Input validation:
8889
* Quorum-related fields MUST have equal lengths: `quorumNumbers`, `params.quorumApks`, `params.quorumApkIndices`, `params.totalStakeIndices`, `params.nonSignerStakeIndices`
8990
* Nonsigner-related fields MUST have equal lengths: `params.nonSignerPubkeys`, `params.nonSignerQuorumBitmapIndices`
90-
* `referenceBlockNumber` MUST NOT be greater than `block.number`
91+
* `referenceBlockNumber` MUST be less than `block.number`
9192
* `quorumNumbers` MUST be an ordered list of valid, initialized quorums
9293
* `params.nonSignerPubkeys` MUST ONLY contain unique pubkeys, in ascending order of their pubkey hash
9394
* For each quorum:
94-
* If stale stakes are forbidden (see [`BLSSignatureChecker.setStaleStakesForbidden`](#blssignaturecheckersetstalestakesforbidden)), check the last `quorumUpdateBlockNumber` is within `DelegationManager.withdrawalDelayBlocks` of `referenceBlockNumber`. This references a value in the EigenLayer core contracts - see [EigenLayer core docs][core-docs-m2] for more info.
95+
* If stale stakes are forbidden (see [`BLSSignatureChecker.setStaleStakesForbidden`](#blssignaturecheckersetstalestakesforbidden)), check the last `quorumUpdateBlockNumber` is within `DelegationManager.minWithdrawalDelayBlocks` of `referenceBlockNumber`. This references a value in the EigenLayer core contracts - see [EigenLayer core docs][core-docs-m2] for more info.
9596
* Validate that each `params.quorumApks` corresponds to the quorum's apk at the `referenceBlockNumber`
9697
* For each historical state lookup, the `referenceBlockNumber` and provided index MUST point to a valid historical entry:
9798
* `referenceBlockNumber` MUST come after the entry's `updateBlockNumber`

docs/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ These histories are used by offchain code to query state at particular blocks, a
9797
##### Hooking Into EigenLayer Core
9898

9999
The main thing that links an AVS to the EigenLayer core contracts is that when EigenLayer Operators register/deregister with an AVS, the AVS calls these functions in EigenLayer core:
100-
* [`DelegationManager.registerOperatorToAVS`][core-registerToAVS]
101-
* [`DelegationManager.deregisterOperatorFromAVS`][core-deregisterFromAVS]
100+
* [`AVSDirectory.registerOperatorToAVS`][core-registerToAVS]
101+
* [`AVSDirectory.deregisterOperatorFromAVS`][core-deregisterFromAVS]
102102

103103
These methods ensure that the Operator registering with the AVS is also registered as an Operator in EigenLayer core. In this repo, these methods are called by the `ServiceManagerBase`.
104104

lib/eigenlayer-contracts

Submodule eigenlayer-contracts updated 65 files

src/BLSApkRegistry.sol

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -205,19 +205,19 @@ contract BLSApkRegistry is BLSApkRegistryStorage {
205205
uint256 blockNumber
206206
) external view returns (uint32[] memory) {
207207
uint32[] memory indices = new uint32[](quorumNumbers.length);
208-
for (uint i = 0; i < quorumNumbers.length; i++) {
208+
209+
for (uint256 i = 0; i < quorumNumbers.length; i++) {
209210
uint8 quorumNumber = uint8(quorumNumbers[i]);
210-
uint32 quorumApkUpdatesLength = uint32(apkHistory[quorumNumber].length);
211-
211+
212+
uint256 quorumApkUpdatesLength = apkHistory[quorumNumber].length;
212213
if (quorumApkUpdatesLength == 0 || blockNumber < apkHistory[quorumNumber][0].updateBlockNumber) {
213-
revert(
214-
"BLSApkRegistry.getApkIndicesAtBlockNumber: blockNumber is before the first update"
215-
);
214+
revert("BLSApkRegistry.getApkIndicesAtBlockNumber: blockNumber is before the first update");
216215
}
217216

218-
for (uint32 j = 0; j < quorumApkUpdatesLength; j++) {
219-
if (apkHistory[quorumNumber][quorumApkUpdatesLength - j - 1].updateBlockNumber <= blockNumber) {
220-
indices[i] = quorumApkUpdatesLength - j - 1;
217+
// Loop backward through apkHistory until we find an entry that preceeds `blockNumber`
218+
for (uint256 j = quorumApkUpdatesLength; j > 0; j--) {
219+
if (apkHistory[quorumNumber][j - 1].updateBlockNumber <= blockNumber) {
220+
indices[i] = uint32(j - 1);
221221
break;
222222
}
223223
}

src/BLSSignatureChecker.sol

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ contract BLSSignatureChecker is IBLSSignatureChecker {
4646

4747
/**
4848
* RegistryCoordinator owner can either enforce or not that operator stakes are staler
49-
* than the delegation.withdrawalDelayBlocks() window.
49+
* than the delegation.minWithdrawalDelayBlocks() window.
5050
* @param value to toggle staleStakesForbidden
5151
*/
5252
function setStaleStakesForbidden(bool value) external onlyCoordinatorOwner {
@@ -75,6 +75,9 @@ contract BLSSignatureChecker is IBLSSignatureChecker {
7575
* is correct, i.e., ensure that the stake returned from the specified block number is recent enough and that the stake is either the most recent update
7676
* for the total stake (of the operator) or latest before the referenceBlockNumber.
7777
* @param msgHash is the hash being signed
78+
* @dev NOTE: Be careful to ensure `msgHash` is collision-resistant! This method does not hash
79+
* `msgHash` in any way, so if an attacker is able to pass in an arbitrary value, they may be able
80+
* to tamper with signature verification.
7881
* @param quorumNumbers is the bytes array of quorum numbers that are being signed for
7982
* @param referenceBlockNumber is the block number at which the stake information is being verified
8083
* @param params is the struct containing information on nonsigners, stakes, quorum apks, and the aggregate signature
@@ -109,7 +112,7 @@ contract BLSSignatureChecker is IBLSSignatureChecker {
109112
"BLSSignatureChecker.checkSignatures: input nonsigner length mismatch"
110113
);
111114

112-
require(referenceBlockNumber <= uint32(block.number), "BLSSignatureChecker.checkSignatures: invalid reference block");
115+
require(referenceBlockNumber < uint32(block.number), "BLSSignatureChecker.checkSignatures: invalid reference block");
113116

114117
// This method needs to calculate the aggregate pubkey for all signing operators across
115118
// all signing quorums. To do that, we can query the aggregate pubkey for each quorum
@@ -179,8 +182,8 @@ contract BLSSignatureChecker is IBLSSignatureChecker {
179182
* - subtract the stake for each nonsigner to calculate the stake belonging to signers
180183
*/
181184
{
182-
uint256 withdrawalDelayBlocks = delegation.withdrawalDelayBlocks();
183185
bool _staleStakesForbidden = staleStakesForbidden;
186+
uint256 withdrawalDelayBlocks = _staleStakesForbidden ? delegation.minWithdrawalDelayBlocks() : 0;
184187

185188
for (uint256 i = 0; i < quorumNumbers.length; i++) {
186189
// If we're disallowing stale stake updates, check that each quorum's last update block
@@ -280,4 +283,8 @@ contract BLSSignatureChecker is IBLSSignatureChecker {
280283
PAIRING_EQUALITY_CHECK_GAS
281284
);
282285
}
286+
287+
// storage gap for upgradeability
288+
// slither-disable-next-line shadowing-state
289+
uint256[49] private __GAP;
283290
}

src/IndexRegistry.sol

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -253,13 +253,11 @@ contract IndexRegistry is IndexRegistryStorage {
253253
uint32 blockNumber
254254
) internal view returns (uint32){
255255
uint256 historyLength = _operatorCountHistory[quorumNumber].length;
256-
require(historyLength != 0, "IndexRegistry._operatorCountAtBlockNumber: quorum does not exist");
257256

258-
// Loop backwards through the total operator history
259-
for (uint256 i = 0; i < historyLength; i++) {
260-
uint256 listIndex = (historyLength - 1) - i;
261-
QuorumUpdate memory quorumUpdate = _operatorCountHistory[quorumNumber][listIndex];
262-
// Look for the first update that began before or at `blockNumber`
257+
// Loop backwards through _operatorCountHistory until we find an entry that preceeds `blockNumber`
258+
for (uint256 i = historyLength; i > 0; i--) {
259+
QuorumUpdate memory quorumUpdate = _operatorCountHistory[quorumNumber][i - 1];
260+
263261
if (quorumUpdate.fromBlockNumber <= blockNumber) {
264262
return quorumUpdate.numOperators;
265263
}
@@ -278,18 +276,18 @@ contract IndexRegistry is IndexRegistryStorage {
278276
uint32 blockNumber
279277
) internal view returns(bytes32) {
280278
uint256 historyLength = _operatorIndexHistory[quorumNumber][operatorIndex].length;
281-
// Loop backward through operatorIndex history
282-
for (uint256 i = 0; i < historyLength; i++) {
283-
uint256 listIndex = (historyLength - 1) - i;
284-
OperatorUpdate memory operatorIndexUpdate = _operatorIndexHistory[quorumNumber][operatorIndex][listIndex];
285-
// Look for the first update that began before or at `blockNumber`
279+
280+
// Loop backward through _operatorIndexHistory until we find an entry that preceeds `blockNumber`
281+
for (uint256 i = historyLength; i > 0; i--) {
282+
OperatorUpdate memory operatorIndexUpdate = _operatorIndexHistory[quorumNumber][operatorIndex][i - 1];
283+
286284
if (operatorIndexUpdate.fromBlockNumber <= blockNumber) {
287285
// Special case: this will be OPERATOR_DOES_NOT_EXIST_ID if this operatorIndex was not used at the block number
288286
return operatorIndexUpdate.operatorId;
289287
}
290288
}
291289

292-
// we should only it this if the operatorIndex was never used before blockNumber
290+
// we should only hit this if the operatorIndex was never used before blockNumber
293291
return OPERATOR_DOES_NOT_EXIST_ID;
294292
}
295293

0 commit comments

Comments
 (0)