From 7d49b5181b09198ed275783453aa082bb3766990 Mon Sep 17 00:00:00 2001 From: Gautham Anant <32277907+gpsanant@users.noreply.github.com> Date: Wed, 17 Jul 2024 08:42:54 -0700 Subject: [PATCH 01/52] Update LICENSE (#285) --- LICENSE | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/LICENSE b/LICENSE index 91921f64..b65b84a3 100644 --- a/LICENSE +++ b/LICENSE @@ -12,9 +12,35 @@ Licensor: Layr Labs, Inc. Licensed Work: EigenLayer Middleware Contracts The Licensed Work is (c) 2023 Layr Labs, Inc. -Additional Use Grant: None. - -Change Date: 2025-10-16 (October 16th, 2025) +Additional Use Grant: + +You may additionally use any of the software included in the following repositories +[here](https://docs.google.com/spreadsheets/d/1PlJRow5C0GMqXZlIxRm5CEnkhH-gMV1wIdq1pCfbZco/edit?usp=sharing) +(“Additional Use Grant Software”) for production commercial uses, but only if such +uses are (i) built on or using the EigenLayer Protocol or EigenDA, and (ii) not +Competing Uses. + +“Competing Use” means any use of the Additional Use Grant Software in any product, +protocol, application or service that is made available to third parties and that +(i) substitutes for use of EigenLayer Protocol or EigenDA, (ii) offers the same or +substantially similar functionality as the EigenLayer Protocol or EigenDA or +(iii) is built on or using a protocol with substantially similar functionality as +the EigenLayer Protocol. + +EigenLayer Protocol means the restaking protocol as further described in the +documentation [here](https://docs.eigenlayer.xyz/), as updated from time to time. + +EigenDA means the data availability protocol built on top of the EigenLayer +Protocol as further described in the documentation +[here](https://docs.eigenlayer.xyz/eigenda/overview), as updated from time to time. + +Change Dates: + +- All commits at or prior to commit a23de118e7d16081d350c7f83c24261d1421b0ba +(i.e. committed to this repository on or before May 19, 2024, the date of) have a +change date of 2025-10-16 (October 16th, 2025) +- All commits after a23de118e7d16081d350c7f83c24261d1421b0ba (i.e. committed to this +repository after May 19, 2024) have a change date of 2027-05-01 (May 1st, 2027) Change License: MIT From 163f4c334042accc12baacd284b78218e0a1c56e Mon Sep 17 00:00:00 2001 From: steven Date: Thu, 25 Jul 2024 10:53:02 -0400 Subject: [PATCH 02/52] chore: upgrade core to target operator set release --- lib/eigenlayer-contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eigenlayer-contracts b/lib/eigenlayer-contracts index bd1c9b2d..f88912de 160000 --- a/lib/eigenlayer-contracts +++ b/lib/eigenlayer-contracts @@ -1 +1 @@ -Subproject commit bd1c9b2d34e93ba5d0be224bc15d2c211848dad6 +Subproject commit f88912dec4ce2854b0f8824fb293e32eaa6c83d5 From b7f49030171fac63116337f78f1afcfa486f0f55 Mon Sep 17 00:00:00 2001 From: Madhur Shrimal Date: Mon, 5 Aug 2024 16:21:33 -0700 Subject: [PATCH 03/52] chore: update mock contracts with latest interfaces (#293) * chore: update mock contracts with latest interfaces --- lib/eigenlayer-contracts | 2 +- test/mocks/AVSDirectoryMock.sol | 123 ++++++++++++++++++++++++++ test/mocks/RewardsCoordinatorMock.sol | 32 +++++++ 3 files changed, 156 insertions(+), 1 deletion(-) diff --git a/lib/eigenlayer-contracts b/lib/eigenlayer-contracts index f88912de..4716a9c2 160000 --- a/lib/eigenlayer-contracts +++ b/lib/eigenlayer-contracts @@ -1 +1 @@ -Subproject commit f88912dec4ce2854b0f8824fb293e32eaa6c83d5 +Subproject commit 4716a9c2f32c3fcae6c32814be5d6f69b176bdf6 diff --git a/test/mocks/AVSDirectoryMock.sol b/test/mocks/AVSDirectoryMock.sol index 813e913a..581fe8b6 100644 --- a/test/mocks/AVSDirectoryMock.sol +++ b/test/mocks/AVSDirectoryMock.sol @@ -4,6 +4,83 @@ pragma solidity ^0.8.12; import {IAVSDirectory, ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; contract AVSDirectoryMock is IAVSDirectory { + /** + * @notice Called by an AVS to create a list of new operatorSets. + * + * @param operatorSetIds The IDs of the operator set to initialize. + * + * @dev msg.sender must be the AVS. + * @dev The AVS may create operator sets before it becomes an operator set AVS. + */ + function createOperatorSets(uint32[] calldata operatorSetIds) external {} + + /** + * @notice Sets the AVS as an operator set AVS, preventing legacy M2 operator registrations. + * + * @dev msg.sender must be the AVS. + */ + function becomeOperatorSetAVS() external {} + + /** + * @notice Called by an AVS to migrate operators that have a legacy M2 registration to operator sets. + * + * @param operators The list of operators to migrate + * @param operatorSetIds The list of operatorSets to migrate the operators to + * + * @dev The msg.sender used is the AVS + * @dev The operator can only be migrated at most once per AVS + * @dev The AVS can no longer register operators via the legacy M2 registration path once it begins migration + * @dev The operator is deregistered from the M2 legacy AVS once migrated + */ + function migrateOperatorsToOperatorSets( + address[] calldata operators, + uint32[][] calldata operatorSetIds + ) external {} + + /** + * @notice Called by AVSs to add an operator to list of operatorSets. + * + * @param operator The address of the operator to be added to the operator set. + * @param operatorSetIds The IDs of the operator sets. + * @param operatorSignature The signature of the operator on their intent to register. + * + * @dev msg.sender is used as the AVS. + * @dev The operator must not have a pending deregistration from the operator set. + */ + function registerOperatorToOperatorSets( + address operator, + uint32[] calldata operatorSetIds, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external {} + + /** + * @notice Called by AVSs to remove an operator from an operator set. + * + * @param operator The address of the operator to be removed from the operator set. + * @param operatorSetIds The IDs of the operator sets. + * + * @dev msg.sender is used as the AVS. + */ + function deregisterOperatorFromOperatorSets(address operator, uint32[] calldata operatorSetIds) external {} + + /** + * @notice Called by an operator to deregister from an operator set + * + * @param operator The operator to deregister from the operatorSets. + * @param avs The address of the AVS to deregister the operator from. + * @param operatorSetIds The IDs of the operator sets. + * @param operatorSignature the signature of the operator on their intent to deregister or empty if the operator itself is calling + * + * @dev if the operatorSignature is empty, the caller must be the operator + * @dev this will likely only be called in case the AVS contracts are in a state that prevents operators from deregistering + */ + function forceDeregisterFromOperatorSets( + address operator, + address avs, + uint32[] calldata operatorSetIds, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external {} + /** * @notice Called by an avs to register an operator with the avs. * @param operator The address of the operator to register. @@ -27,12 +104,21 @@ contract AVSDirectoryMock is IAVSDirectory { */ function updateAVSMetadataURI(string calldata metadataURI) external {} + /** + * @notice Called by an operator to cancel a salt that has been used to register with an AVS. + * + * @param salt A unique and single use value associated with the approver signature. + */ + function cancelSalt(bytes32 salt) external{} + /** * @notice Returns whether or not the salt has already been used by the operator. * @dev Salts is used in the `registerOperatorToAVS` function. */ function operatorSaltIsSpent(address operator, bytes32 salt) external view returns (bool) {} + function isMember(address avs, address operator, uint32 operatorSetId) external view returns (bool){} + /** * @notice Calculates the digest hash to be signed by an operator to register with an AVS * @param operator The account registering as an operator @@ -47,6 +133,43 @@ contract AVSDirectoryMock is IAVSDirectory { uint256 expiry ) external view returns (bytes32) {} + /** + * @notice Calculates the digest hash to be signed by an operator to register with an operator set. + * + * @param avs The AVS that operator is registering to operator sets for. + * @param operatorSetIds An array of operator set IDs the operator is registering to. + * @param salt A unique and single use value associated with the approver signature. + * @param expiry Time after which the approver's signature becomes invalid. + */ + function calculateOperatorSetRegistrationDigestHash( + address avs, + uint32[] calldata operatorSetIds, + bytes32 salt, + uint256 expiry + ) external view returns (bytes32) {} + + /** + * @notice Calculates the digest hash to be signed by an operator to force deregister from an operator set. + * + * @param avs The AVS that operator is deregistering from. + * @param operatorSetIds An array of operator set IDs the operator is deregistering from. + * @param salt A unique and single use value associated with the approver signature. + * @param expiry Time after which the approver's signature becomes invalid. + */ + function calculateOperatorSetForceDeregistrationTypehash( + address avs, + uint32[] calldata operatorSetIds, + bytes32 salt, + uint256 expiry + ) external view returns (bytes32) {} + + /// @notice Getter function for the current EIP-712 domain separator for this contract. + /// @dev The domain separator will change in the event of a fork that changes the ChainID. + function domainSeparator() external view returns (bytes32) {} + /// @notice The EIP-712 typehash for the Registration struct used by the contract function OPERATOR_AVS_REGISTRATION_TYPEHASH() external view returns (bytes32) {} + + /// @notice The EIP-712 typehash for the OperatorSetRegistration struct used by the contract. + function OPERATOR_SET_REGISTRATION_TYPEHASH() external view returns (bytes32) {} } diff --git a/test/mocks/RewardsCoordinatorMock.sol b/test/mocks/RewardsCoordinatorMock.sol index ff32a27a..11a6c94d 100644 --- a/test/mocks/RewardsCoordinatorMock.sol +++ b/test/mocks/RewardsCoordinatorMock.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.12; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import "./AVSDirectoryMock.sol"; contract RewardsCoordinatorMock is IRewardsCoordinator { /// @notice The address of the entity that can update the contract with new merkle roots @@ -25,6 +26,21 @@ contract RewardsCoordinatorMock is IRewardsCoordinator { function cumulativeClaimed(address claimer, IERC20 token) external view returns (uint256) {} + /// @notice the commission for a specific operator for a specific avs + /// NOTE: Currently unused and simply returns the globalOperatorCommissionBips value but will be used in future release + function getOperatorCommissionBips( + address operator, + IAVSDirectory.OperatorSet calldata operatorSet, + RewardType rewardType + ) external view returns (uint16) {} + + /// @notice returns the length of the operator commission update history + function getOperatorCommissionUpdateHistoryLength( + address operator, + IAVSDirectory.OperatorSet calldata operatorSet, + RewardType rewardType + ) external view returns (uint256) {} + function globalOperatorCommissionBips() external view returns (uint16) {} function operatorCommissionBips(address operator, address avs) external view returns (uint16) {} @@ -75,4 +91,20 @@ contract RewardsCoordinatorMock is IRewardsCoordinator { * @param _newValue The new value for isPayAllForRangeSubmitter */ function setRewardsForAllSubmitter(address _submitter, bool _newValue) external {} + + /** + * @notice Sets the commission an operator takes in bips for a given reward type and operatorSet + * @param operatorSet The operatorSet to update commission for + * @param rewardType The associated rewardType to update commission for + * @param commissionBips The commission in bips for the operator, must be <= MAX_COMMISSION_BIPS + * @return effectTimestamp The timestamp at which the operator commission update will take effect + * + * @dev The commission can range from 1 to 10000 + * @dev The commission update takes effect after 7 days + */ + function setOperatorCommissionBips( + IAVSDirectory.OperatorSet calldata operatorSet, + RewardType rewardType, + uint16 commissionBips + ) external returns (uint32) {} } \ No newline at end of file From d991827fe3d3f818c9e80b4f1b4c8e7644d19446 Mon Sep 17 00:00:00 2001 From: steven Date: Thu, 8 Aug 2024 07:25:32 -0400 Subject: [PATCH 04/52] chore: bump to latest operator set release commits --- lib/eigenlayer-contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eigenlayer-contracts b/lib/eigenlayer-contracts index 4716a9c2..ed44903c 160000 --- a/lib/eigenlayer-contracts +++ b/lib/eigenlayer-contracts @@ -1 +1 @@ -Subproject commit 4716a9c2f32c3fcae6c32814be5d6f69b176bdf6 +Subproject commit ed44903ca218a52cf259d226b5a60bee8a8320a7 From 496681381572567e1baeb02c4e6fa54e988ca739 Mon Sep 17 00:00:00 2001 From: steven Date: Thu, 8 Aug 2024 07:33:24 -0400 Subject: [PATCH 05/52] chore: fixes for depedency bump --- test/mocks/AVSDirectoryMock.sol | 4 ++++ test/mocks/RewardsCoordinatorMock.sol | 2 ++ test/unit/ServiceManagerBase.t.sol | 8 +++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/test/mocks/AVSDirectoryMock.sol b/test/mocks/AVSDirectoryMock.sol index 581fe8b6..fdb02613 100644 --- a/test/mocks/AVSDirectoryMock.sol +++ b/test/mocks/AVSDirectoryMock.sol @@ -172,4 +172,8 @@ contract AVSDirectoryMock is IAVSDirectory { /// @notice The EIP-712 typehash for the OperatorSetRegistration struct used by the contract. function OPERATOR_SET_REGISTRATION_TYPEHASH() external view returns (bytes32) {} + + function isOperatorSetAVS(address avs) external view returns (bool) {} + + function isOperatorSet(address avs, uint32 operatorSetId) external view returns (bool){} } diff --git a/test/mocks/RewardsCoordinatorMock.sol b/test/mocks/RewardsCoordinatorMock.sol index 11a6c94d..6e4f6538 100644 --- a/test/mocks/RewardsCoordinatorMock.sol +++ b/test/mocks/RewardsCoordinatorMock.sol @@ -107,4 +107,6 @@ contract RewardsCoordinatorMock is IRewardsCoordinator { RewardType rewardType, uint16 commissionBips ) external returns (uint32) {} + + function rewardOperatorSetForRange(OperatorSetRewardsSubmission[] calldata rewardsSubmissions) external{} } \ No newline at end of file diff --git a/test/unit/ServiceManagerBase.t.sol b/test/unit/ServiceManagerBase.t.sol index 2b04dabd..7673facd 100644 --- a/test/unit/ServiceManagerBase.t.sol +++ b/test/unit/ServiceManagerBase.t.sol @@ -21,6 +21,9 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve uint32 MAX_FUTURE_LENGTH = 28 days; uint32 GENESIS_REWARDS_TIMESTAMP = 1_712_188_800; uint256 MAX_REWARDS_AMOUNT = 1e38 - 1; + uint32 OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP = 0; /// TODO: what values should these have + uint32 OPERATOR_SET_MAX_RETROACTIVE_LENGTH = 0; /// TODO: What values these should have + /// @notice Delay in timestamp before a posted root can be claimed against uint32 activationDelay = 7 days; /// @notice the commission for all operators across all avss @@ -51,11 +54,14 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve rewardsCoordinatorImplementation = new RewardsCoordinator( delegationMock, strategyManagerMock, + avsDirectoryMock, CALCULATION_INTERVAL_SECONDS, MAX_REWARDS_DURATION, MAX_RETROACTIVE_LENGTH, MAX_FUTURE_LENGTH, - GENESIS_REWARDS_TIMESTAMP + GENESIS_REWARDS_TIMESTAMP, + OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP, + OPERATOR_SET_MAX_RETROACTIVE_LENGTH ); rewardsCoordinator = RewardsCoordinator( From 4fabf8074ad2e827f9d3da25420beaa6ae5e4926 Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Mon, 12 Aug 2024 09:46:27 -0400 Subject: [PATCH 06/52] feat: operator set migration-1-migration (#286) * chore: checkout migration branch * feat: implement migration function * chore: update to release branch * feat: operator set creation for each quorum number * feat: migration with merge sorted array of operators and their quorums * feat: operator set migration working * chore: revert change from testing * chore: revert change from testing * chore: remove extra logging and commented out asserts * chore: remove unused file * fix: remove console logs * refactor: to view functions * chore: nit and remove unneeded function * fix: remove duplication of looping for all the operators * chore: remove comment * feat: allow migrating in two transactions * feat: finalization of migration * chore: use string errors and fix migration issues * chore: rename * feat: use library for merge sort * test: fuzz view function --- src/ServiceManagerBase.sol | 74 ++++++ src/ServiceManagerBaseStorage.sol | 2 + src/libraries/LibMergeSort.sol | 61 +++++ test/harnesses/AVSDirectoryHarness.sol | 49 ++++ test/unit/LibMergeSort.t.sol | 188 ++++++++++++++ test/unit/ServiceManagerBase.t.sol | 2 +- test/unit/ServiceManagerMigration.t.sol | 309 ++++++++++++++++++++++++ 7 files changed, 684 insertions(+), 1 deletion(-) create mode 100644 src/libraries/LibMergeSort.sol create mode 100644 test/harnesses/AVSDirectoryHarness.sol create mode 100644 test/unit/LibMergeSort.t.sol create mode 100644 test/unit/ServiceManagerMigration.t.sol diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index 3560692b..ab1a47d8 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.12; import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; import {ServiceManagerBaseStorage} from "./ServiceManagerBaseStorage.sol"; @@ -11,6 +12,8 @@ import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; import {BitmapUtils} from "./libraries/BitmapUtils.sol"; +import {LibMergeSort} from "./libraries/LibMergeSort.sol"; +import {console} from "forge-std/Test.sol"; /** * @title Minimal implementation of a ServiceManager-type contract. @@ -135,6 +138,77 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _setRewardsInitiator(newRewardsInitiator); } + function migrateAndCreateOperatorSetIds(uint32[] memory operatorSetsToCreate) external onlyOwner{ + _migrateAndCreateOperatorSetIds(operatorSetsToCreate); + } + + function migrateToOperatorSets(uint32[][] memory operatorSetIds, address[] memory operators) external onlyOwner { + require(!migrationFinalized, "SerivceManager: Migration Already Finalized"); + _migrateToOperatorSets(operatorSetIds, operators); + } + + function finalizeMigration() external onlyOwner{ + require(!migrationFinalized, "SerivceManager: Migration Already Finalized"); + migrationFinalized = true; + } + + function _migrateAndCreateOperatorSetIds(uint32[] memory operatorSetIdsToCreate) internal { + _avsDirectory.becomeOperatorSetAVS(); + AVSDirectory(address(_avsDirectory)).createOperatorSets(operatorSetIdsToCreate); + } + + function _migrateToOperatorSets(uint32[][] memory operatorSetIds, address[] memory operators) internal { + AVSDirectory(address(_avsDirectory)).migrateOperatorsToOperatorSets(operators, operatorSetIds); + } + + function getOperatorsToMigrate() public view returns (uint32[] memory operatorSetIdsToCreate, uint32[][] memory operatorSetIds, address[] memory allOperators) { + uint256 quorumCount = _registryCoordinator.quorumCount(); + + allOperators = new address[](0); + operatorSetIdsToCreate = new uint32[](quorumCount); + + // Step 1: Iterate through quorum numbers and get a list of unique operators + for (uint8 quorumNumber = 0; quorumNumber < quorumCount; quorumNumber++) { + // Step 2: Get operator list for quorum at current block + bytes32[] memory operatorIds = _registryCoordinator.indexRegistry().getOperatorListAtBlockNumber(quorumNumber, uint32(block.number)); + + // Step 3: Convert to address list and maintain a sorted array of operators + address[] memory operators = new address[](operatorIds.length); + for (uint256 i = 0; i < operatorIds.length; i++) { + operators[i] = _registryCoordinator.blsApkRegistry().getOperatorFromPubkeyHash(operatorIds[i]); + // Insert into sorted array of all operators + allOperators = LibMergeSort.mergeSortArrays(allOperators, LibMergeSort.sort(operators)); + } + address[] memory filteredOperators = new address[](allOperators.length); + uint256 count = 0; + for (uint256 i = 0; i < allOperators.length; i++) { + if (allOperators[i] != address(0)) { + filteredOperators[count++] = allOperators[i]; + } + } + // Resize array to remove empty slots + assembly { mstore(filteredOperators, count) } + allOperators = filteredOperators; + + operatorSetIdsToCreate[quorumNumber] = uint32(quorumNumber); + } + + operatorSetIds = new uint32[][](allOperators.length); + // Loop through each unique operator to get the quorums they are registered for + for (uint256 i = 0; i < allOperators.length; i++) { + address operator = allOperators[i]; + bytes32 operatorId = _registryCoordinator.getOperatorId(operator); + uint192 quorumsBitmap = _registryCoordinator.getCurrentQuorumBitmap(operatorId); + bytes memory quorumBytesArray = BitmapUtils.bitmapToBytesArray(quorumsBitmap); + uint32[] memory quorums = new uint32[](quorumBytesArray.length); + for (uint256 j = 0; j < quorumBytesArray.length; j++) { + quorums[j] = uint32(uint8(quorumBytesArray[j])); + } + operatorSetIds[i] = quorums; + } + + } + function _setRewardsInitiator(address newRewardsInitiator) internal { emit RewardsInitiatorUpdated(rewardsInitiator, newRewardsInitiator); rewardsInitiator = newRewardsInitiator; diff --git a/src/ServiceManagerBaseStorage.sol b/src/ServiceManagerBaseStorage.sol index e0c1d86a..4d0c1fec 100644 --- a/src/ServiceManagerBaseStorage.sol +++ b/src/ServiceManagerBaseStorage.sol @@ -35,6 +35,8 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab /// @notice The address of the entity that can initiate rewards address public rewardsInitiator; + bool public migrationFinalized; + /// @notice Sets the (immutable) `_avsDirectory`, `_rewardsCoordinator`, `_registryCoordinator`, and `_stakeRegistry` addresses constructor( IAVSDirectory __avsDirectory, diff --git a/src/libraries/LibMergeSort.sol b/src/libraries/LibMergeSort.sol new file mode 100644 index 00000000..012feed4 --- /dev/null +++ b/src/libraries/LibMergeSort.sol @@ -0,0 +1,61 @@ + +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +library LibMergeSort { + function sort(address[] memory array) internal pure returns (address[] memory) { + if (array.length <= 1) { + return array; + } + + uint256 mid = array.length / 2; + address[] memory left = new address[](mid); + address[] memory right = new address[](array.length - mid); + + for (uint256 i = 0; i < mid; i++) { + left[i] = array[i]; + } + for (uint256 i = mid; i < array.length; i++) { + right[i - mid] = array[i]; + } + + return mergeSortArrays(sort(left), sort(right)); + } + function mergeSortArrays(address[] memory left, address[] memory right) internal pure returns (address[] memory) { + uint256 leftLength = left.length; + uint256 rightLength = right.length; + address[] memory merged = new address[](leftLength + rightLength); + + uint256 i = 0; // Index for left array + uint256 j = 0; // Index for right array + uint256 k = 0; // Index for merged array + + // Merge the two arrays into the merged array + while (i < leftLength && j < rightLength) { + if (left[i] < right[j]) { + merged[k++] = left[i++]; + } else if (left[i] > right[j]) { + merged[k++] = right[j++]; + } else { + merged[k++] = left[i++]; + j++; + } + } + + // Copy remaining elements of left, if any + while (i < leftLength) { + merged[k++] = left[i++]; + } + + // Copy remaining elements of right, if any + while (j < rightLength) { + merged[k++] = right[j++]; + } + + // Resize the merged array to remove unused space + assembly { mstore(merged, k) } + + return merged; + } + +} \ No newline at end of file diff --git a/test/harnesses/AVSDirectoryHarness.sol b/test/harnesses/AVSDirectoryHarness.sol new file mode 100644 index 00000000..4f20a668 --- /dev/null +++ b/test/harnesses/AVSDirectoryHarness.sol @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; + +// wrapper around the AVSDirectory contract that exposes internal functionality, for unit testing +contract AVSDirectoryHarness is AVSDirectory { + + constructor(IDelegationManager _delegation) AVSDirectory(_delegation) {} + + function setOperatorSaltIsSpent(address operator, bytes32 salt, bool isSpent) external { + operatorSaltIsSpent[operator][salt] = isSpent; + } + + function setAvsOperatorStatus(address avs, address operator, OperatorAVSRegistrationStatus status) external { + avsOperatorStatus[avs][operator] = status; + } + + function setIsOperatorSetAVS(address avs, bool isOperatorSet) external { + isOperatorSetAVS[avs] = isOperatorSet; + } + + function setIsOperatorSet(address avs, uint32 operatorSetId, bool isSet) external { + isOperatorSet[avs][operatorSetId] = isSet; + } + + function setIsMember(address avs, address operator, uint32 operatorSetId, bool membershipStatus) external { + isMember[avs][operator][operatorSetId] = membershipStatus; + } + + function _registerToOperatorSetsExternal(address avs, address operator, uint32[] calldata operatorSetIds) external { + _registerToOperatorSets(avs, operator, operatorSetIds); + } + + function _deregisterFromOperatorSetsExternal(address avs, address operator, uint32[] calldata operatorSetIds) external { + _deregisterFromOperatorSets(avs, operator, operatorSetIds); + } + + function _calculateDigestHashExternal(bytes32 structHash) external view returns (bytes32) { + return _calculateDigestHash(structHash); + } + + function _calculateDomainSeparatorExternal() external view returns (bytes32) { + return _calculateDomainSeparator(); + } +} + + diff --git a/test/unit/LibMergeSort.t.sol b/test/unit/LibMergeSort.t.sol new file mode 100644 index 00000000..f3014d3f --- /dev/null +++ b/test/unit/LibMergeSort.t.sol @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import "forge-std/Test.sol"; +import "../../src/libraries/LibMergeSort.sol"; + +contract LibMergeSortTest is Test { + using LibMergeSort for address[]; + + function testMergeSortArrays() public { + address[] memory left = new address[](3); + address[] memory right = new address[](3); + + left[0] = address(0x1); + left[1] = address(0x3); + left[2] = address(0x5); + + right[0] = address(0x2); + right[1] = address(0x4); + right[2] = address(0x6); + + address[] memory expected = new address[](6); + expected[0] = address(0x1); + expected[1] = address(0x2); + expected[2] = address(0x3); + expected[3] = address(0x4); + expected[4] = address(0x5); + expected[5] = address(0x6); + + address[] memory result = left.mergeSortArrays(right); + + for (uint256 i = 0; i < expected.length; i++) { + assertEq(result[i], expected[i], "Array elements are not sorted correctly"); + } + } + + function testMergeSortArraysWithDuplicates() public { + address[] memory left = new address[](3); + address[] memory right = new address[](3); + + left[0] = address(0x1); + left[1] = address(0x3); + left[2] = address(0x5); + + right[0] = address(0x1); + right[1] = address(0x3); + right[2] = address(0x5); + + address[] memory expected = new address[](3); + expected[0] = address(0x1); + expected[1] = address(0x3); + expected[2] = address(0x5); + + address[] memory result = left.mergeSortArrays(right); + assertEq(expected, result, "Not sorted"); + } + + function testMergeSortArraysWithEmptyLeft() public { + address[] memory left = new address[](0); + address[] memory right = new address[](3); + + right[0] = address(0x2); + right[1] = address(0x4); + right[2] = address(0x6); + + address[] memory expected = new address[](3); + expected[0] = address(0x2); + expected[1] = address(0x4); + expected[2] = address(0x6); + + address[] memory result = left.mergeSortArrays(right); + + for (uint256 i = 0; i < expected.length; i++) { + assertEq(result[i], expected[i], "Array elements are not sorted correctly"); + } + } + + function testMergeSortArraysWithEmptyRight() public { + address[] memory left = new address[](3); + address[] memory right = new address[](0); + + left[0] = address(0x1); + left[1] = address(0x3); + left[2] = address(0x5); + + address[] memory expected = new address[](3); + expected[0] = address(0x1); + expected[1] = address(0x3); + expected[2] = address(0x5); + + address[] memory result = left.mergeSortArrays(right); + + for (uint256 i = 0; i < expected.length; i++) { + assertEq(result[i], expected[i], "Array elements are not sorted correctly"); + } + } + +function testMergeSortArrays_Sort() public { + address[] memory left = new address[](3); + address[] memory right = new address[](3); + + left[0] = address(0x3); + left[1] = address(0x1); + left[2] = address(0x2); + + right[0] = address(0x6); + right[1] = address(0x4); + right[2] = address(0x5); + + left = left.sort(); + right = right.sort(); + + address[] memory expected = new address[](6); + expected[0] = address(0x1); + expected[1] = address(0x2); + expected[2] = address(0x3); + expected[3] = address(0x4); + expected[4] = address(0x5); + expected[5] = address(0x6); + + address[] memory result = left.mergeSortArrays(right); + + for (uint256 i = 0; i < expected.length; i++) { + assertEq(result[i], expected[i], "Array elements are not sorted correctly"); + } +} + +/// NOTE: we're assuming the input arrays themselves are unique. +/// Demonstrating behavior of library +function testMergeSortArraysWithDuplicateInLeft() public { + address[] memory left = new address[](4); + address[] memory right = new address[](3); + + left[0] = address(0x1); + left[1] = address(0x3); + left[2] = address(0x3); // Duplicate + left[3] = address(0x5); + + right[0] = address(0x2); + right[1] = address(0x4); + right[2] = address(0x6); + + address[] memory expected = new address[](7); + expected[0] = address(0x1); + expected[1] = address(0x2); + expected[2] = address(0x3); + expected[3] = address(0x3); + expected[4] = address(0x4); + expected[5] = address(0x5); + expected[6] = address(0x6); + + address[] memory result = left.mergeSortArrays(right); + + for (uint256 i = 0; i < expected.length; i++) { + assertEq(result[i], expected[i], "Array elements are not sorted correctly"); + } +} +function testMergeSortArraysWithDuplicateInRight() public { + address[] memory left = new address[](3); + address[] memory right = new address[](4); + + left[0] = address(0x1); + left[1] = address(0x3); + left[2] = address(0x5); + + right[0] = address(0x2); + right[1] = address(0x4); + right[2] = address(0x4); // Duplicate + right[3] = address(0x6); + + address[] memory expected = new address[](7); + expected[0] = address(0x1); + expected[1] = address(0x2); + expected[2] = address(0x3); + expected[3] = address(0x4); + expected[4] = address(0x4); + expected[5] = address(0x5); + expected[6] = address(0x6); + + address[] memory result = left.mergeSortArrays(right); + + for (uint256 i = 0; i < expected.length; i++) { + assertEq(result[i], expected[i], "Array elements are not sorted correctly"); + } +} + + +} diff --git a/test/unit/ServiceManagerBase.t.sol b/test/unit/ServiceManagerBase.t.sol index 7673facd..eba791c3 100644 --- a/test/unit/ServiceManagerBase.t.sol +++ b/test/unit/ServiceManagerBase.t.sol @@ -530,4 +530,4 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve cheats.prank(caller); serviceManager.setRewardsInitiator(newRewardsInitiator); } -} +} \ No newline at end of file diff --git a/test/unit/ServiceManagerMigration.t.sol b/test/unit/ServiceManagerMigration.t.sol new file mode 100644 index 00000000..91451458 --- /dev/null +++ b/test/unit/ServiceManagerMigration.t.sol @@ -0,0 +1,309 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; +import { + RewardsCoordinator, + IRewardsCoordinator, + IERC20 +} from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; +import {StrategyBase} from "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; +import {IServiceManagerBaseEvents} from "../events/IServiceManagerBaseEvents.sol"; +import {AVSDirectoryHarness} from "../harnesses/AVSDirectoryHarness.sol"; + +import "../utils/MockAVSDeployer.sol"; + +contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBaseEvents { + // RewardsCoordinator config + address rewardsUpdater = address(uint160(uint256(keccak256("rewardsUpdater")))); + uint32 CALCULATION_INTERVAL_SECONDS = 7 days; + uint32 MAX_REWARDS_DURATION = 70 days; + uint32 MAX_RETROACTIVE_LENGTH = 84 days; + uint32 MAX_FUTURE_LENGTH = 28 days; + uint32 GENESIS_REWARDS_TIMESTAMP = 1_712_188_800; + uint256 MAX_REWARDS_AMOUNT = 1e38 - 1; + uint32 OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP = 0; /// TODO: what values should these have + uint32 OPERATOR_SET_MAX_RETROACTIVE_LENGTH = 0; /// TODO: What values these should have + /// @notice Delay in timestamp before a posted root can be claimed against + uint32 activationDelay = 7 days; + /// @notice the commission for all operators across all avss + uint16 globalCommissionBips = 1000; + + // Testing Config and Mocks + address serviceManagerOwner; + address rewardsInitiator = address(uint160(uint256(keccak256("rewardsInitiator")))); + IERC20[] rewardTokens; + uint256 mockTokenInitialSupply = 10e50; + IStrategy strategyMock1; + IStrategy strategyMock2; + IStrategy strategyMock3; + StrategyBase strategyImplementation; + IRewardsCoordinator.StrategyAndMultiplier[] defaultStrategyAndMultipliers; + AVSDirectoryHarness avsDirectoryHarness; + + // mapping to setting fuzzed inputs + mapping(address => bool) public addressIsExcludedFromFuzzedInputs; + + modifier filterFuzzedAddressInputs(address fuzzedAddress) { + cheats.assume(!addressIsExcludedFromFuzzedInputs[fuzzedAddress]); + _; + } + + function setUp() public virtual { + numQuorums = maxQuorumsToRegisterFor; + _deployMockEigenLayerAndAVS(); + + avsDirectoryHarness = new AVSDirectoryHarness(delegationMock); + // Deploy rewards coordinator + rewardsCoordinatorImplementation = new RewardsCoordinator( + delegationMock, + strategyManagerMock, + avsDirectoryMock, + CALCULATION_INTERVAL_SECONDS, + MAX_REWARDS_DURATION, + MAX_RETROACTIVE_LENGTH, + MAX_FUTURE_LENGTH, + GENESIS_REWARDS_TIMESTAMP, + OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP, + OPERATOR_SET_MAX_RETROACTIVE_LENGTH + ); + + rewardsCoordinator = RewardsCoordinator( + address( + new TransparentUpgradeableProxy( + address(rewardsCoordinatorImplementation), + address(proxyAdmin), + abi.encodeWithSelector( + RewardsCoordinator.initialize.selector, + msg.sender, + pauserRegistry, + 0, /*initialPausedStatus*/ + rewardsUpdater, + activationDelay, + globalCommissionBips + ) + ) + ) + ); + // Deploy ServiceManager + serviceManagerImplementation = new ServiceManagerMock( + avsDirectory, + rewardsCoordinator, + registryCoordinator, + stakeRegistry + ); + + serviceManager = ServiceManagerMock( + address( + new TransparentUpgradeableProxy( + address(serviceManagerImplementation), + address(proxyAdmin), + abi.encodeWithSelector( + ServiceManagerMock.initialize.selector, msg.sender, msg.sender + ) + ) + ) + ); + + + serviceManagerOwner = serviceManager.owner(); + cheats.prank(serviceManagerOwner); + serviceManager.setRewardsInitiator(rewardsInitiator); + + _setUpDefaultStrategiesAndMultipliers(); + + cheats.warp(GENESIS_REWARDS_TIMESTAMP + 2 weeks); + + addressIsExcludedFromFuzzedInputs[address(pauserRegistry)] = true; + addressIsExcludedFromFuzzedInputs[address(proxyAdmin)] = true; + } + + function _setUpDefaultStrategiesAndMultipliers() internal virtual { + // Deploy Mock Strategies + IERC20 token1 = new ERC20PresetFixedSupply( + "dog wif hat", "MOCK1", mockTokenInitialSupply, address(this) + ); + IERC20 token2 = + new ERC20PresetFixedSupply("jeo boden", "MOCK2", mockTokenInitialSupply, address(this)); + IERC20 token3 = new ERC20PresetFixedSupply( + "pepe wif avs", "MOCK3", mockTokenInitialSupply, address(this) + ); + strategyImplementation = new StrategyBase(strategyManagerMock); + strategyMock1 = StrategyBase( + address( + new TransparentUpgradeableProxy( + address(strategyImplementation), + address(proxyAdmin), + abi.encodeWithSelector(StrategyBase.initialize.selector, token1, pauserRegistry) + ) + ) + ); + strategyMock2 = StrategyBase( + address( + new TransparentUpgradeableProxy( + address(strategyImplementation), + address(proxyAdmin), + abi.encodeWithSelector(StrategyBase.initialize.selector, token2, pauserRegistry) + ) + ) + ); + strategyMock3 = StrategyBase( + address( + new TransparentUpgradeableProxy( + address(strategyImplementation), + address(proxyAdmin), + abi.encodeWithSelector(StrategyBase.initialize.selector, token3, pauserRegistry) + ) + ) + ); + IStrategy[] memory strategies = new IStrategy[](3); + strategies[0] = strategyMock1; + strategies[1] = strategyMock2; + strategies[2] = strategyMock3; + strategies = _sortArrayAsc(strategies); + + strategyManagerMock.setStrategyWhitelist(strategies[0], true); + strategyManagerMock.setStrategyWhitelist(strategies[1], true); + strategyManagerMock.setStrategyWhitelist(strategies[2], true); + + defaultStrategyAndMultipliers.push( + IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[0])), 1e18) + ); + defaultStrategyAndMultipliers.push( + IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[1])), 2e18) + ); + defaultStrategyAndMultipliers.push( + IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[2])), 3e18) + ); + } + + /// @dev Sort to ensure that the array is in ascending order for strategies + function _sortArrayAsc(IStrategy[] memory arr) internal pure returns (IStrategy[] memory) { + uint256 l = arr.length; + for (uint256 i = 0; i < l; i++) { + for (uint256 j = i + 1; j < l; j++) { + if (address(arr[i]) > address(arr[j])) { + IStrategy temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + } + } + return arr; + } + + function test_viewFunction(uint256 randomValue) public { + _registerRandomOperators(randomValue); + (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); + + // Assert that all operators are in quorum 0 invariant of _registerRandomOperators + for (uint256 i = 0; i < operators.length; i++) { + bytes32 operatorId = registryCoordinator.getOperatorId(operators[i]); + uint192 operatorBitmap = registryCoordinator.getCurrentQuorumBitmap(operatorId); + assertTrue(operatorId != bytes32(0), "Operator was registered"); + assertTrue(operatorBitmap & 1 == 1, "Operator is not registered in quorum 0"); + } + + // Assert we are migrating all the quorums that existed + uint256 quorumCount = registryCoordinator.quorumCount(); + assertEq(quorumCount, operatorSetsToCreate.length, "Operator sets to create incorrect"); + } + + function test_migrateToOperatorSets() public { + (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); + cheats.startPrank(serviceManagerOwner); + serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); + serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); + cheats.stopPrank(); + + assertTrue(avsDirectory.isOperatorSetAVS(address(serviceManager)), "AVS is not an operator set AVS"); + } + + function test_migrateTwoTransactions() public { + (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); + // Split the operatorSetIdsToMigrate and operators into two separate sets + uint256 halfLength = operatorSetIdsToMigrate.length / 2; + + uint32[][] memory firstHalfOperatorSetIds = new uint32[][](halfLength); + uint32[][] memory secondHalfOperatorSetIds = new uint32[][](operatorSetIdsToMigrate.length - halfLength); + address[] memory firstHalfOperators = new address[](halfLength); + address[] memory secondHalfOperators = new address[](operators.length - halfLength); + + for (uint256 i = 0; i < halfLength; i++) { + firstHalfOperatorSetIds[i] = operatorSetIdsToMigrate[i]; + firstHalfOperators[i] = operators[i]; + } + + for (uint256 i = halfLength; i < operatorSetIdsToMigrate.length; i++) { + secondHalfOperatorSetIds[i - halfLength] = operatorSetIdsToMigrate[i]; + secondHalfOperators[i - halfLength] = operators[i]; + } + + // Migrate the first half + cheats.startPrank(serviceManagerOwner); + serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); + serviceManager.migrateToOperatorSets(firstHalfOperatorSetIds, firstHalfOperators); + serviceManager.migrateToOperatorSets(secondHalfOperatorSetIds, secondHalfOperators); + cheats.stopPrank(); + + assertTrue(avsDirectory.isOperatorSetAVS(address(serviceManager)), "AVS is not an operator set AVS"); + } + + function test_migrateToOperatorSets_revert_alreadyMigrated() public { + (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); + cheats.startPrank(serviceManagerOwner); + serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); + serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); + serviceManager.finalizeMigration(); + + vm.expectRevert(); /// TODO: Now that it's not 1 step, we should have a way to signal completion + serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); + + cheats.stopPrank(); + } + + function test_migrateToOperatorSets_revert_notOwner() public { + (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); + cheats.startPrank(serviceManagerOwner); + serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); + cheats.stopPrank(); + address caller = address(uint160(uint256(keccak256("caller")))); + cheats.expectRevert("Ownable: caller is not the owner"); + cheats.prank(caller); + serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); + } + + function test_migrateToOperatorSets_verify() public { + uint256 pseudoRandomNumber = uint256(keccak256("pseudoRandomNumber")); + _registerRandomOperators(pseudoRandomNumber); + + vm.prank(proxyAdmin.owner()); + proxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(avsDirectory))), + address(avsDirectoryHarness) + ); + + uint256 quorumCount = registryCoordinator.quorumCount(); + for (uint256 i = 0; i < quorumCount; i++) { + uint256 operatorCount = indexRegistry.totalOperatorsForQuorum(uint8(i)); + bytes32[] memory operatorIds = indexRegistry.getOperatorListAtBlockNumber(uint8(i), uint32(block.number)); + assertEq(operatorCount, operatorIds.length, "Operator Id length mismatch");// sanity check + for (uint256 j = 0; j < operatorCount; j++) { + address operatorAddress = registryCoordinator.blsApkRegistry().getOperatorFromPubkeyHash(operatorIds[j]); + AVSDirectoryHarness(address(avsDirectory)).setAvsOperatorStatus(address(serviceManager), operatorAddress, IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED); + } + } + + (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); + cheats.startPrank(serviceManagerOwner); + serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); + serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); + cheats.stopPrank(); + + /// quick check, this operator is in operator set 3 + assertTrue( + avsDirectory.isMember(address(serviceManager), 0x73e2Ce949f15Be901f76b54F5a4554A6C8DCf539, uint32(3)), + "Operator not migrated to operator set" + ); + } +} From fe93ac6c8bb7b1186c3d84d6db3eb96915fc67f1 Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Mon, 12 Aug 2024 09:57:22 -0400 Subject: [PATCH 07/52] feat: operator set migration-2-create quorum (#287) * chore: checkout migration branch * feat: implement migration function * chore: update to release branch * feat: operator set creation for each quorum number * feat: migration with merge sorted array of operators and their quorums * feat: operator set migration working * chore: revert change from testing * chore: revert change from testing * chore: remove extra logging and commented out asserts * chore: remove unused file * fix: remove console logs * feat: create quorum post operator set migration * test(wip): create quorum test adds new operator set * test: migration create quorum * refactor: to view functions * chore: nit and remove unneeded function * fix: remove duplication of looping for all the operators * chore: remove comment * feat: allow migrating in two transactions * feat: finalization of migration * chore: use string errors and fix migration issues * chore: rename * feat: use library for merge sort * test: fuzz view function * fix: updates from merge * chore: use interface --- src/RegistryCoordinator.sol | 9 + src/ServiceManagerBase.sol | 8 +- src/interfaces/IServiceManager.sol | 2 + test/mocks/ECDSAServiceManagerMock.sol | 9 +- test/unit/RegistryCoordinatorMigration.t.sol | 200 +++++++++++++++++++ 5 files changed, 224 insertions(+), 4 deletions(-) create mode 100644 test/unit/RegistryCoordinatorMigration.t.sol diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 6d2ff3f4..86266f5d 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.12; import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; +import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; import {ISocketUpdater} from "./interfaces/ISocketUpdater.sol"; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; @@ -732,6 +733,14 @@ contract RegistryCoordinator is stakeRegistry.initializeQuorum(quorumNumber, minimumStake, strategyParams); indexRegistry.initializeQuorum(quorumNumber); blsApkRegistry.initializeQuorum(quorumNumber); + // Check if the AVS has migrated to operator sets + AVSDirectory avsDirectory = AVSDirectory(serviceManager.avsDirectory()); + if (avsDirectory.isOperatorSetAVS(address(serviceManager))){ + // Create an operator set for the new quorum + uint32[] memory operatorSetIds = new uint32[](1); + operatorSetIds[0] = uint32(quorumNumber); + serviceManager.createOperatorSets(operatorSetIds); + } } /** diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index ab1a47d8..ac12619c 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -4,7 +4,6 @@ pragma solidity ^0.8.12; import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; -import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; import {ServiceManagerBaseStorage} from "./ServiceManagerBaseStorage.sol"; @@ -108,6 +107,9 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); } + function createOperatorSets(uint32[] memory operatorSetIds) external onlyRegistryCoordinator{ + _avsDirectory.createOperatorSets(operatorSetIds); + } /** * @notice Forwards a call to EigenLayer's AVSDirectory contract to confirm operator registration with the AVS @@ -154,11 +156,11 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { function _migrateAndCreateOperatorSetIds(uint32[] memory operatorSetIdsToCreate) internal { _avsDirectory.becomeOperatorSetAVS(); - AVSDirectory(address(_avsDirectory)).createOperatorSets(operatorSetIdsToCreate); + IAVSDirectory(address(_avsDirectory)).createOperatorSets(operatorSetIdsToCreate); } function _migrateToOperatorSets(uint32[][] memory operatorSetIds, address[] memory operators) internal { - AVSDirectory(address(_avsDirectory)).migrateOperatorsToOperatorSets(operators, operatorSetIds); + IAVSDirectory(address(_avsDirectory)).migrateOperatorsToOperatorSets(operators, operatorSetIds); } function getOperatorsToMigrate() public view returns (uint32[] memory operatorSetIdsToCreate, uint32[][] memory operatorSetIds, address[] memory allOperators) { diff --git a/src/interfaces/IServiceManager.sol b/src/interfaces/IServiceManager.sol index ad953ec0..26f2c71b 100644 --- a/src/interfaces/IServiceManager.sol +++ b/src/interfaces/IServiceManager.sol @@ -22,6 +22,8 @@ interface IServiceManager is IServiceManagerUI { */ function createAVSRewardsSubmission(IRewardsCoordinator.RewardsSubmission[] calldata rewardsSubmissions) external; + function createOperatorSets(uint32[] memory operatorSetIds) external ; + // EVENTS event RewardsInitiatorUpdated(address prevRewardsInitiator, address newRewardsInitiator); } diff --git a/test/mocks/ECDSAServiceManagerMock.sol b/test/mocks/ECDSAServiceManagerMock.sol index 528270ae..e38e0395 100644 --- a/test/mocks/ECDSAServiceManagerMock.sol +++ b/test/mocks/ECDSAServiceManagerMock.sol @@ -10,7 +10,12 @@ contract ECDSAServiceManagerMock is ECDSAServiceManagerBase { address _rewardsCoordinator, address _delegationManager ) - ECDSAServiceManagerBase(_avsDirectory, _stakeRegistry, _rewardsCoordinator, _delegationManager) + ECDSAServiceManagerBase( + _avsDirectory, + _stakeRegistry, + _rewardsCoordinator, + _delegationManager + ) {} function initialize( @@ -19,4 +24,6 @@ contract ECDSAServiceManagerMock is ECDSAServiceManagerBase { ) public virtual initializer { __ServiceManagerBase_init(initialOwner, rewardsInitiator); } + + function createOperatorSets(uint32[] memory) external {} } diff --git a/test/unit/RegistryCoordinatorMigration.t.sol b/test/unit/RegistryCoordinatorMigration.t.sol new file mode 100644 index 00000000..0eb80273 --- /dev/null +++ b/test/unit/RegistryCoordinatorMigration.t.sol @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; +import { + RewardsCoordinator, + IRewardsCoordinator, + IERC20 +} from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; +import {StrategyBase} from "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; +import {IServiceManagerBaseEvents} from "../events/IServiceManagerBaseEvents.sol"; +import {AVSDirectoryHarness} from "../harnesses/AVSDirectoryHarness.sol"; + +import "../utils/MockAVSDeployer.sol"; + +contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBaseEvents { + // RewardsCoordinator config + address rewardsUpdater = address(uint160(uint256(keccak256("rewardsUpdater")))); + uint32 CALCULATION_INTERVAL_SECONDS = 7 days; + uint32 MAX_REWARDS_DURATION = 70 days; + uint32 MAX_RETROACTIVE_LENGTH = 84 days; + uint32 MAX_FUTURE_LENGTH = 28 days; + uint32 GENESIS_REWARDS_TIMESTAMP = 1_712_188_800; + uint256 MAX_REWARDS_AMOUNT = 1e38 - 1; + /// @notice Delay in timestamp before a posted root can be claimed against + uint32 activationDelay = 7 days; + /// @notice the commission for all operators across all avss + uint16 globalCommissionBips = 1000; + + // Testing Config and Mocks + address serviceManagerOwner; + IERC20[] rewardTokens; + uint256 mockTokenInitialSupply = 10e50; + IStrategy strategyMock1; + IStrategy strategyMock2; + IStrategy strategyMock3; + StrategyBase strategyImplementation; + IRewardsCoordinator.StrategyAndMultiplier[] defaultStrategyAndMultipliers; + AVSDirectoryHarness avsDirectoryHarness; + + // mapping to setting fuzzed inputs + mapping(address => bool) public addressIsExcludedFromFuzzedInputs; + + modifier filterFuzzedAddressInputs(address fuzzedAddress) { + cheats.assume(!addressIsExcludedFromFuzzedInputs[fuzzedAddress]); + _; + } + + function setUp() public virtual { + numQuorums = maxQuorumsToRegisterFor; + _deployMockEigenLayerAndAVS(); + + serviceManagerImplementation = new ServiceManagerMock( + avsDirectory, + IRewardsCoordinator(address(rewardsCoordinatorMock)), + registryCoordinator, + stakeRegistry + ); + avsDirectoryHarness = new AVSDirectoryHarness(delegationMock); + + serviceManagerImplementation = new ServiceManagerMock( + avsDirectory, + rewardsCoordinatorMock, + registryCoordinator, + stakeRegistry + ); + /// Needed to upgrade to a service manager that points to an AVS Directory that can track state + vm.prank(proxyAdmin.owner()); + proxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(serviceManager))), + address(serviceManagerImplementation) + ); + + serviceManagerOwner = serviceManager.owner(); + + _setUpDefaultStrategiesAndMultipliers(); + + addressIsExcludedFromFuzzedInputs[address(pauserRegistry)] = true; + addressIsExcludedFromFuzzedInputs[address(proxyAdmin)] = true; + } + + function _setUpDefaultStrategiesAndMultipliers() internal virtual { + // Deploy Mock Strategies + IERC20 token1 = new ERC20PresetFixedSupply( + "dog wif hat", "MOCK1", mockTokenInitialSupply, address(this) + ); + IERC20 token2 = + new ERC20PresetFixedSupply("jeo boden", "MOCK2", mockTokenInitialSupply, address(this)); + IERC20 token3 = new ERC20PresetFixedSupply( + "pepe wif avs", "MOCK3", mockTokenInitialSupply, address(this) + ); + strategyImplementation = new StrategyBase(strategyManagerMock); + strategyMock1 = StrategyBase( + address( + new TransparentUpgradeableProxy( + address(strategyImplementation), + address(proxyAdmin), + abi.encodeWithSelector(StrategyBase.initialize.selector, token1, pauserRegistry) + ) + ) + ); + strategyMock2 = StrategyBase( + address( + new TransparentUpgradeableProxy( + address(strategyImplementation), + address(proxyAdmin), + abi.encodeWithSelector(StrategyBase.initialize.selector, token2, pauserRegistry) + ) + ) + ); + strategyMock3 = StrategyBase( + address( + new TransparentUpgradeableProxy( + address(strategyImplementation), + address(proxyAdmin), + abi.encodeWithSelector(StrategyBase.initialize.selector, token3, pauserRegistry) + ) + ) + ); + IStrategy[] memory strategies = new IStrategy[](3); + strategies[0] = strategyMock1; + strategies[1] = strategyMock2; + strategies[2] = strategyMock3; + strategies = _sortArrayAsc(strategies); + + strategyManagerMock.setStrategyWhitelist(strategies[0], true); + strategyManagerMock.setStrategyWhitelist(strategies[1], true); + strategyManagerMock.setStrategyWhitelist(strategies[2], true); + + defaultStrategyAndMultipliers.push( + IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[0])), 1e18) + ); + defaultStrategyAndMultipliers.push( + IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[1])), 2e18) + ); + defaultStrategyAndMultipliers.push( + IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[2])), 3e18) + ); + } + + /// @dev Sort to ensure that the array is in ascending order for strategies + function _sortArrayAsc(IStrategy[] memory arr) internal pure returns (IStrategy[] memory) { + uint256 l = arr.length; + for (uint256 i = 0; i < l; i++) { + for (uint256 j = i + 1; j < l; j++) { + if (address(arr[i]) > address(arr[j])) { + IStrategy temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } + } + } + return arr; + } + + function test_migrateToOperatorSets() public { + (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); + cheats.startPrank(serviceManagerOwner); + serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); + serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); + cheats.stopPrank(); + + assertTrue(avsDirectory.isOperatorSetAVS(address(serviceManager)), "AVS is not an operator set AVS"); + } + + + + function test_createQuorum() public { + (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); + cheats.startPrank(serviceManagerOwner); + serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); + serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); + cheats.stopPrank(); + + assertTrue(avsDirectory.isOperatorSetAVS(address(serviceManager)), "AVS is not an operator set AVS"); + + uint8 quorumNumber = registryCoordinator.quorumCount(); + uint96 minimumStake = 1000; + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: 10, + kickBIPsOfOperatorStake: 50, + kickBIPsOfTotalStake: 2 + }); + IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = + IStakeRegistry.StrategyParams({ + strategy: IStrategy(address(1000)), + multiplier: 1e16 + }); + + assertFalse(avsDirectory.isOperatorSet(address(serviceManager), quorumNumber), "Operator set already existed"); + assertTrue(avsDirectory.isOperatorSet(address(serviceManager), quorumNumber-1), "Operator set doesn't already existed"); + + vm.prank(registryCoordinator.owner()); + registryCoordinator.createQuorum(operatorSetParams, minimumStake, strategyParams); + + assertTrue(avsDirectory.isOperatorSet(address(serviceManager), quorumNumber), "Operator set was not created for the quorum"); + + } +} From e5b26885f8f388dd20132beb06af66bc88ce21a9 Mon Sep 17 00:00:00 2001 From: steven Date: Thu, 15 Aug 2024 08:45:52 -0400 Subject: [PATCH 08/52] chore: bump operator set release dependency in core --- lib/eigenlayer-contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eigenlayer-contracts b/lib/eigenlayer-contracts index ed44903c..f2a7515a 160000 --- a/lib/eigenlayer-contracts +++ b/lib/eigenlayer-contracts @@ -1 +1 @@ -Subproject commit ed44903ca218a52cf259d226b5a60bee8a8320a7 +Subproject commit f2a7515a43162adb5e1b778308349043f60db6a8 From ec2fdf31b2653556c3375c2e915d652aa256b421 Mon Sep 17 00:00:00 2001 From: steven Date: Thu, 15 Aug 2024 08:46:02 -0400 Subject: [PATCH 09/52] chore: updates from dependency bump --- test/harnesses/AVSDirectoryHarness.sol | 37 ++++++-- test/integration/IntegrationDeployer.t.sol | 44 +++++----- .../mocks/BeaconChainOracleMock.t.sol | 7 +- test/mocks/AVSDirectoryMock.sol | 27 ++++-- test/unit/ServiceManagerMigration.t.sol | 84 ++++++++++++++----- test/utils/MockAVSDeployer.sol | 7 +- 6 files changed, 140 insertions(+), 66 deletions(-) diff --git a/test/harnesses/AVSDirectoryHarness.sol b/test/harnesses/AVSDirectoryHarness.sol index 4f20a668..99efedec 100644 --- a/test/harnesses/AVSDirectoryHarness.sol +++ b/test/harnesses/AVSDirectoryHarness.sol @@ -1,19 +1,23 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.12; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {IDelegationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; // wrapper around the AVSDirectory contract that exposes internal functionality, for unit testing contract AVSDirectoryHarness is AVSDirectory { - constructor(IDelegationManager _delegation) AVSDirectory(_delegation) {} function setOperatorSaltIsSpent(address operator, bytes32 salt, bool isSpent) external { operatorSaltIsSpent[operator][salt] = isSpent; } - function setAvsOperatorStatus(address avs, address operator, OperatorAVSRegistrationStatus status) external { + function setAvsOperatorStatus( + address avs, + address operator, + OperatorAVSRegistrationStatus status + ) external { avsOperatorStatus[avs][operator] = status; } @@ -25,15 +29,32 @@ contract AVSDirectoryHarness is AVSDirectory { isOperatorSet[avs][operatorSetId] = isSet; } - function setIsMember(address avs, address operator, uint32 operatorSetId, bool membershipStatus) external { - isMember[avs][operator][operatorSetId] = membershipStatus; + function setIsMember( + address avs, + address operator, + uint32[] calldata operatorSetIds, + bool membershipStatus + ) external { + if (membershipStatus) { + _registerToOperatorSets(avs, operator, operatorSetIds); + } else { + _deregisterFromOperatorSets(avs, operator, operatorSetIds); + } } - function _registerToOperatorSetsExternal(address avs, address operator, uint32[] calldata operatorSetIds) external { + function _registerToOperatorSetsExternal( + address avs, + address operator, + uint32[] calldata operatorSetIds + ) external { _registerToOperatorSets(avs, operator, operatorSetIds); } - function _deregisterFromOperatorSetsExternal(address avs, address operator, uint32[] calldata operatorSetIds) external { + function _deregisterFromOperatorSetsExternal( + address avs, + address operator, + uint32[] calldata operatorSetIds + ) external { _deregisterFromOperatorSets(avs, operator, operatorSetIds); } @@ -45,5 +66,3 @@ contract AVSDirectoryHarness is AVSDirectory { return _calculateDomainSeparator(); } } - - diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index ec9075e9..51525a8c 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -20,7 +20,7 @@ import "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; import "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; import "eigenlayer-contracts/src/contracts/pods/EigenPodManager.sol"; import "eigenlayer-contracts/src/contracts/pods/EigenPod.sol"; -import "eigenlayer-contracts/src/contracts/pods/DelayedWithdrawalRouter.sol"; +// import "eigenlayer-contracts/src/contracts/pods/DelayedWithdrawalRouter.sol"; import "eigenlayer-contracts/src/contracts/permissions/PauserRegistry.sol"; import "eigenlayer-contracts/src/test/mocks/ETHDepositMock.sol"; // import "eigenlayer-contracts/src/test/integration/mocks/BeaconChainOracleMock.t.sol"; @@ -57,7 +57,7 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { Slasher slasher; IBeacon eigenPodBeacon; EigenPod pod; - DelayedWithdrawalRouter delayedWithdrawalRouter; + // DelayedWithdrawalRouter delayedWithdrawalRouter; ETHPOSDepositMock ethPOSDeposit; BeaconChainOracleMock beaconChainOracle; @@ -147,11 +147,11 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") ) ); - delayedWithdrawalRouter = DelayedWithdrawalRouter( - address( - new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") - ) - ); + // delayedWithdrawalRouter = DelayedWithdrawalRouter( + // address( + // new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") + // ) + // ); avsDirectory = AVSDirectory( address( new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") @@ -164,9 +164,9 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { // Deploy EigenPod Contracts pod = new EigenPod( ethPOSDeposit, - delayedWithdrawalRouter, + // delayedWithdrawalRouter, eigenPodManager, - MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR, + // MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR, 0 ); @@ -181,8 +181,8 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { EigenPodManager eigenPodManagerImplementation = new EigenPodManager( ethPOSDeposit, eigenPodBeacon, strategyManager, slasher, delegationManager ); - DelayedWithdrawalRouter delayedWithdrawalRouterImplementation = - new DelayedWithdrawalRouter(eigenPodManager); + // DelayedWithdrawalRouter delayedWithdrawalRouterImplementation = + // new DelayedWithdrawalRouter(eigenPodManager); AVSDirectory avsDirectoryImplemntation = new AVSDirectory(delegationManager); // RewardsCoordinator rewardsCoordinatorImplementation = new RewardsCoordinator( // delegationManager, @@ -247,17 +247,17 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { ) ); // Delayed Withdrawal Router - proxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(delayedWithdrawalRouter))), - address(delayedWithdrawalRouterImplementation), - abi.encodeWithSelector( - DelayedWithdrawalRouter.initialize.selector, - eigenLayerReputedMultisig, // initialOwner - pauserRegistry, - 0, // initialPausedStatus - minWithdrawalDelayBlocks - ) - ); + // proxyAdmin.upgradeAndCall( + // TransparentUpgradeableProxy(payable(address(delayedWithdrawalRouter))), + // address(delayedWithdrawalRouterImplementation), + // abi.encodeWithSelector( + // DelayedWithdrawalRouter.initialize.selector, + // eigenLayerReputedMultisig, // initialOwner + // pauserRegistry, + // 0, // initialPausedStatus + // minWithdrawalDelayBlocks + // ) + // ); // AVSDirectory proxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(avsDirectory))), diff --git a/test/integration/mocks/BeaconChainOracleMock.t.sol b/test/integration/mocks/BeaconChainOracleMock.t.sol index dabd6b6a..6dd1756a 100644 --- a/test/integration/mocks/BeaconChainOracleMock.t.sol +++ b/test/integration/mocks/BeaconChainOracleMock.t.sol @@ -1,16 +1,17 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.12; -import "eigenlayer-contracts/src/contracts/interfaces/IBeaconChainOracle.sol"; +// import "eigenlayer-contracts/src/contracts/interfaces/IBeaconChainOracle.sol"; // NOTE: There's a copy of this file in the core repo, but importing that was causing // the compiler to complain for an unfathomable reason. Apparently reimplementing it // here fixes the issue. -contract BeaconChainOracleMock is IBeaconChainOracle { +contract BeaconChainOracleMock { + // contract BeaconChainOracleMock is IBeaconChainOracle { mapping(uint64 => bytes32) blockRoots; - function timestampToBlockRoot(uint timestamp) public view returns (bytes32) { + function timestampToBlockRoot(uint256 timestamp) public view returns (bytes32) { return blockRoots[uint64(timestamp)]; } diff --git a/test/mocks/AVSDirectoryMock.sol b/test/mocks/AVSDirectoryMock.sol index fdb02613..46bfb5db 100644 --- a/test/mocks/AVSDirectoryMock.sol +++ b/test/mocks/AVSDirectoryMock.sol @@ -1,7 +1,10 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.12; -import {IAVSDirectory, ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import { + IAVSDirectory, + ISignatureUtils +} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; contract AVSDirectoryMock is IAVSDirectory { /** @@ -61,7 +64,10 @@ contract AVSDirectoryMock is IAVSDirectory { * * @dev msg.sender is used as the AVS. */ - function deregisterOperatorFromOperatorSets(address operator, uint32[] calldata operatorSetIds) external {} + function deregisterOperatorFromOperatorSets( + address operator, + uint32[] calldata operatorSetIds + ) external {} /** * @notice Called by an operator to deregister from an operator set @@ -109,7 +115,7 @@ contract AVSDirectoryMock is IAVSDirectory { * * @param salt A unique and single use value associated with the approver signature. */ - function cancelSalt(bytes32 salt) external{} + function cancelSalt(bytes32 salt) external {} /** * @notice Returns whether or not the salt has already been used by the operator. @@ -117,7 +123,11 @@ contract AVSDirectoryMock is IAVSDirectory { */ function operatorSaltIsSpent(address operator, bytes32 salt) external view returns (bool) {} - function isMember(address avs, address operator, uint32 operatorSetId) external view returns (bool){} + function isMember( + address avs, + address operator, + uint32 operatorSetId + ) external view returns (bool) {} /** * @notice Calculates the digest hash to be signed by an operator to register with an AVS @@ -175,5 +185,10 @@ contract AVSDirectoryMock is IAVSDirectory { function isOperatorSetAVS(address avs) external view returns (bool) {} - function isOperatorSet(address avs, uint32 operatorSetId) external view returns (bool){} -} + function isOperatorSet(address avs, uint32 operatorSetId) external view returns (bool) {} + + function isMember( + address operator, + OperatorSet memory operatorSet + ) external view returns (bool) {} +} diff --git a/test/unit/ServiceManagerMigration.t.sol b/test/unit/ServiceManagerMigration.t.sol index 91451458..69cd4c7c 100644 --- a/test/unit/ServiceManagerMigration.t.sol +++ b/test/unit/ServiceManagerMigration.t.sol @@ -22,8 +22,10 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa uint32 MAX_FUTURE_LENGTH = 28 days; uint32 GENESIS_REWARDS_TIMESTAMP = 1_712_188_800; uint256 MAX_REWARDS_AMOUNT = 1e38 - 1; - uint32 OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP = 0; /// TODO: what values should these have - uint32 OPERATOR_SET_MAX_RETROACTIVE_LENGTH = 0; /// TODO: What values these should have + uint32 OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP = 0; + /// TODO: what values should these have + uint32 OPERATOR_SET_MAX_RETROACTIVE_LENGTH = 0; + /// TODO: What values these should have /// @notice Delay in timestamp before a posted root can be claimed against uint32 activationDelay = 7 days; /// @notice the commission for all operators across all avss @@ -87,10 +89,7 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa ); // Deploy ServiceManager serviceManagerImplementation = new ServiceManagerMock( - avsDirectory, - rewardsCoordinator, - registryCoordinator, - stakeRegistry + avsDirectory, rewardsCoordinator, registryCoordinator, stakeRegistry ); serviceManager = ServiceManagerMock( @@ -105,7 +104,6 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa ) ); - serviceManagerOwner = serviceManager.owner(); cheats.prank(serviceManagerOwner); serviceManager.setRewardsInitiator(rewardsInitiator); @@ -194,7 +192,11 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa function test_viewFunction(uint256 randomValue) public { _registerRandomOperators(randomValue); - (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); + ( + uint32[] memory operatorSetsToCreate, + uint32[][] memory operatorSetIdsToMigrate, + address[] memory operators + ) = serviceManager.getOperatorsToMigrate(); // Assert that all operators are in quorum 0 invariant of _registerRandomOperators for (uint256 i = 0; i < operators.length; i++) { @@ -210,22 +212,33 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa } function test_migrateToOperatorSets() public { - (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); + ( + uint32[] memory operatorSetsToCreate, + uint32[][] memory operatorSetIdsToMigrate, + address[] memory operators + ) = serviceManager.getOperatorsToMigrate(); cheats.startPrank(serviceManagerOwner); serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); cheats.stopPrank(); - assertTrue(avsDirectory.isOperatorSetAVS(address(serviceManager)), "AVS is not an operator set AVS"); + assertTrue( + avsDirectory.isOperatorSetAVS(address(serviceManager)), "AVS is not an operator set AVS" + ); } function test_migrateTwoTransactions() public { - (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); + ( + uint32[] memory operatorSetsToCreate, + uint32[][] memory operatorSetIdsToMigrate, + address[] memory operators + ) = serviceManager.getOperatorsToMigrate(); // Split the operatorSetIdsToMigrate and operators into two separate sets uint256 halfLength = operatorSetIdsToMigrate.length / 2; uint32[][] memory firstHalfOperatorSetIds = new uint32[][](halfLength); - uint32[][] memory secondHalfOperatorSetIds = new uint32[][](operatorSetIdsToMigrate.length - halfLength); + uint32[][] memory secondHalfOperatorSetIds = + new uint32[][](operatorSetIdsToMigrate.length - halfLength); address[] memory firstHalfOperators = new address[](halfLength); address[] memory secondHalfOperators = new address[](operators.length - halfLength); @@ -246,24 +259,36 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa serviceManager.migrateToOperatorSets(secondHalfOperatorSetIds, secondHalfOperators); cheats.stopPrank(); - assertTrue(avsDirectory.isOperatorSetAVS(address(serviceManager)), "AVS is not an operator set AVS"); + assertTrue( + avsDirectory.isOperatorSetAVS(address(serviceManager)), "AVS is not an operator set AVS" + ); } function test_migrateToOperatorSets_revert_alreadyMigrated() public { - (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); + ( + uint32[] memory operatorSetsToCreate, + uint32[][] memory operatorSetIdsToMigrate, + address[] memory operators + ) = serviceManager.getOperatorsToMigrate(); cheats.startPrank(serviceManagerOwner); serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); serviceManager.finalizeMigration(); - vm.expectRevert(); /// TODO: Now that it's not 1 step, we should have a way to signal completion + vm.expectRevert(); + + /// TODO: Now that it's not 1 step, we should have a way to signal completion serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); cheats.stopPrank(); } function test_migrateToOperatorSets_revert_notOwner() public { - (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); + ( + uint32[] memory operatorSetsToCreate, + uint32[][] memory operatorSetIdsToMigrate, + address[] memory operators + ) = serviceManager.getOperatorsToMigrate(); cheats.startPrank(serviceManagerOwner); serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); cheats.stopPrank(); @@ -286,15 +311,25 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa uint256 quorumCount = registryCoordinator.quorumCount(); for (uint256 i = 0; i < quorumCount; i++) { uint256 operatorCount = indexRegistry.totalOperatorsForQuorum(uint8(i)); - bytes32[] memory operatorIds = indexRegistry.getOperatorListAtBlockNumber(uint8(i), uint32(block.number)); - assertEq(operatorCount, operatorIds.length, "Operator Id length mismatch");// sanity check + bytes32[] memory operatorIds = + indexRegistry.getOperatorListAtBlockNumber(uint8(i), uint32(block.number)); + assertEq(operatorCount, operatorIds.length, "Operator Id length mismatch"); // sanity check for (uint256 j = 0; j < operatorCount; j++) { - address operatorAddress = registryCoordinator.blsApkRegistry().getOperatorFromPubkeyHash(operatorIds[j]); - AVSDirectoryHarness(address(avsDirectory)).setAvsOperatorStatus(address(serviceManager), operatorAddress, IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED); + address operatorAddress = + registryCoordinator.blsApkRegistry().getOperatorFromPubkeyHash(operatorIds[j]); + AVSDirectoryHarness(address(avsDirectory)).setAvsOperatorStatus( + address(serviceManager), + operatorAddress, + IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED + ); } } - (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); + ( + uint32[] memory operatorSetsToCreate, + uint32[][] memory operatorSetIdsToMigrate, + address[] memory operators + ) = serviceManager.getOperatorsToMigrate(); cheats.startPrank(serviceManagerOwner); serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); @@ -302,8 +337,11 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa /// quick check, this operator is in operator set 3 assertTrue( - avsDirectory.isMember(address(serviceManager), 0x73e2Ce949f15Be901f76b54F5a4554A6C8DCf539, uint32(3)), + avsDirectory.isMember( + 0x73e2Ce949f15Be901f76b54F5a4554A6C8DCf539, + IAVSDirectory.OperatorSet(address(serviceManager), uint32(3)) + ), "Operator not migrated to operator set" - ); + ); } } diff --git a/test/utils/MockAVSDeployer.sol b/test/utils/MockAVSDeployer.sol index 23875760..b3eebf1a 100644 --- a/test/utils/MockAVSDeployer.sol +++ b/test/utils/MockAVSDeployer.sol @@ -34,8 +34,9 @@ import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSD import {RewardsCoordinatorMock} from "../mocks/RewardsCoordinatorMock.sol"; -import { RewardsCoordinator } from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; -import { IRewardsCoordinator } from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import {RewardsCoordinator} from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; +import {IRewardsCoordinator} from + "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; import {BLSApkRegistryHarness} from "../harnesses/BLSApkRegistryHarness.sol"; import {EmptyContract} from "eigenlayer-contracts/src/test/mocks/EmptyContract.sol"; @@ -147,7 +148,7 @@ contract MockAVSDeployer is Test { delegationMock = new DelegationMock(); avsDirectoryMock = new AVSDirectoryMock(); - eigenPodManagerMock = new EigenPodManagerMock(); + eigenPodManagerMock = new EigenPodManagerMock(pauserRegistry); strategyManagerMock = new StrategyManagerMock(); slasherImplementation = new Slasher(strategyManagerMock, delegationMock); slasher = Slasher( From 12eda5dd36ba793b03136516d2342554b173151a Mon Sep 17 00:00:00 2001 From: steven Date: Thu, 15 Aug 2024 09:02:11 -0400 Subject: [PATCH 10/52] feat: add natspec --- src/ServiceManagerBase.sol | 100 ++++++++++++++++++++++++++++--------- 1 file changed, 77 insertions(+), 23 deletions(-) diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index ac12619c..469addd1 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -4,7 +4,8 @@ pragma solidity ^0.8.12; import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; -import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import {IRewardsCoordinator} from + "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; import {ServiceManagerBaseStorage} from "./ServiceManagerBaseStorage.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; @@ -89,15 +90,15 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { * @dev This function will revert if the `rewardsSubmission` is malformed, * e.g. if the `strategies` and `weights` arrays are of non-equal lengths */ - function createAVSRewardsSubmission(IRewardsCoordinator.RewardsSubmission[] calldata rewardsSubmissions) - public - virtual - onlyRewardsInitiator - { + function createAVSRewardsSubmission( + IRewardsCoordinator.RewardsSubmission[] calldata rewardsSubmissions + ) public virtual onlyRewardsInitiator { for (uint256 i = 0; i < rewardsSubmissions.length; ++i) { // transfer token to ServiceManager and approve RewardsCoordinator to transfer again // in createAVSRewardsSubmission() call - rewardsSubmissions[i].token.transferFrom(msg.sender, address(this), rewardsSubmissions[i].amount); + rewardsSubmissions[i].token.transferFrom( + msg.sender, address(this), rewardsSubmissions[i].amount + ); uint256 allowance = rewardsSubmissions[i].token.allowance(address(this), address(_rewardsCoordinator)); rewardsSubmissions[i].token.approve( @@ -107,7 +108,8 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); } - function createOperatorSets(uint32[] memory operatorSetIds) external onlyRegistryCoordinator{ + + function createOperatorSets(uint32[] memory operatorSetIds) external onlyRegistryCoordinator { _avsDirectory.createOperatorSets(operatorSetIds); } @@ -140,30 +142,78 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _setRewardsInitiator(newRewardsInitiator); } - function migrateAndCreateOperatorSetIds(uint32[] memory operatorSetsToCreate) external onlyOwner{ + /** + * @notice Migrates the AVS to use operator sets and creates new operator set IDs. + * @param operatorSetsToCreate An array of operator set IDs to create. + * @dev This function can only be called by the contract owner. + */ + function migrateAndCreateOperatorSetIds(uint32[] memory operatorSetsToCreate) + external + onlyOwner + { _migrateAndCreateOperatorSetIds(operatorSetsToCreate); } - function migrateToOperatorSets(uint32[][] memory operatorSetIds, address[] memory operators) external onlyOwner { - require(!migrationFinalized, "SerivceManager: Migration Already Finalized"); + /** + * @notice Migrates operators to their respective operator sets. + * @param operatorSetIds A 2D array where each sub-array contains the operator set IDs for a specific operator. + * @param operators An array of operator addresses to migrate. + * @dev This function can only be called by the contract owner. + * @dev Reverts if the migration has already been finalized. + */ + function migrateToOperatorSets( + uint32[][] memory operatorSetIds, + address[] memory operators + ) external onlyOwner { + require(!migrationFinalized, "ServiceManager: Migration Already Finalized"); _migrateToOperatorSets(operatorSetIds, operators); } - function finalizeMigration() external onlyOwner{ - require(!migrationFinalized, "SerivceManager: Migration Already Finalized"); + /** + * @notice Finalizes the migration process, preventing further migrations. + * @dev This function can only be called by the contract owner. + * @dev Reverts if the migration has already been finalized. + */ + function finalizeMigration() external onlyOwner { + require(!migrationFinalized, "ServiceManager: Migration Already Finalized"); migrationFinalized = true; } - function _migrateAndCreateOperatorSetIds(uint32[] memory operatorSetIdsToCreate) internal { + /** + * @notice Migrates the AVS to use operator sets and create new operator set IDs. + * @param operatorSetIdsToCreate An array of operator set IDs to create. + */ + function _migrateAndCreateOperatorSetIds(uint32[] memory operatorSetIdsToCreate) { _avsDirectory.becomeOperatorSetAVS(); IAVSDirectory(address(_avsDirectory)).createOperatorSets(operatorSetIdsToCreate); } - function _migrateToOperatorSets(uint32[][] memory operatorSetIds, address[] memory operators) internal { - IAVSDirectory(address(_avsDirectory)).migrateOperatorsToOperatorSets(operators, operatorSetIds); + /** + * @notice Migrates operators to their respective operator sets. + * @param operatorSetIds A 2D array where each sub-array contains the operator set IDs for a specific operator. + * @param operators An array of operator addresses to migrate. + */ + function _migrateToOperatorSets(uint32[][] memory operatorSetIds, address[] memory operators) { + IAVSDirectory(address(_avsDirectory)).migrateOperatorsToOperatorSets( + operators, operatorSetIds + ); } - function getOperatorsToMigrate() public view returns (uint32[] memory operatorSetIdsToCreate, uint32[][] memory operatorSetIds, address[] memory allOperators) { + /** + * @notice Retrieves the operators to migrate along with their respective operator set IDs. + * @return operatorSetIdsToCreate An array of operator set IDs to create. + * @return operatorSetIds A 2D array where each sub-array contains the operator set IDs for a specific operator. + * @return allOperators An array of all unique operator addresses. + */ + function getOperatorsToMigrate() + public + view + returns ( + uint32[] memory operatorSetIdsToCreate, + uint32[][] memory operatorSetIds, + address[] memory allOperators + ) + { uint256 quorumCount = _registryCoordinator.quorumCount(); allOperators = new address[](0); @@ -172,14 +222,17 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { // Step 1: Iterate through quorum numbers and get a list of unique operators for (uint8 quorumNumber = 0; quorumNumber < quorumCount; quorumNumber++) { // Step 2: Get operator list for quorum at current block - bytes32[] memory operatorIds = _registryCoordinator.indexRegistry().getOperatorListAtBlockNumber(quorumNumber, uint32(block.number)); - + bytes32[] memory operatorIds = _registryCoordinator.indexRegistry() + .getOperatorListAtBlockNumber(quorumNumber, uint32(block.number)); + // Step 3: Convert to address list and maintain a sorted array of operators address[] memory operators = new address[](operatorIds.length); for (uint256 i = 0; i < operatorIds.length; i++) { - operators[i] = _registryCoordinator.blsApkRegistry().getOperatorFromPubkeyHash(operatorIds[i]); + operators[i] = + _registryCoordinator.blsApkRegistry().getOperatorFromPubkeyHash(operatorIds[i]); // Insert into sorted array of all operators - allOperators = LibMergeSort.mergeSortArrays(allOperators, LibMergeSort.sort(operators)); + allOperators = + LibMergeSort.mergeSortArrays(allOperators, LibMergeSort.sort(operators)); } address[] memory filteredOperators = new address[](allOperators.length); uint256 count = 0; @@ -189,7 +242,9 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { } } // Resize array to remove empty slots - assembly { mstore(filteredOperators, count) } + assembly { + mstore(filteredOperators, count) + } allOperators = filteredOperators; operatorSetIdsToCreate[quorumNumber] = uint32(quorumNumber); @@ -208,7 +263,6 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { } operatorSetIds[i] = quorums; } - } function _setRewardsInitiator(address newRewardsInitiator) internal { From 788cd0946ba37dcffee3369a612713e0c0b3f9c3 Mon Sep 17 00:00:00 2001 From: steven Date: Thu, 15 Aug 2024 09:03:08 -0400 Subject: [PATCH 11/52] docs: add natspec --- src/ServiceManagerBase.sol | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index 469addd1..213e8ee2 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -183,7 +183,7 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { * @notice Migrates the AVS to use operator sets and create new operator set IDs. * @param operatorSetIdsToCreate An array of operator set IDs to create. */ - function _migrateAndCreateOperatorSetIds(uint32[] memory operatorSetIdsToCreate) { + function _migrateAndCreateOperatorSetIds(uint32[] memory operatorSetIdsToCreate) internal { _avsDirectory.becomeOperatorSetAVS(); IAVSDirectory(address(_avsDirectory)).createOperatorSets(operatorSetIdsToCreate); } @@ -193,7 +193,10 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { * @param operatorSetIds A 2D array where each sub-array contains the operator set IDs for a specific operator. * @param operators An array of operator addresses to migrate. */ - function _migrateToOperatorSets(uint32[][] memory operatorSetIds, address[] memory operators) { + function _migrateToOperatorSets( + uint32[][] memory operatorSetIds, + address[] memory operators + ) internal { IAVSDirectory(address(_avsDirectory)).migrateOperatorsToOperatorSets( operators, operatorSetIds ); From d64f4af465201d66e2c581e42f28b32764a82381 Mon Sep 17 00:00:00 2001 From: steven Date: Thu, 15 Aug 2024 09:54:59 -0400 Subject: [PATCH 12/52] feat: add checks operator was registered for quorums when migrating --- src/ServiceManagerBase.sol | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index 213e8ee2..a3374a4d 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -197,11 +197,37 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { uint32[][] memory operatorSetIds, address[] memory operators ) internal { + require( + operators.length == operatorSetIds.length, "ServiceManager: Input array length mismatch" + ); + for (uint256 i; i < operators.length; i++) { + _isOperatorRegisteredForQuorums(operators[i], operatorSetIds[i]); + } IAVSDirectory(address(_avsDirectory)).migrateOperatorsToOperatorSets( operators, operatorSetIds ); } + /** + * @notice Checks if an operator is registered for a specific quorum + * @param operator The address of the operator to check + * @param quorumNumbers The quorum number to check the registration for + * @return bool Returns true if the operator is registered for the specified quorum, false otherwise + */ + function _isOperatorRegisteredForQuorums( + address operator, + uint32[] memory quorumNumbers + ) internal view returns (bool) { + bytes32 operatorId = _registryCoordinator.getOperatorId(operator); + uint192 operatorBitmap = _registryCoordinator.getCurrentQuorumBitmap(operatorId); + for (uint256 i; i < quorumNumbers.length; i++) { + require( + BitmapUtils.isSet(operatorBitmap, uint8(quorumNumbers[i])), + "ServiceManager: Operator not in quorum" + ); + } + } + /** * @notice Retrieves the operators to migrate along with their respective operator set IDs. * @return operatorSetIdsToCreate An array of operator set IDs to create. From a92d51acc2f09197a363761b4ede024219269cb3 Mon Sep 17 00:00:00 2001 From: steven Date: Thu, 15 Aug 2024 10:23:51 -0400 Subject: [PATCH 13/52] fix: resolve code size issue in RegistryCoordinator --- src/RegistryCoordinator.sol | 381 ++++++++++++++++---------- src/libraries/SignatureCheckerLib.sol | 27 ++ 2 files changed, 256 insertions(+), 152 deletions(-) create mode 100644 src/libraries/SignatureCheckerLib.sol diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 86266f5d..738213f3 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -11,9 +11,9 @@ import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; -import {EIP1271SignatureUtils} from "eigenlayer-contracts/src/contracts/libraries/EIP1271SignatureUtils.sol"; import {BitmapUtils} from "./libraries/BitmapUtils.sol"; import {BN254} from "./libraries/BN254.sol"; +import {SignatureCheckerLib} from "./libraries/SignatureCheckerLib.sol"; import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; @@ -27,22 +27,22 @@ import {RegistryCoordinatorStorage} from "./RegistryCoordinatorStorage.sol"; * 1) a `StakeRegistry` that keeps track of operators' stakes * 2) a `BLSApkRegistry` that keeps track of operators' BLS public keys and aggregate BLS public keys for each quorum * 3) an `IndexRegistry` that keeps track of an ordered list of operators for each quorum - * + * * @author Layr Labs, Inc. */ -contract RegistryCoordinator is - EIP712, - Initializable, +contract RegistryCoordinator is + EIP712, + Initializable, Pausable, OwnableUpgradeable, - RegistryCoordinatorStorage, - ISocketUpdater, + RegistryCoordinatorStorage, + ISocketUpdater, ISignatureUtils { using BitmapUtils for *; using BN254 for BN254.G1Point; - modifier onlyEjector { + modifier onlyEjector() { _checkEjector(); _; } @@ -59,9 +59,9 @@ contract RegistryCoordinator is IStakeRegistry _stakeRegistry, IBLSApkRegistry _blsApkRegistry, IIndexRegistry _indexRegistry - ) + ) RegistryCoordinatorStorage(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry) - EIP712("AVSRegistryCoordinator", "v0.0.1") + EIP712("AVSRegistryCoordinator", "v0.0.1") { _disableInitializers(); } @@ -88,10 +88,11 @@ contract RegistryCoordinator is IStakeRegistry.StrategyParams[][] memory _strategyParams ) external initializer { require( - _operatorSetParams.length == _minimumStakes.length && _minimumStakes.length == _strategyParams.length, + _operatorSetParams.length == _minimumStakes.length + && _minimumStakes.length == _strategyParams.length, "RegistryCoordinator.initialize: input length mismatch" ); - + // Initialize roles _transferOwnership(_initialOwner); _initializePauser(_pauserRegistry, _initialPausedStatus); @@ -109,9 +110,11 @@ contract RegistryCoordinator is } } - /******************************************************************************* - EXTERNAL FUNCTIONS - *******************************************************************************/ + /** + * + * EXTERNAL FUNCTIONS + * + */ /** * @notice Registers msg.sender as an operator for one or more quorums. If any quorum exceeds its maximum @@ -141,9 +144,9 @@ contract RegistryCoordinator is // Register the operator in each of the registry contracts and update the operator's // quorum bitmap and registration status uint32[] memory numOperatorsPerQuorum = _registerOperator({ - operator: msg.sender, + operator: msg.sender, operatorId: operatorId, - quorumNumbers: quorumNumbers, + quorumNumbers: quorumNumbers, socket: socket, operatorSignature: operatorSignature }).numOperatorsPerQuorum; @@ -173,15 +176,18 @@ contract RegistryCoordinator is * @dev `operatorSignature` is ignored if the operator's status is already REGISTERED */ function registerOperatorWithChurn( - bytes calldata quorumNumbers, + bytes calldata quorumNumbers, string calldata socket, IBLSApkRegistry.PubkeyRegistrationParams calldata params, OperatorKickParam[] calldata operatorKickParams, SignatureWithSaltAndExpiry memory churnApproverSignature, SignatureWithSaltAndExpiry memory operatorSignature ) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { - require(operatorKickParams.length == quorumNumbers.length, "RegistryCoordinator.registerOperatorWithChurn: input length mismatch"); - + require( + operatorKickParams.length == quorumNumbers.length, + "RegistryCoordinator.registerOperatorWithChurn: input length mismatch" + ); + /** * If the operator has NEVER registered a pubkey before, use `params` to register * their pubkey in blsApkRegistry @@ -213,7 +219,7 @@ contract RegistryCoordinator is // is exceeded, use `operatorKickParams` to deregister an existing operator to make space for (uint256 i = 0; i < quorumNumbers.length; i++) { OperatorSetParam memory operatorSetParams = _quorumParams[uint8(quorumNumbers[i])]; - + /** * If the new operator count for any quorum exceeds the maximum, validate * that churn can be performed, then deregister the specified operator @@ -228,7 +234,7 @@ contract RegistryCoordinator is setParams: operatorSetParams }); - _deregisterOperator(operatorKickParams[i].operator, quorumNumbers[i:i+1]); + _deregisterOperator(operatorKickParams[i].operator, quorumNumbers[i:i + 1]); } } } @@ -237,13 +243,11 @@ contract RegistryCoordinator is * @notice Deregisters the caller from one or more quorums * @param quorumNumbers is an ordered byte array containing the quorum numbers being deregistered from */ - function deregisterOperator( - bytes calldata quorumNumbers - ) external onlyWhenNotPaused(PAUSED_DEREGISTER_OPERATOR) { - _deregisterOperator({ - operator: msg.sender, - quorumNumbers: quorumNumbers - }); + function deregisterOperator(bytes calldata quorumNumbers) + external + onlyWhenNotPaused(PAUSED_DEREGISTER_OPERATOR) + { + _deregisterOperator({operator: msg.sender, quorumNumbers: quorumNumbers}); } /** @@ -252,7 +256,10 @@ contract RegistryCoordinator is * @dev stakes are queried from the Eigenlayer core DelegationManager contract * @param operators a list of operator addresses to update */ - function updateOperators(address[] calldata operators) external onlyWhenNotPaused(PAUSED_UPDATE_OPERATOR) { + function updateOperators(address[] calldata operators) + external + onlyWhenNotPaused(PAUSED_UPDATE_OPERATOR) + { for (uint256 i = 0; i < operators.length; i++) { address operator = operators[i]; OperatorInfo memory operatorInfo = _operatorInfo[operator]; @@ -276,18 +283,19 @@ contract RegistryCoordinator is * @param quorumNumbers is an ordered byte array containing the quorum numbers being updated * @dev invariant: Each list of `operatorsPerQuorum` MUST be a sorted version of `IndexRegistry.getOperatorListAtBlockNumber` * for the corresponding quorum. - * @dev note on race condition: if an operator registers/deregisters for any quorum in `quorumNumbers` after a txn to + * @dev note on race condition: if an operator registers/deregisters for any quorum in `quorumNumbers` after a txn to * this method is broadcast (but before it is executed), the method will fail */ function updateOperatorsForQuorum( address[][] calldata operatorsPerQuorum, bytes calldata quorumNumbers ) external onlyWhenNotPaused(PAUSED_UPDATE_OPERATOR) { - // Input validation + // Input validation // - all quorums should exist (checked against `quorumCount` in orderedBytesArrayToBitmap) // - there should be no duplicates in `quorumNumbers` // - there should be one list of operators per quorum - uint192 quorumBitmap = uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); + uint192 quorumBitmap = + uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); require( operatorsPerQuorum.length == quorumNumbers.length, "RegistryCoordinator.updateOperatorsForQuorum: input length mismatch" @@ -311,10 +319,10 @@ contract RegistryCoordinator is // ... then, update their stakes for (uint256 j = 0; j < currQuorumOperators.length; ++j) { address operator = currQuorumOperators[j]; - + OperatorInfo memory operatorInfo = _operatorInfo[operator]; bytes32 operatorId = operatorInfo.operatorId; - + { uint192 currentBitmap = _currentOperatorBitmap(operatorId); // Check that the operator is registered @@ -328,9 +336,9 @@ contract RegistryCoordinator is "RegistryCoordinator.updateOperatorsForQuorum: operators array must be sorted in ascending address order" ); } - + // Update the operator - _updateOperator(operator, operatorInfo, quorumNumbers[i:i+1]); + _updateOperator(operator, operatorInfo, quorumNumbers[i:i + 1]); prevOperatorAddress = operator; } @@ -345,13 +353,18 @@ contract RegistryCoordinator is * @param socket is the new socket of the operator */ function updateSocket(string memory socket) external { - require(_operatorInfo[msg.sender].status == OperatorStatus.REGISTERED, "RegistryCoordinator.updateSocket: operator is not registered"); + require( + _operatorInfo[msg.sender].status == OperatorStatus.REGISTERED, + "RegistryCoordinator.updateSocket: operator is not registered" + ); emit OperatorSocketUpdate(_operatorInfo[msg.sender].operatorId, socket); } - /******************************************************************************* - EXTERNAL FUNCTIONS - EJECTOR - *******************************************************************************/ + /** + * + * EXTERNAL FUNCTIONS - EJECTOR + * + */ /** * @notice Forcibly deregisters an operator from one or more quorums @@ -359,31 +372,27 @@ contract RegistryCoordinator is * @param quorumNumbers the quorum numbers to eject the operator from * @dev possible race condition if prior to being ejected for a set of quorums the operator self deregisters from a subset */ - function ejectOperator( - address operator, - bytes calldata quorumNumbers - ) external onlyEjector { + function ejectOperator(address operator, bytes calldata quorumNumbers) external onlyEjector { lastEjectionTimestamp[operator] = block.timestamp; OperatorInfo storage operatorInfo = _operatorInfo[operator]; bytes32 operatorId = operatorInfo.operatorId; - uint192 quorumsToRemove = uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); + uint192 quorumsToRemove = + uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); uint192 currentBitmap = _currentOperatorBitmap(operatorId); - if( - operatorInfo.status == OperatorStatus.REGISTERED && - !quorumsToRemove.isEmpty() && - quorumsToRemove.isSubsetOf(currentBitmap) - ){ - _deregisterOperator({ - operator: operator, - quorumNumbers: quorumNumbers - }); + if ( + operatorInfo.status == OperatorStatus.REGISTERED && !quorumsToRemove.isEmpty() + && quorumsToRemove.isSubsetOf(currentBitmap) + ) { + _deregisterOperator({operator: operator, quorumNumbers: quorumNumbers}); } } - /******************************************************************************* - EXTERNAL FUNCTIONS - OWNER - *******************************************************************************/ + /** + * + * EXTERNAL FUNCTIONS - OWNER + * + */ /** * @notice Creates a quorum and initializes it in each registry contract @@ -409,7 +418,7 @@ contract RegistryCoordinator is * @dev only callable by the owner */ function setOperatorSetParams( - uint8 quorumNumber, + uint8 quorumNumber, OperatorSetParam memory operatorSetParams ) external onlyOwner quorumExists(quorumNumber) { _setOperatorSetParams(quorumNumber, operatorSetParams); @@ -435,7 +444,7 @@ contract RegistryCoordinator is } /** - * @notice Sets the ejection cooldown, which is the time an operator must wait in + * @notice Sets the ejection cooldown, which is the time an operator must wait in * seconds afer ejection before registering for any quorum * @param _ejectionCooldown the new ejection cooldown in seconds * @dev only callable by the owner @@ -444,22 +453,23 @@ contract RegistryCoordinator is ejectionCooldown = _ejectionCooldown; } - /******************************************************************************* - INTERNAL FUNCTIONS - *******************************************************************************/ - + /** + * + * INTERNAL FUNCTIONS + * + */ struct RegisterResults { uint32[] numOperatorsPerQuorum; uint96[] operatorStakes; uint96[] totalStakes; } - /** + /** * @notice Register the operator for one or more quorums. This method updates the * operator's quorum bitmap, socket, and status, then registers them with each registry. */ function _registerOperator( - address operator, + address operator, bytes32 operatorId, bytes calldata quorumNumbers, string memory socket, @@ -472,33 +482,37 @@ contract RegistryCoordinator is * - the operator is not currently registered for any quorums we're registering for * Then, calculate the operator's new bitmap after registration */ - uint192 quorumsToAdd = uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); + uint192 quorumsToAdd = + uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); uint192 currentBitmap = _currentOperatorBitmap(operatorId); - require(!quorumsToAdd.isEmpty(), "RegistryCoordinator._registerOperator: bitmap cannot be 0"); - require(quorumsToAdd.noBitsInCommon(currentBitmap), "RegistryCoordinator._registerOperator: operator already registered for some quorums being registered for"); + require( + !quorumsToAdd.isEmpty(), "RegistryCoordinator._registerOperator: bitmap cannot be 0" + ); + require( + quorumsToAdd.noBitsInCommon(currentBitmap), + "RegistryCoordinator._registerOperator: operator already registered for some quorums being registered for" + ); uint192 newBitmap = uint192(currentBitmap.plus(quorumsToAdd)); // Check that the operator can reregister if ejected - require(lastEjectionTimestamp[operator] + ejectionCooldown < block.timestamp, "RegistryCoordinator._registerOperator: operator cannot reregister yet"); + require( + lastEjectionTimestamp[operator] + ejectionCooldown < block.timestamp, + "RegistryCoordinator._registerOperator: operator cannot reregister yet" + ); /** * Update operator's bitmap, socket, and status. Only update operatorInfo if needed: * if we're `REGISTERED`, the operatorId and status are already correct. */ - _updateOperatorBitmap({ - operatorId: operatorId, - newBitmap: newBitmap - }); + _updateOperatorBitmap({operatorId: operatorId, newBitmap: newBitmap}); emit OperatorSocketUpdate(operatorId, socket); // If the operator wasn't registered for any quorums, update their status // and register them with this AVS in EigenLayer core (DelegationManager) if (_operatorInfo[operator].status != OperatorStatus.REGISTERED) { - _operatorInfo[operator] = OperatorInfo({ - operatorId: operatorId, - status: OperatorStatus.REGISTERED - }); + _operatorInfo[operator] = + OperatorInfo({operatorId: operatorId, status: OperatorStatus.REGISTERED}); // Register the operator with the EigenLayer core contracts via this AVS's ServiceManager serviceManager.registerOperatorToAVS(operator, operatorSignature); @@ -508,7 +522,7 @@ contract RegistryCoordinator is // Register the operator with the BLSApkRegistry, StakeRegistry, and IndexRegistry blsApkRegistry.registerOperator(operator, quorumNumbers); - (results.operatorStakes, results.totalStakes) = + (results.operatorStakes, results.totalStakes) = stakeRegistry.registerOperator(operator, operatorId, quorumNumbers); results.numOperatorsPerQuorum = indexRegistry.registerOperator(operatorId, quorumNumbers); @@ -530,8 +544,7 @@ contract RegistryCoordinator is */ function _checkQuorumExists(uint8 quorumNumber) internal view { require( - quorumNumber < quorumCount, - "RegistryCoordinator.quorumExists: quorum does not exist" + quorumNumber < quorumCount, "RegistryCoordinator.quorumExists: quorum does not exist" ); } @@ -549,7 +562,9 @@ contract RegistryCoordinator is ) internal returns (bytes32 operatorId) { operatorId = blsApkRegistry.getOperatorId(operator); if (operatorId == 0) { - operatorId = blsApkRegistry.registerBLSPublicKey(operator, params, pubkeyRegistrationMessageHash(operator)); + operatorId = blsApkRegistry.registerBLSPublicKey( + operator, params, pubkeyRegistrationMessageHash(operator) + ); } return operatorId; } @@ -573,17 +588,22 @@ contract RegistryCoordinator is * mentioned above */ function _validateChurn( - uint8 quorumNumber, + uint8 quorumNumber, uint96 totalQuorumStake, - address newOperator, + address newOperator, uint96 newOperatorStake, - OperatorKickParam memory kickParams, + OperatorKickParam memory kickParams, OperatorSetParam memory setParams ) internal view { address operatorToKick = kickParams.operator; bytes32 idToKick = _operatorInfo[operatorToKick].operatorId; - require(newOperator != operatorToKick, "RegistryCoordinator._validateChurn: cannot churn self"); - require(kickParams.quorumNumber == quorumNumber, "RegistryCoordinator._validateChurn: quorumNumber not the same as signed"); + require( + newOperator != operatorToKick, "RegistryCoordinator._validateChurn: cannot churn self" + ); + require( + kickParams.quorumNumber == quorumNumber, + "RegistryCoordinator._validateChurn: quorumNumber not the same as signed" + ); // Get the target operator's stake and check that it is below the kick thresholds uint96 operatorToKickStake = stakeRegistry.getCurrentStake(idToKick, quorumNumber); @@ -602,15 +622,15 @@ contract RegistryCoordinator is * This method updates the operator's quorum bitmap and status, then deregisters * the operator with the BLSApkRegistry, IndexRegistry, and StakeRegistry */ - function _deregisterOperator( - address operator, - bytes memory quorumNumbers - ) internal virtual { + function _deregisterOperator(address operator, bytes memory quorumNumbers) internal virtual { // Fetch the operator's info and ensure they are registered OperatorInfo storage operatorInfo = _operatorInfo[operator]; bytes32 operatorId = operatorInfo.operatorId; - require(operatorInfo.status == OperatorStatus.REGISTERED, "RegistryCoordinator._deregisterOperator: operator is not registered"); - + require( + operatorInfo.status == OperatorStatus.REGISTERED, + "RegistryCoordinator._deregisterOperator: operator is not registered" + ); + /** * Get bitmap of quorums to deregister from and operator's current bitmap. Validate that: * - we're trying to deregister from at least 1 quorum @@ -618,19 +638,23 @@ contract RegistryCoordinator is * - the operator is currently registered for any quorums we're trying to deregister from * Then, calculate the operator's new bitmap after deregistration */ - uint192 quorumsToRemove = uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); + uint192 quorumsToRemove = + uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); uint192 currentBitmap = _currentOperatorBitmap(operatorId); - require(!quorumsToRemove.isEmpty(), "RegistryCoordinator._deregisterOperator: bitmap cannot be 0"); - require(quorumsToRemove.isSubsetOf(currentBitmap), "RegistryCoordinator._deregisterOperator: operator is not registered for specified quorums"); + require( + !quorumsToRemove.isEmpty(), + "RegistryCoordinator._deregisterOperator: bitmap cannot be 0" + ); + require( + quorumsToRemove.isSubsetOf(currentBitmap), + "RegistryCoordinator._deregisterOperator: operator is not registered for specified quorums" + ); uint192 newBitmap = uint192(currentBitmap.minus(quorumsToRemove)); // Update operator's bitmap and status - _updateOperatorBitmap({ - operatorId: operatorId, - newBitmap: newBitmap - }); + _updateOperatorBitmap({operatorId: operatorId, newBitmap: newBitmap}); - // If the operator is no longer registered for any quorums, update their status and deregister + // If the operator is no longer registered for any quorums, update their status and deregister // them from the AVS via the EigenLayer core contracts if (newBitmap.isEmpty()) { operatorInfo.status = OperatorStatus.DEREGISTERED; @@ -659,13 +683,14 @@ contract RegistryCoordinator is return; } bytes32 operatorId = operatorInfo.operatorId; - uint192 quorumsToRemove = stakeRegistry.updateOperatorStake(operator, operatorId, quorumsToUpdate); + uint192 quorumsToRemove = + stakeRegistry.updateOperatorStake(operator, operatorId, quorumsToUpdate); if (!quorumsToRemove.isEmpty()) { _deregisterOperator({ operator: operator, quorumNumbers: BitmapUtils.bitmapToBytesArray(quorumsToRemove) - }); + }); } } @@ -673,7 +698,10 @@ contract RegistryCoordinator is * @notice Returns the stake threshold required for an incoming operator to replace an existing operator * The incoming operator must have more stake than the return value. */ - function _individualKickThreshold(uint96 operatorStake, OperatorSetParam memory setParams) internal pure returns (uint96) { + function _individualKickThreshold( + uint96 operatorStake, + OperatorSetParam memory setParams + ) internal pure returns (uint96) { return operatorStake * setParams.kickBIPsOfOperatorStake / BIPS_DENOMINATOR; } @@ -681,28 +709,43 @@ contract RegistryCoordinator is * @notice Returns the total stake threshold required for an operator to remain in a quorum. * The operator must have at least the returned stake amount to keep their position. */ - function _totalKickThreshold(uint96 totalStake, OperatorSetParam memory setParams) internal pure returns (uint96) { + function _totalKickThreshold( + uint96 totalStake, + OperatorSetParam memory setParams + ) internal pure returns (uint96) { return totalStake * setParams.kickBIPsOfTotalStake / BIPS_DENOMINATOR; } /// @notice verifies churnApprover's signature on operator churn approval and increments the churnApprover nonce function _verifyChurnApproverSignature( address registeringOperator, - bytes32 registeringOperatorId, - OperatorKickParam[] memory operatorKickParams, + bytes32 registeringOperatorId, + OperatorKickParam[] memory operatorKickParams, SignatureWithSaltAndExpiry memory churnApproverSignature ) internal { // make sure the salt hasn't been used already - require(!isChurnApproverSaltUsed[churnApproverSignature.salt], "RegistryCoordinator._verifyChurnApproverSignature: churnApprover salt already used"); - require(churnApproverSignature.expiry >= block.timestamp, "RegistryCoordinator._verifyChurnApproverSignature: churnApprover signature expired"); + require( + !isChurnApproverSaltUsed[churnApproverSignature.salt], + "RegistryCoordinator._verifyChurnApproverSignature: churnApprover salt already used" + ); + require( + churnApproverSignature.expiry >= block.timestamp, + "RegistryCoordinator._verifyChurnApproverSignature: churnApprover signature expired" + ); // set salt used to true - isChurnApproverSaltUsed[churnApproverSignature.salt] = true; - - // check the churnApprover's signature - EIP1271SignatureUtils.checkSignature_EIP1271( - churnApprover, - calculateOperatorChurnApprovalDigestHash(registeringOperator, registeringOperatorId, operatorKickParams, churnApproverSignature.salt, churnApproverSignature.expiry), + isChurnApproverSaltUsed[churnApproverSignature.salt] = true; + + // check the churnApprover's signature + SignatureCheckerLib.isValidSignature( + churnApprover, + calculateOperatorChurnApprovalDigestHash( + registeringOperator, + registeringOperatorId, + operatorKickParams, + churnApproverSignature.salt, + churnApproverSignature.expiry + ), churnApproverSignature.signature ); } @@ -722,9 +765,12 @@ contract RegistryCoordinator is ) internal { // Increment the total quorum count. Fails if we're already at the max uint8 prevQuorumCount = quorumCount; - require(prevQuorumCount < MAX_QUORUM_COUNT, "RegistryCoordinator.createQuorum: max quorums reached"); + require( + prevQuorumCount < MAX_QUORUM_COUNT, + "RegistryCoordinator.createQuorum: max quorums reached" + ); quorumCount = prevQuorumCount + 1; - + // The previous count is the new quorum's number uint8 quorumNumber = prevQuorumCount; @@ -735,7 +781,7 @@ contract RegistryCoordinator is blsApkRegistry.initializeQuorum(quorumNumber); // Check if the AVS has migrated to operator sets AVSDirectory avsDirectory = AVSDirectory(serviceManager.avsDirectory()); - if (avsDirectory.isOperatorSetAVS(address(serviceManager))){ + if (avsDirectory.isOperatorSetAVS(address(serviceManager))) { // Create an operator set for the new quorum uint32[] memory operatorSetIds = new uint32[](1); operatorSetIds[0] = uint32(quorumNumber); @@ -748,19 +794,21 @@ contract RegistryCoordinator is * @param newBitmap is the most up-to-date set of bitmaps the operator is registered for */ function _updateOperatorBitmap(bytes32 operatorId, uint192 newBitmap) internal { - uint256 historyLength = _operatorBitmapHistory[operatorId].length; if (historyLength == 0) { // No prior bitmap history - push our first entry - _operatorBitmapHistory[operatorId].push(QuorumBitmapUpdate({ - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0, - quorumBitmap: newBitmap - })); + _operatorBitmapHistory[operatorId].push( + QuorumBitmapUpdate({ + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0, + quorumBitmap: newBitmap + }) + ); } else { // We have prior history - fetch our last-recorded update - QuorumBitmapUpdate storage lastUpdate = _operatorBitmapHistory[operatorId][historyLength - 1]; + QuorumBitmapUpdate storage lastUpdate = + _operatorBitmapHistory[operatorId][historyLength - 1]; /** * If the last update was made in the current block, update the entry. @@ -770,11 +818,13 @@ contract RegistryCoordinator is lastUpdate.quorumBitmap = newBitmap; } else { lastUpdate.nextUpdateBlockNumber = uint32(block.number); - _operatorBitmapHistory[operatorId].push(QuorumBitmapUpdate({ - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0, - quorumBitmap: newBitmap - })); + _operatorBitmapHistory[operatorId].push( + QuorumBitmapUpdate({ + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0, + quorumBitmap: newBitmap + }) + ); } } } @@ -796,7 +846,7 @@ contract RegistryCoordinator is * @dev This function is designed to find proper inputs to the `getQuorumBitmapAtBlockNumberByIndex` function */ function _getQuorumBitmapIndexAtBlockNumber( - uint32 blockNumber, + uint32 blockNumber, bytes32 operatorId ) internal view returns (uint32 index) { uint256 length = _operatorBitmapHistory[operatorId].length; @@ -816,11 +866,14 @@ contract RegistryCoordinator is ); } - function _setOperatorSetParams(uint8 quorumNumber, OperatorSetParam memory operatorSetParams) internal { + function _setOperatorSetParams( + uint8 quorumNumber, + OperatorSetParam memory operatorSetParams + ) internal { _quorumParams[quorumNumber] = operatorSetParams; emit OperatorSetParamsUpdated(quorumNumber, operatorSetParams); } - + function _setChurnApprover(address newChurnApprover) internal { emit ChurnApproverUpdated(churnApprover, newChurnApprover); churnApprover = newChurnApprover; @@ -831,12 +884,18 @@ contract RegistryCoordinator is ejector = newEjector; } - /******************************************************************************* - VIEW FUNCTIONS - *******************************************************************************/ + /** + * + * VIEW FUNCTIONS + * + */ /// @notice Returns the operator set params for the given `quorumNumber` - function getOperatorSetParams(uint8 quorumNumber) external view returns (OperatorSetParam memory) { + function getOperatorSetParams(uint8 quorumNumber) + external + view + returns (OperatorSetParam memory) + { return _quorumParams[quorumNumber]; } @@ -856,7 +915,11 @@ contract RegistryCoordinator is } /// @notice Returns the status for the given `operator` - function getOperatorStatus(address operator) external view returns (IRegistryCoordinator.OperatorStatus) { + function getOperatorStatus(address operator) + external + view + returns (IRegistryCoordinator.OperatorStatus) + { return _operatorInfo[operator].status; } @@ -866,7 +929,7 @@ contract RegistryCoordinator is * @dev This function is designed to find proper inputs to the `getQuorumBitmapAtBlockNumberByIndex` function */ function getQuorumBitmapIndicesAtBlockNumber( - uint32 blockNumber, + uint32 blockNumber, bytes32[] memory operatorIds ) external view returns (uint32[] memory) { uint32[] memory indices = new uint32[](operatorIds.length); @@ -881,25 +944,26 @@ contract RegistryCoordinator is * reverting if `index` is incorrect * @dev This function is meant to be used in concert with `getQuorumBitmapIndicesAtBlockNumber`, which * helps off-chain processes to fetch the correct `index` input - */ + */ function getQuorumBitmapAtBlockNumberByIndex( - bytes32 operatorId, - uint32 blockNumber, + bytes32 operatorId, + uint32 blockNumber, uint256 index ) external view returns (uint192) { QuorumBitmapUpdate memory quorumBitmapUpdate = _operatorBitmapHistory[operatorId][index]; - + /** * Validate that the update is valid for the given blockNumber: * - blockNumber should be >= the update block number * - the next update block number should be either 0 or strictly greater than blockNumber */ require( - blockNumber >= quorumBitmapUpdate.updateBlockNumber, + blockNumber >= quorumBitmapUpdate.updateBlockNumber, "RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from after blockNumber" ); require( - quorumBitmapUpdate.nextUpdateBlockNumber == 0 || blockNumber < quorumBitmapUpdate.nextUpdateBlockNumber, + quorumBitmapUpdate.nextUpdateBlockNumber == 0 + || blockNumber < quorumBitmapUpdate.nextUpdateBlockNumber, "RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from before blockNumber" ); @@ -908,7 +972,7 @@ contract RegistryCoordinator is /// @notice Returns the `index`th entry in the operator with `operatorId`'s bitmap history function getQuorumBitmapUpdateByIndex( - bytes32 operatorId, + bytes32 operatorId, uint256 index ) external view returns (QuorumBitmapUpdate memory) { return _operatorBitmapHistory[operatorId][index]; @@ -931,7 +995,7 @@ contract RegistryCoordinator is /** * @notice Public function for the the churnApprover signature hash calculation when operators are being kicked from quorums - * @param registeringOperatorId The id of the registering operator + * @param registeringOperatorId The id of the registering operator * @param operatorKickParams The parameters needed to kick the operator from the quorums that have reached their caps * @param salt The salt to use for the churnApprover's signature * @param expiry The desired expiry time of the churnApprover's signature @@ -944,18 +1008,31 @@ contract RegistryCoordinator is uint256 expiry ) public view returns (bytes32) { // calculate the digest hash - return _hashTypedDataV4(keccak256(abi.encode(OPERATOR_CHURN_APPROVAL_TYPEHASH, registeringOperator, registeringOperatorId, operatorKickParams, salt, expiry))); + return _hashTypedDataV4( + keccak256( + abi.encode( + OPERATOR_CHURN_APPROVAL_TYPEHASH, + registeringOperator, + registeringOperatorId, + operatorKickParams, + salt, + expiry + ) + ) + ); } /** * @notice Returns the message hash that an operator must sign to register their BLS public key. * @param operator is the address of the operator registering their BLS public key */ - function pubkeyRegistrationMessageHash(address operator) public view returns (BN254.G1Point memory) { + function pubkeyRegistrationMessageHash(address operator) + public + view + returns (BN254.G1Point memory) + { return BN254.hashToG1( - _hashTypedDataV4( - keccak256(abi.encode(PUBKEY_REGISTRATION_TYPEHASH, operator)) - ) + _hashTypedDataV4(keccak256(abi.encode(PUBKEY_REGISTRATION_TYPEHASH, operator))) ); } diff --git a/src/libraries/SignatureCheckerLib.sol b/src/libraries/SignatureCheckerLib.sol new file mode 100644 index 00000000..fa2fb137 --- /dev/null +++ b/src/libraries/SignatureCheckerLib.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import {EIP1271SignatureUtils} from + "eigenlayer-contracts/src/contracts/libraries/EIP1271SignatureUtils.sol"; + +/** + * @title SignatureCheckerLib + * @dev This library wraps the EIP1271SignatureUtils library to provide an external function for signature validation. + * This approach helps in reducing the code size of the RegistryCoordinator contract by offloading the signature + * validation logic to this external library. + */ +library SignatureCheckerLib { + /** + * @notice Validates a signature using EIP-1271 standard. + * @param signer The address of the signer. + * @param digestHash The hash of the data that was signed. + * @param signature The signature to be validated. + */ + function isValidSignature( + address signer, + bytes32 digestHash, + bytes memory signature + ) external view { + EIP1271SignatureUtils.checkSignature_EIP1271(signer, digestHash, signature); + } +} From 32148dee470cf8addfff85cbb34d73693bf1c04d Mon Sep 17 00:00:00 2001 From: Madhur Shrimal Date: Thu, 15 Aug 2024 13:46:22 -0700 Subject: [PATCH 14/52] chore: update to latest core (#299) * chore: update to latest eigenlayer-contracts feat/operator-set-release * chore: add method to mock --- lib/eigenlayer-contracts | 2 +- test/mocks/RewardsCoordinatorMock.sol | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/eigenlayer-contracts b/lib/eigenlayer-contracts index f2a7515a..d8a8341c 160000 --- a/lib/eigenlayer-contracts +++ b/lib/eigenlayer-contracts @@ -1 +1 @@ -Subproject commit f2a7515a43162adb5e1b778308349043f60db6a8 +Subproject commit d8a8341c5d5c960e6da7c08a845f2584da579cf7 diff --git a/test/mocks/RewardsCoordinatorMock.sol b/test/mocks/RewardsCoordinatorMock.sol index 6e4f6538..a31df78c 100644 --- a/test/mocks/RewardsCoordinatorMock.sol +++ b/test/mocks/RewardsCoordinatorMock.sol @@ -63,6 +63,8 @@ contract RewardsCoordinatorMock is IRewardsCoordinator { function getDistributionRootAtIndex(uint256 index) external view returns (DistributionRoot memory) {} + function getCurrentClaimableDistributionRoot() external view returns (DistributionRoot memory) {} + function getCurrentDistributionRoot() external view returns (DistributionRoot memory) {} function createAVSRewardsSubmission(RewardsSubmission[] calldata rewardsSubmissions) external {} From 86f0928dd6030eefe971c6de65b1a1241117a149 Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Wed, 21 Aug 2024 14:27:00 -0400 Subject: [PATCH 15/52] feat(op sets): update stakes when forceUnregister (#300) * feat: update stakes handle direct deregistration on AVSDirectory * test: update stake for quorum if operator directly unregistered from the AVSDirectory * chore: simplify setup * chore: simplify setup * chore: make service manager immutable on stakeRegistry --- src/StakeRegistry.sol | 28 ++++++- src/StakeRegistryStorage.sol | 14 +++- src/interfaces/IRegistryCoordinator.sol | 3 + test/harnesses/StakeRegistryHarness.sol | 6 +- test/integration/IntegrationDeployer.t.sol | 2 +- test/mocks/RegistryCoordinatorMock.sol | 4 +- test/unit/RegistryCoordinatorMigration.t.sol | 85 ++++++++++++++++++++ test/unit/StakeRegistryUnit.t.sol | 2 +- test/utils/MockAVSDeployer.sol | 2 +- 9 files changed, 135 insertions(+), 11 deletions(-) diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index 929b67d9..ca4b55fb 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -2,6 +2,8 @@ pragma solidity ^0.8.12; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {StakeRegistryStorage, IStrategy} from "./StakeRegistryStorage.sol"; @@ -40,8 +42,10 @@ contract StakeRegistry is StakeRegistryStorage { constructor( IRegistryCoordinator _registryCoordinator, - IDelegationManager _delegationManager - ) StakeRegistryStorage(_registryCoordinator, _delegationManager) {} + IDelegationManager _delegationManager, + IAVSDirectory _avsDirectory, + IServiceManager _serviceManager + ) StakeRegistryStorage(_registryCoordinator, _delegationManager, _avsDirectory, _serviceManager) {} /******************************************************************************* EXTERNAL FUNCTIONS - REGISTRY COORDINATOR @@ -148,6 +152,10 @@ contract StakeRegistry is StakeRegistryStorage { ) external onlyRegistryCoordinator returns (uint192) { uint192 quorumsToRemove; + bool isOperatorSetAVS = avsDirectory.isOperatorSetAVS( + address(serviceManager) + ); + /** * For each quorum, update the operator's stake and record the delta * in the quorum's total stake. @@ -163,9 +171,21 @@ contract StakeRegistry is StakeRegistryStorage { // Fetch the operator's current stake, applying weighting parameters and checking // against the minimum stake requirements for the quorum. (uint96 stakeWeight, bool hasMinimumStake) = _weightOfOperatorForQuorum(quorumNumber, operator); - // If the operator no longer meets the minimum stake, set their stake to zero and mark them for removal - if (!hasMinimumStake) { + /// also handle setting the operator's stake to 0 and remove them from the quorum + /// if they directly unregistered from the AVSDirectory bubbles up info via registry coordinator to deregister them + bool operatorRegistered; + // Convert quorumNumber to operatorSetId + uint32 operatorSetId = uint32(quorumNumber); + + // Get the AVSDirectory address from the RegistryCoordinator + // Query the AVSDirectory to check if the operator is directly unregistered + operatorRegistered = avsDirectory.isMember( + operator, + IAVSDirectory.OperatorSet(address(serviceManager), operatorSetId) + ); + + if (!hasMinimumStake || (isOperatorSetAVS && !operatorRegistered)) { stakeWeight = 0; quorumsToRemove = uint192(quorumsToRemove.setBit(quorumNumber)); } diff --git a/src/StakeRegistryStorage.sol b/src/StakeRegistryStorage.sol index 6ef74e3e..f76608d2 100644 --- a/src/StakeRegistryStorage.sol +++ b/src/StakeRegistryStorage.sol @@ -2,6 +2,8 @@ pragma solidity ^0.8.12; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {IStrategyManager, IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; @@ -24,6 +26,12 @@ abstract contract StakeRegistryStorage is IStakeRegistry { /// @notice The address of the Delegation contract for EigenLayer. IDelegationManager public immutable delegation; + /// @notice The address of the Delegation contract for EigenLayer. + IAVSDirectory public immutable avsDirectory; + + /// @notice the address of the ServiceManager associtated with the stake registries + IServiceManager public immutable serviceManager; + /// @notice the coordinator contract that this registry is associated with address public immutable registryCoordinator; @@ -47,10 +55,14 @@ abstract contract StakeRegistryStorage is IStakeRegistry { constructor( IRegistryCoordinator _registryCoordinator, - IDelegationManager _delegationManager + IDelegationManager _delegationManager, + IAVSDirectory _avsDirectory, + IServiceManager _serviceManager ) { registryCoordinator = address(_registryCoordinator); delegation = _delegationManager; + avsDirectory = _avsDirectory; + serviceManager = _serviceManager; } // storage gap for upgradeability diff --git a/src/interfaces/IRegistryCoordinator.sol b/src/interfaces/IRegistryCoordinator.sol index 43fa7e0a..3a56baa2 100644 --- a/src/interfaces/IRegistryCoordinator.sol +++ b/src/interfaces/IRegistryCoordinator.sol @@ -1,6 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.12; +import {IServiceManager} from "./IServiceManager.sol"; import {IBLSApkRegistry} from "./IBLSApkRegistry.sol"; import {IStakeRegistry} from "./IStakeRegistry.sol"; import {IIndexRegistry} from "./IIndexRegistry.sol"; @@ -150,4 +151,6 @@ interface IRegistryCoordinator { /// @notice The owner of the registry coordinator function owner() external view returns (address); + + function serviceManager() external view returns (IServiceManager); } diff --git a/test/harnesses/StakeRegistryHarness.sol b/test/harnesses/StakeRegistryHarness.sol index 386508d9..ca3cd2af 100644 --- a/test/harnesses/StakeRegistryHarness.sol +++ b/test/harnesses/StakeRegistryHarness.sol @@ -7,8 +7,10 @@ import "../../src/StakeRegistry.sol"; contract StakeRegistryHarness is StakeRegistry { constructor( IRegistryCoordinator _registryCoordinator, - IDelegationManager _delegationManager - ) StakeRegistry(_registryCoordinator, _delegationManager) { + IDelegationManager _delegationManager, + IAVSDirectory _avsDirectory, + IServiceManager _serviceManager + ) StakeRegistry(_registryCoordinator, _delegationManager, _avsDirectory, _serviceManager) { } function recordOperatorStakeUpdate(bytes32 operatorId, uint8 quorumNumber, uint96 newStake) external returns(int256) { diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index 51525a8c..6d36a8be 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -330,7 +330,7 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { cheats.stopPrank(); StakeRegistry stakeRegistryImplementation = new StakeRegistry( - IRegistryCoordinator(registryCoordinator), IDelegationManager(delegationManager) + IRegistryCoordinator(registryCoordinator), IDelegationManager(delegationManager), IAVSDirectory(avsDirectory), IServiceManager(serviceManager) ); BLSApkRegistry blsApkRegistryImplementation = new BLSApkRegistry(IRegistryCoordinator(registryCoordinator)); diff --git a/test/mocks/RegistryCoordinatorMock.sol b/test/mocks/RegistryCoordinatorMock.sol index abee1a6a..73308f14 100644 --- a/test/mocks/RegistryCoordinatorMock.sol +++ b/test/mocks/RegistryCoordinatorMock.sol @@ -68,4 +68,6 @@ contract RegistryCoordinatorMock is IRegistryCoordinator { function quorumUpdateBlockNumber(uint8 quorumNumber) external view returns (uint256) {} function owner() external view returns (address) {} -} + + function serviceManager() external view returns (IServiceManager){} +} \ No newline at end of file diff --git a/test/unit/RegistryCoordinatorMigration.t.sol b/test/unit/RegistryCoordinatorMigration.t.sol index 0eb80273..357af6d2 100644 --- a/test/unit/RegistryCoordinatorMigration.t.sol +++ b/test/unit/RegistryCoordinatorMigration.t.sol @@ -197,4 +197,89 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas assertTrue(avsDirectory.isOperatorSet(address(serviceManager), quorumNumber), "Operator set was not created for the quorum"); } + + function test_updateOperatorsForQuorumsAfterDirectUnregister() public { + vm.prank(proxyAdmin.owner()); + proxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(avsDirectory))), + address(avsDirectoryMock) + ); + uint256 pseudoRandomNumber = uint256(keccak256("pseudoRandomNumber")); + _registerRandomOperators(pseudoRandomNumber); + + vm.prank(proxyAdmin.owner()); + proxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(avsDirectory))), + address(avsDirectoryHarness) + ); + + uint256 quorumCount = registryCoordinator.quorumCount(); + for (uint256 i = 0; i < quorumCount; i++) { + uint256 operatorCount = indexRegistry.totalOperatorsForQuorum(uint8(i)); + bytes32[] memory operatorIds = + indexRegistry.getOperatorListAtBlockNumber(uint8(i), uint32(block.number)); + assertEq(operatorCount, operatorIds.length, "Operator Id length mismatch"); // sanity check + for (uint256 j = 0; j < operatorCount; j++) { + address operatorAddress = + registryCoordinator.blsApkRegistry().getOperatorFromPubkeyHash(operatorIds[j]); + AVSDirectoryHarness(address(avsDirectory)).setAvsOperatorStatus( + address(serviceManager), + operatorAddress, + IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED + ); + } + } + + ( + uint32[] memory operatorSetsToCreate, + uint32[][] memory operatorSetIdsToMigrate, + address[] memory operators + ) = serviceManager.getOperatorsToMigrate(); + cheats.startPrank(serviceManagerOwner); + serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); + serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); + cheats.stopPrank(); + + bytes32[] memory registeredOperators = indexRegistry.getOperatorListAtBlockNumber(defaultQuorumNumber, uint32(block.number)); + uint256 preNumOperators = registeredOperators.length; + address[] memory registeredOperatorAddresses = new address[](registeredOperators.length); + for (uint256 i = 0; i < registeredOperators.length; i++) { + registeredOperatorAddresses[i] = registryCoordinator.blsApkRegistry().pubkeyHashToOperator(registeredOperators[i]); + } + + uint32[] memory operatorSetsToUnregister = new uint32[](1); + operatorSetsToUnregister[0] = defaultQuorumNumber; + + vm.prank(operators[0]); + avsDirectory.forceDeregisterFromOperatorSets( + operators[0], + address(serviceManager), + operatorSetsToUnregister, + ISignatureUtils.SignatureWithSaltAndExpiry({ + signature: new bytes(0), + salt: bytes32(0), + expiry: 0 + }) + ); + // sanity check if the operator was unregistered from the intended operator set + bool operatorIsUnRegistered = !avsDirectory.isMember(operators[0], IAVSDirectory.OperatorSet({ + avs: address(serviceManager), + operatorSetId: defaultQuorumNumber + })); + bool isOperatorSetAVS = avsDirectory.isOperatorSetAVS(address(serviceManager)); + assertTrue(isOperatorSetAVS, "ServiceManager is not an operator set AVS"); + assertTrue(operatorIsUnRegistered, "Operator wasnt unregistered from op set"); + + address[][] memory registeredOperatorAddresses2D = new address[][](1); + registeredOperatorAddresses2D[0] = registeredOperatorAddresses; + bytes memory quorumNumbers = new bytes(1); + quorumNumbers[0] = bytes1(defaultQuorumNumber); + registryCoordinator.updateOperatorsForQuorum(registeredOperatorAddresses2D, quorumNumbers); + + registeredOperators = indexRegistry.getOperatorListAtBlockNumber(defaultQuorumNumber, uint32(block.number)); + uint256 postRegisteredOperators = registeredOperators.length; + + assertEq(preNumOperators-1, postRegisteredOperators, ""); + + } } diff --git a/test/unit/StakeRegistryUnit.t.sol b/test/unit/StakeRegistryUnit.t.sol index ed53225c..56f244cf 100644 --- a/test/unit/StakeRegistryUnit.t.sol +++ b/test/unit/StakeRegistryUnit.t.sol @@ -52,7 +52,7 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { ); stakeRegistryImplementation = new StakeRegistryHarness( - IRegistryCoordinator(address(registryCoordinator)), delegationMock + IRegistryCoordinator(address(registryCoordinator)), delegationMock, avsDirectoryMock, serviceManager ); stakeRegistry = StakeRegistryHarness( diff --git a/test/utils/MockAVSDeployer.sol b/test/utils/MockAVSDeployer.sol index b3eebf1a..7ce4d5c4 100644 --- a/test/utils/MockAVSDeployer.sol +++ b/test/utils/MockAVSDeployer.sol @@ -222,7 +222,7 @@ contract MockAVSDeployer is Test { cheats.startPrank(proxyAdminOwner); stakeRegistryImplementation = - new StakeRegistryHarness(IRegistryCoordinator(registryCoordinator), delegationMock); + new StakeRegistryHarness(IRegistryCoordinator(registryCoordinator), delegationMock, avsDirectory, serviceManager); proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(stakeRegistry))), From f6ad20ecedf810bb13b11aba18691195227e4d2f Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Thu, 22 Aug 2024 10:54:54 -0400 Subject: [PATCH 16/52] feat(op sets): register and deregister (#301) * feat: register and deregister to operator sets * fix: bytecode wrangling * chore: shorter errors to reduce bytecode * test: register after migration * chore: remove stale todos * chore: add back commented line * chore: remain consistent with m2 events * fix: side effect of merge from _deregister function * fix: bytecode massaging * chore: rename for clarity * chore: remove comments and whitespace * docs: add natspec to the library --- src/RegistryCoordinator.sol | 171 +++++++---------- src/RegistryCoordinatorStorage.sol | 7 +- src/ServiceManagerBase.sol | 26 +++ src/interfaces/IServiceManager.sol | 20 ++ src/libraries/BN254.sol | 18 +- src/libraries/QuorumBitmapHistoryLib.sol | 145 ++++++++++++++ .../RegistryCoordinatorHarness.t.sol | 5 +- test/integration/CoreRegistration.t.sol | 3 +- test/integration/IntegrationDeployer.t.sol | 2 +- test/mocks/ECDSAServiceManagerMock.sol | 8 + test/unit/OperatorStateRetrieverUnit.t.sol | 8 +- test/unit/RegistryCoordinatorMigration.t.sol | 179 ++++++++++++++++++ test/unit/RegistryCoordinatorUnit.t.sol | 30 +-- test/unit/StakeRegistryUnit.t.sol | 3 +- test/utils/MockAVSDeployer.sol | 2 +- 15 files changed, 494 insertions(+), 133 deletions(-) create mode 100644 src/libraries/QuorumBitmapHistoryLib.sol diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 738213f3..818f0541 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.12; import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; -import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; +import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {ISocketUpdater} from "./interfaces/ISocketUpdater.sol"; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; @@ -14,6 +14,7 @@ import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; import {BitmapUtils} from "./libraries/BitmapUtils.sol"; import {BN254} from "./libraries/BN254.sol"; import {SignatureCheckerLib} from "./libraries/SignatureCheckerLib.sol"; +import {QuorumBitmapHistoryLib} from "./libraries/QuorumBitmapHistoryLib.sol"; import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; @@ -58,9 +59,10 @@ contract RegistryCoordinator is IServiceManager _serviceManager, IStakeRegistry _stakeRegistry, IBLSApkRegistry _blsApkRegistry, - IIndexRegistry _indexRegistry + IIndexRegistry _indexRegistry, + IAVSDirectory _avsDirectory ) - RegistryCoordinatorStorage(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry) + RegistryCoordinatorStorage(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry, _avsDirectory) EIP712("AVSRegistryCoordinator", "v0.0.1") { _disableInitializers(); @@ -158,7 +160,7 @@ contract RegistryCoordinator is require( numOperatorsPerQuorum[i] <= _quorumParams[quorumNumber].maxOperatorCount, - "RegistryCoordinator.registerOperator: operator count exceeds maximum" + "RegistryCoordinator.registerOperator: operator exceeds max" ); } } @@ -333,7 +335,7 @@ contract RegistryCoordinator is // Prevent duplicate operators require( operator > prevOperatorAddress, - "RegistryCoordinator.updateOperatorsForQuorum: operators array must be sorted in ascending address order" + "RegistryCoordinator.updateOperatorsForQuorum: operators must be sorted" ); } @@ -355,7 +357,7 @@ contract RegistryCoordinator is function updateSocket(string memory socket) external { require( _operatorInfo[msg.sender].status == OperatorStatus.REGISTERED, - "RegistryCoordinator.updateSocket: operator is not registered" + "RegistryCoordinator.updateSocket: not registered" ); emit OperatorSocketUpdate(_operatorInfo[msg.sender].operatorId, socket); } @@ -486,7 +488,7 @@ contract RegistryCoordinator is uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); uint192 currentBitmap = _currentOperatorBitmap(operatorId); require( - !quorumsToAdd.isEmpty(), "RegistryCoordinator._registerOperator: bitmap cannot be 0" + !quorumsToAdd.isEmpty(), "RegistryCoordinator._registerOperator: bitmap empty" ); require( quorumsToAdd.noBitsInCommon(currentBitmap), @@ -515,9 +517,20 @@ contract RegistryCoordinator is OperatorInfo({operatorId: operatorId, status: OperatorStatus.REGISTERED}); // Register the operator with the EigenLayer core contracts via this AVS's ServiceManager - serviceManager.registerOperatorToAVS(operator, operatorSignature); + bool operatorSetAVS = avsDirectory.isOperatorSetAVS(address(serviceManager)); + if (operatorSetAVS){ + bytes memory quorumBytes = BitmapUtils.bitmapToBytesArray(quorumsToAdd); + uint32[] memory operatorSetIds = new uint32[](quorumBytes.length); + for (uint256 i = 0; i < quorumBytes.length; i++) { + operatorSetIds[i] = uint8(quorumBytes[i]); + } + serviceManager.registerOperatorToOperatorSets(operator, operatorSetIds, operatorSignature); + + } else { + serviceManager.registerOperatorToAVS(operator, operatorSignature); + emit OperatorRegistered(operator, operatorId); + } - emit OperatorRegistered(operator, operatorId); } // Register the operator with the BLSApkRegistry, StakeRegistry, and IndexRegistry @@ -534,7 +547,7 @@ contract RegistryCoordinator is * @dev Reverts if the caller is not the ejector */ function _checkEjector() internal view { - require(msg.sender == ejector, "RegistryCoordinator.onlyEjector: caller is not the ejector"); + require(msg.sender == ejector, "RegistryCoordinator.onlyEjector: not ejector"); } /** @@ -628,7 +641,7 @@ contract RegistryCoordinator is bytes32 operatorId = operatorInfo.operatorId; require( operatorInfo.status == OperatorStatus.REGISTERED, - "RegistryCoordinator._deregisterOperator: operator is not registered" + "RegistryCoordinator._deregisterOperator: not registered" ); /** @@ -647,19 +660,54 @@ contract RegistryCoordinator is ); require( quorumsToRemove.isSubsetOf(currentBitmap), - "RegistryCoordinator._deregisterOperator: operator is not registered for specified quorums" + "RegistryCoordinator._deregisterOperator: not registered for quorum" ); uint192 newBitmap = uint192(currentBitmap.minus(quorumsToRemove)); // Update operator's bitmap and status _updateOperatorBitmap({operatorId: operatorId, newBitmap: newBitmap}); - // If the operator is no longer registered for any quorums, update their status and deregister - // them from the AVS via the EigenLayer core contracts - if (newBitmap.isEmpty()) { - operatorInfo.status = OperatorStatus.DEREGISTERED; - serviceManager.deregisterOperatorFromAVS(operator); - emit OperatorDeregistered(operator, operatorId); + + bool operatorSetAVS = IAVSDirectory(serviceManager.avsDirectory()).isOperatorSetAVS(address(serviceManager)); + if (operatorSetAVS){ + bytes memory quorumBytes = BitmapUtils.bitmapToBytesArray(quorumsToRemove); + uint32[] memory operatorSetIds = new uint32[](quorumBytes.length); + uint256 forceDeregistrationCount; + for (uint256 i = 0; i < quorumBytes.length; i++) { + /// We need to track forceDeregistrations so we don't pass an id that was already deregistered on the AVSDirectory + /// but hasnt yet been recorded in the middleware contracts + if (!avsDirectory.isMember(operator, IAVSDirectory.OperatorSet(address(serviceManager), uint8(quorumBytes[i])))){ + forceDeregistrationCount++; + } + operatorSetIds[i] = uint8(quorumBytes[i]); + } + + /// Filter out forceDeregistration operator set Ids + if (forceDeregistrationCount > 0 ){ + uint32[] memory filteredOperatorSetIds = new uint32[](operatorSetIds.length - forceDeregistrationCount); + uint256 offset; + for (uint256 i; i < operatorSetIds.length; i++){ + if (avsDirectory.isMember(operator, IAVSDirectory.OperatorSet(address(serviceManager), operatorSetIds[i]))){ + filteredOperatorSetIds[i] = operatorSetIds[i+offset]; + } else { + offset++; + } + } + serviceManager.deregisterOperatorFromOperatorSets(operator, filteredOperatorSetIds); + } else { + serviceManager.deregisterOperatorFromOperatorSets(operator, operatorSetIds); + + } + + + } else { + // If the operator is no longer registered for any quorums, update their status and deregister + // them from the AVS via the EigenLayer core contracts + if (newBitmap.isEmpty()) { + operatorInfo.status = OperatorStatus.DEREGISTERED; + serviceManager.deregisterOperatorFromAVS(operator); + emit OperatorDeregistered(operator, operatorId); + } } // Deregister operator with each of the registry contracts @@ -726,11 +774,11 @@ contract RegistryCoordinator is // make sure the salt hasn't been used already require( !isChurnApproverSaltUsed[churnApproverSignature.salt], - "RegistryCoordinator._verifyChurnApproverSignature: churnApprover salt already used" + "RegistryCoordinator._verifyChurnApproverSignature: salt spent" ); require( churnApproverSignature.expiry >= block.timestamp, - "RegistryCoordinator._verifyChurnApproverSignature: churnApprover signature expired" + "RegistryCoordinator._verifyChurnApproverSignature: signature expired" ); // set salt used to true @@ -780,7 +828,6 @@ contract RegistryCoordinator is indexRegistry.initializeQuorum(quorumNumber); blsApkRegistry.initializeQuorum(quorumNumber); // Check if the AVS has migrated to operator sets - AVSDirectory avsDirectory = AVSDirectory(serviceManager.avsDirectory()); if (avsDirectory.isOperatorSetAVS(address(serviceManager))) { // Create an operator set for the new quorum uint32[] memory operatorSetIds = new uint32[](1); @@ -794,50 +841,13 @@ contract RegistryCoordinator is * @param newBitmap is the most up-to-date set of bitmaps the operator is registered for */ function _updateOperatorBitmap(bytes32 operatorId, uint192 newBitmap) internal { - uint256 historyLength = _operatorBitmapHistory[operatorId].length; - - if (historyLength == 0) { - // No prior bitmap history - push our first entry - _operatorBitmapHistory[operatorId].push( - QuorumBitmapUpdate({ - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0, - quorumBitmap: newBitmap - }) - ); - } else { - // We have prior history - fetch our last-recorded update - QuorumBitmapUpdate storage lastUpdate = - _operatorBitmapHistory[operatorId][historyLength - 1]; - - /** - * If the last update was made in the current block, update the entry. - * Otherwise, push a new entry and update the previous entry's "next" field - */ - if (lastUpdate.updateBlockNumber == uint32(block.number)) { - lastUpdate.quorumBitmap = newBitmap; - } else { - lastUpdate.nextUpdateBlockNumber = uint32(block.number); - _operatorBitmapHistory[operatorId].push( - QuorumBitmapUpdate({ - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0, - quorumBitmap: newBitmap - }) - ); - } - } + QuorumBitmapHistoryLib.updateOperatorBitmap(_operatorBitmapHistory, operatorId, newBitmap); } /// @notice Get the most recent bitmap for the operator, returning an empty bitmap if /// the operator is not registered. function _currentOperatorBitmap(bytes32 operatorId) internal view returns (uint192) { - uint256 historyLength = _operatorBitmapHistory[operatorId].length; - if (historyLength == 0) { - return 0; - } else { - return _operatorBitmapHistory[operatorId][historyLength - 1].quorumBitmap; - } + return QuorumBitmapHistoryLib.currentOperatorBitmap(_operatorBitmapHistory, operatorId); } /** @@ -849,21 +859,7 @@ contract RegistryCoordinator is uint32 blockNumber, bytes32 operatorId ) internal view returns (uint32 index) { - uint256 length = _operatorBitmapHistory[operatorId].length; - - // Traverse the operator's bitmap history in reverse, returning the first index - // corresponding to an update made before or at `blockNumber` - for (uint256 i = 0; i < length; i++) { - index = uint32(length - i - 1); - - if (_operatorBitmapHistory[operatorId][index].updateBlockNumber <= blockNumber) { - return index; - } - } - - revert( - "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number" - ); + return QuorumBitmapHistoryLib.getQuorumBitmapIndexAtBlockNumber(_operatorBitmapHistory,blockNumber, operatorId); } function _setOperatorSetParams( @@ -932,11 +928,7 @@ contract RegistryCoordinator is uint32 blockNumber, bytes32[] memory operatorIds ) external view returns (uint32[] memory) { - uint32[] memory indices = new uint32[](operatorIds.length); - for (uint256 i = 0; i < operatorIds.length; i++) { - indices[i] = _getQuorumBitmapIndexAtBlockNumber(blockNumber, operatorIds[i]); - } - return indices; + return QuorumBitmapHistoryLib.getQuorumBitmapIndicesAtBlockNumber(_operatorBitmapHistory, blockNumber, operatorIds); } /** @@ -950,24 +942,7 @@ contract RegistryCoordinator is uint32 blockNumber, uint256 index ) external view returns (uint192) { - QuorumBitmapUpdate memory quorumBitmapUpdate = _operatorBitmapHistory[operatorId][index]; - - /** - * Validate that the update is valid for the given blockNumber: - * - blockNumber should be >= the update block number - * - the next update block number should be either 0 or strictly greater than blockNumber - */ - require( - blockNumber >= quorumBitmapUpdate.updateBlockNumber, - "RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from after blockNumber" - ); - require( - quorumBitmapUpdate.nextUpdateBlockNumber == 0 - || blockNumber < quorumBitmapUpdate.nextUpdateBlockNumber, - "RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from before blockNumber" - ); - - return quorumBitmapUpdate.quorumBitmap; + return QuorumBitmapHistoryLib.getQuorumBitmapAtBlockNumberByIndex(_operatorBitmapHistory, operatorId, blockNumber, index); } /// @notice Returns the `index`th entry in the operator with `operatorId`'s bitmap history diff --git a/src/RegistryCoordinatorStorage.sol b/src/RegistryCoordinatorStorage.sol index 5451efb3..64486e93 100644 --- a/src/RegistryCoordinatorStorage.sol +++ b/src/RegistryCoordinatorStorage.sol @@ -5,6 +5,7 @@ import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; +import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { @@ -39,6 +40,8 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { IStakeRegistry public immutable stakeRegistry; /// @notice the Index Registry contract that will keep track of operators' indexes IIndexRegistry public immutable indexRegistry; + /// @notice the AVS Directory that tracks operator registrations to AVS and operator sets + IAVSDirectory public immutable avsDirectory; /******************************************************************************* STATE @@ -73,12 +76,14 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { IServiceManager _serviceManager, IStakeRegistry _stakeRegistry, IBLSApkRegistry _blsApkRegistry, - IIndexRegistry _indexRegistry + IIndexRegistry _indexRegistry, + IAVSDirectory _avsDirectory ) { serviceManager = _serviceManager; stakeRegistry = _stakeRegistry; blsApkRegistry = _blsApkRegistry; indexRegistry = _indexRegistry; + avsDirectory = _avsDirectory; } // storage gap for upgradeability diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index f7f4a957..2fbacea2 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -133,6 +133,32 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _avsDirectory.deregisterOperatorFromAVS(operator); } + /** + * @notice Forwards a call to EigenLayer's AVSDirectory contract to register an operator to operator sets + * @param operator The address of the operator to register. + * @param operatorSetIds The IDs of the operator sets. + * @param operatorSignature The signature, salt, and expiry of the operator's signature. + */ + function registerOperatorToOperatorSets( + address operator, + uint32[] calldata operatorSetIds, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) public virtual onlyRegistryCoordinator { + _avsDirectory.registerOperatorToOperatorSets(operator, operatorSetIds, operatorSignature); + } + + /** + * @notice Forwards a call to EigenLayer's AVSDirectory contract to deregister an operator from operator sets + * @param operator The address of the operator to deregister. + * @param operatorSetIds The IDs of the operator sets. + */ + function deregisterOperatorFromOperatorSets( + address operator, + uint32[] calldata operatorSetIds + ) public virtual onlyRegistryCoordinator { + _avsDirectory.deregisterOperatorFromOperatorSets(operator, operatorSetIds); + } + /** * @notice Sets the rewards initiator address * @param newRewardsInitiator The new rewards initiator address diff --git a/src/interfaces/IServiceManager.sol b/src/interfaces/IServiceManager.sol index 26f2c71b..8807e9df 100644 --- a/src/interfaces/IServiceManager.sol +++ b/src/interfaces/IServiceManager.sol @@ -3,6 +3,7 @@ pragma solidity >=0.5.0; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; import {IServiceManagerUI} from "./IServiceManagerUI.sol"; +import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; /** * @title Minimal interface for a ServiceManager-type contract that forms the single point for an AVS to push updates to EigenLayer @@ -24,6 +25,25 @@ interface IServiceManager is IServiceManagerUI { function createOperatorSets(uint32[] memory operatorSetIds) external ; + /** + * @notice Forwards a call to EigenLayer's AVSDirectory contract to register an operator to operator sets + * @param operator The address of the operator to register. + * @param operatorSetIds The IDs of the operator sets. + * @param operatorSignature The signature, salt, and expiry of the operator's signature. + */ + function registerOperatorToOperatorSets( + address operator, + uint32[] calldata operatorSetIds, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external; + + /** + * @notice Forwards a call to EigenLayer's AVSDirectory contract to deregister an operator from operator sets + * @param operator The address of the operator to deregister. + * @param operatorSetIds The IDs of the operator sets. + */ + function deregisterOperatorFromOperatorSets(address operator, uint32[] calldata operatorSetIds) external; + // EVENTS event RewardsInitiatorUpdated(address prevRewardsInitiator, address newRewardsInitiator); } diff --git a/src/libraries/BN254.sol b/src/libraries/BN254.sol index 0d8adb92..4d0edf70 100644 --- a/src/libraries/BN254.sol +++ b/src/libraries/BN254.sol @@ -46,7 +46,7 @@ library BN254 { uint256[2] Y; } - function generatorG1() internal pure returns (G1Point memory) { + function generatorG1() external pure returns (G1Point memory) { return G1Point(1, 2); } @@ -62,7 +62,7 @@ library BN254 { /// this is because of the (unknown to us) convention used in the bn254 pairing precompile contract /// "Elements a * i + b of F_p^2 are encoded as two elements of F_p, (a, b)." /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md#encoding - function generatorG2() internal pure returns (G2Point memory) { + function generatorG2() external pure returns (G2Point memory) { return G2Point([G2x1, G2x0], [G2y1, G2y0]); } @@ -73,7 +73,7 @@ library BN254 { uint256 internal constant nG2y1 = 17805874995975841540914202342111839520379459829704422454583296818431106115052; uint256 internal constant nG2y0 = 13392588948715843804641432497768002650278120570034223513918757245338268106653; - function negGeneratorG2() internal pure returns (G2Point memory) { + function negGeneratorG2() external pure returns (G2Point memory) { return G2Point([nG2x1, nG2x0], [nG2y1, nG2y0]); } @@ -84,7 +84,7 @@ library BN254 { * @param p Some point in G1. * @return The negation of `p`, i.e. p.plus(p.negate()) should be zero. */ - function negate(G1Point memory p) internal pure returns (G1Point memory) { + function negate(G1Point memory p) external pure returns (G1Point memory) { // The prime q in the base field F_q for G1 if (p.X == 0 && p.Y == 0) { return G1Point(0, 0); @@ -194,7 +194,7 @@ library BN254 { G2Point memory a2, G1Point memory b1, G2Point memory b2 - ) internal view returns (bool) { + ) external view returns (bool) { G1Point[2] memory p1 = [a1, b1]; G2Point[2] memory p2 = [a2, b2]; @@ -238,7 +238,7 @@ library BN254 { G1Point memory b1, G2Point memory b2, uint256 pairingGas - ) internal view returns (bool, bool) { + ) external view returns (bool, bool) { G1Point[2] memory p1 = [a1, b1]; G2Point[2] memory p2 = [a2, b2]; @@ -270,7 +270,7 @@ library BN254 { /// @return hashedG1 the keccak256 hash of the G1 Point /// @dev used for BLS signatures - function hashG1Point(BN254.G1Point memory pk) internal pure returns (bytes32 hashedG1) { + function hashG1Point(BN254.G1Point memory pk) external pure returns (bytes32 hashedG1) { assembly { mstore(0, mload(pk)) mstore(0x20, mload(add(0x20, pk))) @@ -282,14 +282,14 @@ library BN254 { /// @dev used for BLS signatures function hashG2Point( BN254.G2Point memory pk - ) internal pure returns (bytes32) { + ) external pure returns (bytes32) { return keccak256(abi.encodePacked(pk.X[0], pk.X[1], pk.Y[0], pk.Y[1])); } /** * @notice adapted from https://github.com/HarryR/solcrypto/blob/master/contracts/altbn128.sol */ - function hashToG1(bytes32 _x) internal view returns (G1Point memory) { + function hashToG1(bytes32 _x) external view returns (G1Point memory) { uint256 beta = 0; uint256 y = 0; diff --git a/src/libraries/QuorumBitmapHistoryLib.sol b/src/libraries/QuorumBitmapHistoryLib.sol new file mode 100644 index 00000000..4a3e72fd --- /dev/null +++ b/src/libraries/QuorumBitmapHistoryLib.sol @@ -0,0 +1,145 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import {IRegistryCoordinator} from "../interfaces/IRegistryCoordinator.sol"; + +/// @title QuorumBitmapHistoryLib +/// @notice This library operates on the _operatorBitmapHistory in the RegistryCoordinator +library QuorumBitmapHistoryLib { + + /// @notice Retrieves the index of the quorum bitmap update at or before the specified block number + /// @param self The mapping of operator IDs to their quorum bitmap update history + /// @param blockNumber The block number to search for + /// @param operatorId The ID of the operator + /// @return index The index of the quorum bitmap update + function getQuorumBitmapIndexAtBlockNumber( + mapping(bytes32 => IRegistryCoordinator.QuorumBitmapUpdate[]) storage self, + uint32 blockNumber, + bytes32 operatorId + ) internal view returns (uint32 index) { + uint256 length = self[operatorId].length; + + // Traverse the operator's bitmap history in reverse, returning the first index + // corresponding to an update made before or at `blockNumber` + for (uint256 i = 0; i < length; i++) { + index = uint32(length - i - 1); + + if (self[operatorId][index].updateBlockNumber <= blockNumber) { + return index; + } + } + + revert( + "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId" + ); + } + + /// @notice Retrieves the current quorum bitmap for the given operator ID + /// @param self The mapping of operator IDs to their quorum bitmap update history + /// @param operatorId The ID of the operator + /// @return The current quorum bitmap + function currentOperatorBitmap( + mapping(bytes32 => IRegistryCoordinator.QuorumBitmapUpdate[]) storage self, + bytes32 operatorId + ) external view returns (uint192) { + uint256 historyLength = self[operatorId].length; + if (historyLength == 0) { + return 0; + } else { + return self[operatorId][historyLength - 1].quorumBitmap; + } + } + + /// @notice Retrieves the indices of the quorum bitmap updates for the given operator IDs at the specified block number + /// @param self The mapping of operator IDs to their quorum bitmap update history + /// @param blockNumber The block number to search for + /// @param operatorIds The array of operator IDs + /// @return An array of indices corresponding to the quorum bitmap updates + function getQuorumBitmapIndicesAtBlockNumber( + mapping(bytes32 => IRegistryCoordinator.QuorumBitmapUpdate[]) storage self, + uint32 blockNumber, + bytes32[] memory operatorIds + ) external view returns (uint32[] memory) { + uint32[] memory indices = new uint32[](operatorIds.length); + for (uint256 i = 0; i < operatorIds.length; i++) { + indices[i] = getQuorumBitmapIndexAtBlockNumber(self, blockNumber, operatorIds[i]); + } + return indices; + } + + /// @notice Retrieves the quorum bitmap for the given operator ID at the specified block number and index + /// @param self The mapping of operator IDs to their quorum bitmap update history + /// @param operatorId The ID of the operator + /// @param blockNumber The block number to validate against + /// @param index The index of the quorum bitmap update + /// @return The quorum bitmap at the specified index + function getQuorumBitmapAtBlockNumberByIndex( + mapping(bytes32 => IRegistryCoordinator.QuorumBitmapUpdate[]) storage self, + bytes32 operatorId, + uint32 blockNumber, + uint256 index + ) external view returns (uint192) { + IRegistryCoordinator.QuorumBitmapUpdate memory quorumBitmapUpdate = self[operatorId][index]; + + /** + * Validate that the update is valid for the given blockNumber: + * - blockNumber should be >= the update block number + * - the next update block number should be either 0 or strictly greater than blockNumber + */ + require( + blockNumber >= quorumBitmapUpdate.updateBlockNumber, + "RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from after blockNumber" + ); + require( + quorumBitmapUpdate.nextUpdateBlockNumber == 0 + || blockNumber < quorumBitmapUpdate.nextUpdateBlockNumber, + "RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from before blockNumber" + ); + + return quorumBitmapUpdate.quorumBitmap; + } + + /// @notice Updates the quorum bitmap for the given operator ID + /// @param self The mapping of operator IDs to their quorum bitmap update history + /// @param operatorId The ID of the operator + /// @param newBitmap The new quorum bitmap to set + function updateOperatorBitmap( + mapping(bytes32 => IRegistryCoordinator.QuorumBitmapUpdate[]) storage self, + bytes32 operatorId, + uint192 newBitmap + ) external { + uint256 historyLength = self[operatorId].length; + + if (historyLength == 0) { + // No prior bitmap history - push our first entry + self[operatorId].push( + IRegistryCoordinator.QuorumBitmapUpdate({ + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0, + quorumBitmap: newBitmap + }) + ); + } else { + // We have prior history - fetch our last-recorded update + IRegistryCoordinator.QuorumBitmapUpdate storage lastUpdate = + self[operatorId][historyLength - 1]; + + /** + * If the last update was made in the current block, update the entry. + * Otherwise, push a new entry and update the previous entry's "next" field + */ + if (lastUpdate.updateBlockNumber == uint32(block.number)) { + lastUpdate.quorumBitmap = newBitmap; + } else { + lastUpdate.nextUpdateBlockNumber = uint32(block.number); + self[operatorId].push( + IRegistryCoordinator.QuorumBitmapUpdate({ + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0, + quorumBitmap: newBitmap + }) + ); + } + } + } +} diff --git a/test/harnesses/RegistryCoordinatorHarness.t.sol b/test/harnesses/RegistryCoordinatorHarness.t.sol index d7ae81ae..4644c276 100644 --- a/test/harnesses/RegistryCoordinatorHarness.t.sol +++ b/test/harnesses/RegistryCoordinatorHarness.t.sol @@ -11,8 +11,9 @@ contract RegistryCoordinatorHarness is RegistryCoordinator, Test { IServiceManager _serviceManager, IStakeRegistry _stakeRegistry, IBLSApkRegistry _blsApkRegistry, - IIndexRegistry _indexRegistry - ) RegistryCoordinator(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry) { + IIndexRegistry _indexRegistry, + IAVSDirectory _avsDirectory + ) RegistryCoordinator(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry, _avsDirectory) { _transferOwnership(msg.sender); } diff --git a/test/integration/CoreRegistration.t.sol b/test/integration/CoreRegistration.t.sol index 5998025c..f6cbf571 100644 --- a/test/integration/CoreRegistration.t.sol +++ b/test/integration/CoreRegistration.t.sol @@ -79,7 +79,8 @@ contract Test_CoreRegistration is MockAVSDeployer { serviceManager, stakeRegistry, blsApkRegistry, - indexRegistry + indexRegistry, + avsDirectory ); // Upgrade Registry Coordinator & ServiceManager diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index 4f6bd719..ee3722a7 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -341,7 +341,7 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { }); RegistryCoordinator registryCoordinatorImplementation = - new RegistryCoordinator(serviceManager, stakeRegistry, blsApkRegistry, indexRegistry); + new RegistryCoordinator(serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, avsDirectory); proxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(registryCoordinator))), address(registryCoordinatorImplementation), diff --git a/test/mocks/ECDSAServiceManagerMock.sol b/test/mocks/ECDSAServiceManagerMock.sol index e38e0395..88e3ac6f 100644 --- a/test/mocks/ECDSAServiceManagerMock.sol +++ b/test/mocks/ECDSAServiceManagerMock.sol @@ -26,4 +26,12 @@ contract ECDSAServiceManagerMock is ECDSAServiceManagerBase { } function createOperatorSets(uint32[] memory) external {} + + function registerOperatorToOperatorSets( + address operator, + uint32[] calldata operatorSetIds, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external {} + + function deregisterOperatorFromOperatorSets(address operator, uint32[] calldata operatorSetIds) external{} } diff --git a/test/unit/OperatorStateRetrieverUnit.t.sol b/test/unit/OperatorStateRetrieverUnit.t.sol index ba4fe75e..78b634d7 100644 --- a/test/unit/OperatorStateRetrieverUnit.t.sol +++ b/test/unit/OperatorStateRetrieverUnit.t.sol @@ -13,7 +13,7 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { function test_getOperatorState_revert_neverRegistered() public { cheats.expectRevert( - "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number" + "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId" ); operatorStateRetriever.getOperatorState( registryCoordinator, defaultOperatorId, uint32(block.number) @@ -26,7 +26,7 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { // should revert because the operator was registered for the first time after the reference block number cheats.expectRevert( - "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number" + "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId" ); operatorStateRetriever.getOperatorState( registryCoordinator, defaultOperatorId, registrationBlockNumber - 1 @@ -143,7 +143,7 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { nonSignerOperatorIds[0] = defaultOperatorId; cheats.expectRevert( - "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number" + "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId" ); operatorStateRetriever.getCheckSignaturesIndices( registryCoordinator, @@ -164,7 +164,7 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { // should revert because the operator was registered for the first time after the reference block number cheats.expectRevert( - "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number" + "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId" ); operatorStateRetriever.getCheckSignaturesIndices( registryCoordinator, diff --git a/test/unit/RegistryCoordinatorMigration.t.sol b/test/unit/RegistryCoordinatorMigration.t.sol index 357af6d2..99fd38f4 100644 --- a/test/unit/RegistryCoordinatorMigration.t.sol +++ b/test/unit/RegistryCoordinatorMigration.t.sol @@ -7,6 +7,7 @@ import { IRewardsCoordinator, IERC20 } from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; +import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {StrategyBase} from "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; import {IServiceManagerBaseEvents} from "../events/IServiceManagerBaseEvents.sol"; import {AVSDirectoryHarness} from "../harnesses/AVSDirectoryHarness.sol"; @@ -282,4 +283,182 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas assertEq(preNumOperators-1, postRegisteredOperators, ""); } + + function test_deregister_afterMigration() public { + vm.prank(proxyAdmin.owner()); + proxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(avsDirectory))), + address(avsDirectoryMock) + ); + uint256 pseudoRandomNumber = uint256(keccak256("pseudoRandomNumber")); + _registerRandomOperators(pseudoRandomNumber); + + vm.prank(proxyAdmin.owner()); + proxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(avsDirectory))), + address(avsDirectoryHarness) + ); + + uint256 quorumCount = registryCoordinator.quorumCount(); + for (uint256 i = 0; i < quorumCount; i++) { + uint256 operatorCount = indexRegistry.totalOperatorsForQuorum(uint8(i)); + bytes32[] memory operatorIds = + indexRegistry.getOperatorListAtBlockNumber(uint8(i), uint32(block.number)); + assertEq(operatorCount, operatorIds.length, "Operator Id length mismatch"); // sanity check + for (uint256 j = 0; j < operatorCount; j++) { + address operatorAddress = + registryCoordinator.blsApkRegistry().getOperatorFromPubkeyHash(operatorIds[j]); + AVSDirectoryHarness(address(avsDirectory)).setAvsOperatorStatus( + address(serviceManager), + operatorAddress, + IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED + ); + } + } + + ( + uint32[] memory operatorSetsToCreate, + uint32[][] memory operatorSetIdsToMigrate, + address[] memory operators + ) = serviceManager.getOperatorsToMigrate(); + cheats.startPrank(serviceManagerOwner); + serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); + serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); + cheats.stopPrank(); + + bytes32[] memory registeredOperators = indexRegistry.getOperatorListAtBlockNumber(defaultQuorumNumber, uint32(block.number)); + address[] memory registeredOperatorAddresses = new address[](registeredOperators.length); + for (uint256 i = 0; i < registeredOperators.length; i++) { + registeredOperatorAddresses[i] = registryCoordinator.blsApkRegistry().pubkeyHashToOperator(registeredOperators[i]); + } + + uint32[] memory operatorSetsToUnregister = new uint32[](1); + operatorSetsToUnregister[0] = defaultQuorumNumber; + + address operatorToDeregister = operators[0]; + + bool isOperatorRegistered = avsDirectory.isMember(operatorToDeregister, IAVSDirectory.OperatorSet({ + avs: address(serviceManager), + operatorSetId: defaultQuorumNumber + })); + bool isOperatorSetAVS = avsDirectory.isOperatorSetAVS(address(serviceManager)); + // sanity check if the operator was registered from the intended operator set + assertTrue(isOperatorSetAVS, "ServiceManager is not an operator set AVS"); + assertTrue(isOperatorRegistered, "Operator wasnt unregistered from op set"); + + bytes memory quorumNumbers = new bytes(1); + quorumNumbers[0] = bytes1(defaultQuorumNumber); + cheats.startPrank(operatorToDeregister); + registryCoordinator.deregisterOperator(quorumNumbers); + cheats.stopPrank(); + + isOperatorRegistered = avsDirectory.isMember(operatorToDeregister, IAVSDirectory.OperatorSet({ + avs: address(serviceManager), + operatorSetId: defaultQuorumNumber + })); + assertFalse(isOperatorRegistered, "Operator wasn't deregistered from operator set"); + } + + function test_register_afterMigration() public { + vm.prank(proxyAdmin.owner()); + proxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(avsDirectory))), + address(avsDirectoryMock) + ); + uint256 pseudoRandomNumber = uint256(keccak256("pseudoRandomNumber")); + _registerRandomOperators(pseudoRandomNumber); + + vm.prank(proxyAdmin.owner()); + proxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(avsDirectory))), + address(avsDirectoryHarness) + ); + + uint256 quorumCount = registryCoordinator.quorumCount(); + for (uint256 i = 0; i < quorumCount; i++) { + uint256 operatorCount = indexRegistry.totalOperatorsForQuorum(uint8(i)); + bytes32[] memory operatorIds = + indexRegistry.getOperatorListAtBlockNumber(uint8(i), uint32(block.number)); + assertEq(operatorCount, operatorIds.length, "Operator Id length mismatch"); // sanity check + for (uint256 j = 0; j < operatorCount; j++) { + address operatorAddress = + registryCoordinator.blsApkRegistry().getOperatorFromPubkeyHash(operatorIds[j]); + AVSDirectoryHarness(address(avsDirectory)).setAvsOperatorStatus( + address(serviceManager), + operatorAddress, + IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED + ); + } + } + + ( + uint32[] memory operatorSetsToCreate, + uint32[][] memory operatorSetIdsToMigrate, + address[] memory operators + ) = serviceManager.getOperatorsToMigrate(); + cheats.startPrank(serviceManagerOwner); + serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); + serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); + cheats.stopPrank(); + + bytes32[] memory registeredOperators = indexRegistry.getOperatorListAtBlockNumber(defaultQuorumNumber, uint32(block.number)); + address[] memory registeredOperatorAddresses = new address[](registeredOperators.length); + for (uint256 i = 0; i < registeredOperators.length; i++) { + registeredOperatorAddresses[i] = registryCoordinator.blsApkRegistry().pubkeyHashToOperator(registeredOperators[i]); + } + + uint32[] memory operatorSetsToRegisterFor = new uint32[](1); + operatorSetsToRegisterFor[0] = defaultQuorumNumber; + + uint256 operatorPk = uint256(keccak256("operator to register")); + address operatorToRegister = vm.addr(operatorPk) ; + + bool isOperatorRegistered = avsDirectory.isMember(operatorToRegister, IAVSDirectory.OperatorSet({ + avs: address(serviceManager), + operatorSetId: defaultQuorumNumber + })); + bool isOperatorSetAVS = avsDirectory.isOperatorSetAVS(address(serviceManager)); + // sanity check if the operator was registered from the intended operator set + assertTrue(isOperatorSetAVS, "ServiceManager is not an operator set AVS"); + assertTrue(!isOperatorRegistered, "Operator wasnt unregistered from op set"); + + IDelegationManager.OperatorDetails memory details; + + cheats.startPrank(operatorToRegister); + delegationMock.registerAsOperator(details, "your_metadata_URI_here"); + cheats.stopPrank(); + + delegationMock.setIsOperator(operatorToRegister, true); + + bytes memory quorumNumbers = new bytes(1); + IBLSApkRegistry.PubkeyRegistrationParams memory params; + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; + quorumNumbers[0] = bytes1(defaultQuorumNumber); + bytes32 typeHash = avsDirectory.calculateOperatorSetRegistrationDigestHash( + address(serviceManager), + operatorSetsToRegisterFor, + keccak256(abi.encodePacked("operator registration salt")), + block.timestamp + 1 days + ); + (uint8 v, bytes32 r, bytes32 s) = vm.sign(operatorPk, typeHash); + operatorSignature = ISignatureUtils.SignatureWithSaltAndExpiry({ + signature: abi.encodePacked(r, s, v), + salt: keccak256(abi.encodePacked("operator registration salt")), + expiry: block.timestamp + 1 days + }); + + blsApkRegistry.setBLSPublicKey(operatorToRegister, defaultPubKey); + delegationMock.setOperatorShares(operatorToRegister, IStrategy(address(0)), 100 ether); + cheats.startPrank(operatorToRegister); + registryCoordinator.registerOperator(quorumNumbers, "", params, operatorSignature); + cheats.stopPrank(); + + isOperatorRegistered = avsDirectory.isMember(operatorToRegister, IAVSDirectory.OperatorSet({ + avs: address(serviceManager), + operatorSetId: defaultQuorumNumber + })); + assertTrue(isOperatorRegistered, "Operator wasn't deregistered from operator set"); + } + + } diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index c262b0da..6ae55d59 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -197,7 +197,7 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina function test_updateSocket_revert_notRegistered() public { cheats.prank(defaultOperator); - cheats.expectRevert("RegistryCoordinator.updateSocket: operator is not registered"); + cheats.expectRevert("RegistryCoordinator.updateSocket: not registered"); registryCoordinator.updateSocket("localhost:32004"); } @@ -268,7 +268,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni bytes memory emptyQuorumNumbers = new bytes(0); ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; - cheats.expectRevert("RegistryCoordinator._registerOperator: bitmap cannot be 0"); + cheats.expectRevert("RegistryCoordinator._registerOperator: bitmap empty"); cheats.prank(defaultOperator); registryCoordinator.registerOperator(emptyQuorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); } @@ -482,7 +482,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni _setOperatorWeight(operatorToRegister, defaultQuorumNumber, defaultStake); cheats.prank(operatorToRegister); - cheats.expectRevert("RegistryCoordinator.registerOperator: operator count exceeds maximum"); + cheats.expectRevert("RegistryCoordinator.registerOperator: operator exceeds max"); registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); } @@ -512,7 +512,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni bytes memory emptyQuorumNumbers = new bytes(0); ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; - cheats.expectRevert("RegistryCoordinator._registerOperator: bitmap cannot be 0"); + cheats.expectRevert("RegistryCoordinator._registerOperator: bitmap empty"); registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, emptyQuorumNumbers, defaultSocket, emptySig); } @@ -600,7 +600,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); - cheats.expectRevert("RegistryCoordinator._deregisterOperator: operator is not registered"); + cheats.expectRevert("RegistryCoordinator._deregisterOperator: not registered"); cheats.prank(defaultOperator); registryCoordinator.deregisterOperator(quorumNumbers); } @@ -616,7 +616,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist quorumNumbers[0] = bytes1(defaultQuorumNumber + 1); quorumNumbers[1] = bytes1(defaultQuorumNumber + 2); - cheats.expectRevert("RegistryCoordinator._deregisterOperator: operator is not registered for specified quorums"); + cheats.expectRevert("RegistryCoordinator._deregisterOperator: not registered for quorum"); cheats.prank(defaultOperator); registryCoordinator.deregisterOperator(quorumNumbers); } @@ -962,7 +962,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist function test_deregisterOperatorExternal_revert_notRegistered() public { bytes memory emptyQuorumNumbers = new bytes(0); - cheats.expectRevert("RegistryCoordinator._deregisterOperator: operator is not registered"); + cheats.expectRevert("RegistryCoordinator._deregisterOperator: not registered"); registryCoordinator._deregisterOperatorExternal(defaultOperator, emptyQuorumNumbers); } @@ -984,7 +984,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist incorrectQuorum[0] = bytes1(defaultQuorumNumber + 1); cheats.roll(deregistrationBlockNumber); - cheats.expectRevert("RegistryCoordinator._deregisterOperator: operator is not registered for specified quorums"); + cheats.expectRevert("RegistryCoordinator._deregisterOperator: not registered for quorum"); registryCoordinator._deregisterOperatorExternal(defaultOperator, incorrectQuorum); } @@ -1213,7 +1213,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.prank(defaultOperator); registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); - cheats.expectRevert("RegistryCoordinator.onlyEjector: caller is not the ejector"); + cheats.expectRevert("RegistryCoordinator.onlyEjector: not ejector"); cheats.prank(defaultOperator); registryCoordinator.ejectOperator(defaultOperator, quorumNumbers); } @@ -1221,7 +1221,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist function test_getQuorumBitmapIndicesAtBlockNumber_revert_notRegistered() public { uint32 blockNumber; bytes32[] memory operatorIds = new bytes32[](1); - cheats.expectRevert("RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number"); + cheats.expectRevert("RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId"); registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); } @@ -1242,7 +1242,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist operatorIds[0] = defaultOperatorId; uint32[] memory returnArray; - cheats.expectRevert("RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number"); + cheats.expectRevert("RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId"); registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); blockNumber = registrationBlockNumber; @@ -1264,7 +1264,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist operatorIds[0] = defaultOperatorId; uint32[] memory returnArray; - cheats.expectRevert("RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number"); + cheats.expectRevert("RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId"); registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); blockNumber = registrationBlockNumber; @@ -1556,7 +1556,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ISignatureUtils.SignatureWithSaltAndExpiry memory signatureWithSaltAndExpiry = _signOperatorChurnApproval(operatorToRegister, operatorToRegisterId, operatorKickParams, defaultSalt, block.timestamp - 1); cheats.prank(operatorToRegister); - cheats.expectRevert("RegistryCoordinator._verifyChurnApproverSignature: churnApprover signature expired"); + cheats.expectRevert("RegistryCoordinator._verifyChurnApproverSignature: signature expired"); registryCoordinator.registerOperatorWithChurn( quorumNumbers, defaultSocket, @@ -1738,7 +1738,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit operatorsToUpdate[0] = operatorArray; // note: there is not an explicit check for duplicates, as checking for explicit ordering covers this - cheats.expectRevert(bytes("RegistryCoordinator.updateOperatorsForQuorum: operators array must be sorted in ascending address order")); + cheats.expectRevert(bytes("RegistryCoordinator.updateOperatorsForQuorum: operators must be sorted")); registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); } @@ -1764,7 +1764,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit operatorArray[1] = defaultOperator; operatorsToUpdate[0] = operatorArray; - cheats.expectRevert(bytes("RegistryCoordinator.updateOperatorsForQuorum: operators array must be sorted in ascending address order")); + cheats.expectRevert(bytes("RegistryCoordinator.updateOperatorsForQuorum: operators must be sorted")); registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); } diff --git a/test/unit/StakeRegistryUnit.t.sol b/test/unit/StakeRegistryUnit.t.sol index 56f244cf..71348e1b 100644 --- a/test/unit/StakeRegistryUnit.t.sol +++ b/test/unit/StakeRegistryUnit.t.sol @@ -48,7 +48,8 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { serviceManager, stakeRegistry, IBLSApkRegistry(blsApkRegistry), - IIndexRegistry(indexRegistry) + IIndexRegistry(indexRegistry), + IAVSDirectory(avsDirectory) ); stakeRegistryImplementation = new StakeRegistryHarness( diff --git a/test/utils/MockAVSDeployer.sol b/test/utils/MockAVSDeployer.sol index 7ce4d5c4..b06364a8 100644 --- a/test/utils/MockAVSDeployer.sol +++ b/test/utils/MockAVSDeployer.sol @@ -280,7 +280,7 @@ contract MockAVSDeployer is Test { } registryCoordinatorImplementation = new RegistryCoordinatorHarness( - serviceManager, stakeRegistry, blsApkRegistry, indexRegistry + serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, avsDirectory ); { delete operatorSetParams; From e0a79f11076ae2e2beb0866030cc916ca4ff066a Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:05:38 -0400 Subject: [PATCH 17/52] feat(op sets): upgrade and migrate script (#303) * feat: upgrade and test pre prod upgrade and migration * fix: add param introduced in merge --- foundry.toml | 4 + script/OperatorSetUpgrade.s.sol | 255 ++++++++++++++++++ script/utils/UpgradeLib.sol | 40 +++ .../utils/testdata/17000/core_testdata.json | 23 ++ .../testdata/17000/middlware_testdata.json | 18 ++ 5 files changed, 340 insertions(+) create mode 100644 script/OperatorSetUpgrade.s.sol create mode 100644 script/utils/UpgradeLib.sol create mode 100644 script/utils/testdata/17000/core_testdata.json create mode 100644 script/utils/testdata/17000/middlware_testdata.json diff --git a/foundry.toml b/foundry.toml index 4e13d2e8..fd0aac0f 100644 --- a/foundry.toml +++ b/foundry.toml @@ -17,6 +17,10 @@ via_ir = false # Override the Solidity version (this overrides `auto_detect_solc`) solc_version = '0.8.12' +[etherscan] +mainnet = { key = "${ETHERSCAN_API_KEY}" } +holesky = { key = "${ETHERSCAN_API_KEY}" } + [fmt] bracket_spacing = false int_types = "long" diff --git a/script/OperatorSetUpgrade.s.sol b/script/OperatorSetUpgrade.s.sol new file mode 100644 index 00000000..39158e0a --- /dev/null +++ b/script/OperatorSetUpgrade.s.sol @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import {Script, console2} from "forge-std/Script.sol"; +import {OperatorSetUpgradeLib} from "./utils/UpgradeLib.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {ServiceManagerMock, IServiceManager} from "../test/mocks/ServiceManagerMock.sol"; +import {StakeRegistry, IStakeRegistry} from "../src/StakeRegistry.sol"; +import {RegistryCoordinator, IRegistryCoordinator} from "../src/RegistryCoordinator.sol"; +import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; +import {IBLSApkRegistry} from "../src/interfaces/IBLSApkRegistry.sol"; +import {IIndexRegistry} from "../src/interfaces/IIndexRegistry.sol"; +import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +interface IServiceManagerMigration { + function getOperatorsToMigrate() + external + view + returns ( + uint32[] memory operatorSetIdsToCreate, + uint32[][] memory operatorSetIds, + address[] memory allOperators + ); + function migrateAndCreateOperatorSetIds(uint32[] memory operatorSetsToCreate) external; + function migrateToOperatorSets(uint32[][] memory operatorSetIds, address[] memory operators) external; + function finalizeMigration() external; + function migrationFinalized() external returns (bool); +} + + +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; + +contract OperatorSetUpgradeScript is Script { + using stdJson for string; + + address private constant DEFAULT_FORGE_SENDER = 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38; + + address public proxyAdminOwner; + address public serviceManagerOwner; + address public serviceManager; + address public stakeRegistry; + address public registryCoordinator; + address public avsDirectory; + address public rewardsCoordinator; + address public delegationManager; + address public blsApkRegistry; + address public indexRegistry; + + function setUp() public { + vm.label(DEFAULT_FORGE_SENDER, "DEFAULT FORGE SENDER"); + + // Note: Ensure that the following environment variables are set before running the script: + // - PROXY_ADMIN_OWNER: The private key of the proxy admin owner. + // - SERVICE_MANAGER_OWNER: The private key of the service manager owner. + // These environment variables are crucial for the proper execution of the upgrade and migration processes. + /// TODO: improve DEVX of gnosis safe. Would like to do an tx service integration for SafeAPI + proxyAdminOwner = vm.rememberKey(vm.envUint("PROXY_ADMIN_OWNER")); + serviceManagerOwner = vm.rememberKey(vm.envUint("PROXY_ADMIN_OWNER")); + + string memory middlewareJson = vm.readFile(vm.envString("MIDDLEWARE_JSON_PATH")); + string memory coreJson = vm.readFile(vm.envString("CORE_JSON_PATH")); + + /* + * Note: Ensure that the structure of the configuration JSON files matches the structure + * of `core_testdata.json`. If you rename any of the files, you will need to update the + * corresponding key values in the code. + */ + loadAddressesSetup(middlewareJson, coreJson); + labelAndLogAddressesSetup(); + } + + function run() public { + vm.startBroadcast(proxyAdminOwner); + + _upgrade(); + + vm.stopBroadcast(); + + vm.startBroadcast(serviceManagerOwner); + + _migrateToOperatorSets(); + + vm.stopBroadcast(); + } + // forge script script/OperatorSetUpgrade.s.sol --sig "simulateUpgrade()" -vvv + function simulateUpgrade() public { + + address proxyAdmin = OperatorSetUpgradeLib.getAdmin(serviceManager); + proxyAdminOwner = Ownable(proxyAdmin).owner(); + vm.startPrank(proxyAdminOwner); + + _upgrade(); + + vm.stopPrank(); + + } + + // forge script script/OperatorSetUpgrade.s.sol --sig "simulateMigrate()" -vvv + function simulateMigrate() public { + _upgradeAvsDirectory(); /// Workaround since this isn't on pre-prod yet + + serviceManagerOwner = Ownable(serviceManager).owner(); + vm.startPrank(serviceManagerOwner); + + _migrateToOperatorSets(); + + vm.stopPrank(); + } + + // forge script script/OperatorSetUpgrade.s.sol --sig "simulateUpgradeAndMigrate()" -vvv + function simulateUpgradeAndMigrate() public { + _upgradeAvsDirectory(); /// Workaround since this isn't on pre-prod yet + + address proxyAdmin = OperatorSetUpgradeLib.getAdmin(serviceManager); + proxyAdminOwner = Ownable(proxyAdmin).owner(); + + console2.log(proxyAdminOwner, "Pranker"); + vm.startPrank(proxyAdminOwner); + + _upgrade(); + + vm.stopPrank(); + + serviceManagerOwner = Ownable(serviceManager).owner(); + vm.startPrank(serviceManagerOwner); + + _migrateToOperatorSets(); + + vm.stopPrank(); + + // Assert that serviceManager is an operatorSetAVS + require( + IAVSDirectory(avsDirectory).isOperatorSetAVS(serviceManager), + "simulateUpgradeAndMigrate: serviceManager is not an operatorSetAVS" + ); + + // Assert that the migration is finalized + require( + IServiceManagerMigration(serviceManager).migrationFinalized(), + "simulateUpgradeAndMigrate: Migration is not finalized" + ); + } + + function _upgradeAvsDirectory() internal { + address proxyAdmin = OperatorSetUpgradeLib.getAdmin(avsDirectory); + address avsDirectoryOwner = Ownable(proxyAdmin).owner(); + AVSDirectory avsDirectoryImpl = new AVSDirectory(IDelegationManager(delegationManager)); + + vm.startPrank(avsDirectoryOwner); + OperatorSetUpgradeLib.upgrade(avsDirectory, address(avsDirectoryImpl)); + vm.stopPrank(); + } + + function labelAndLogAddressesSetup() internal virtual { + vm.label(proxyAdminOwner, "Proxy Admin Owner Account"); + vm.label(serviceManagerOwner, "Service Manager Owner Account"); + vm.label(serviceManager, "Service Manager Proxy"); + vm.label(stakeRegistry, "Stake Registry Proxy"); + vm.label(registryCoordinator, "Registry Coordinator Proxy"); + vm.label(indexRegistry, "Index Registry Proxy"); + vm.label(blsApkRegistry, "BLS APK Registry Proxy"); + vm.label(avsDirectory, "AVS Directory Proxy"); + vm.label(delegationManager, "Delegation Manager Proxy"); + vm.label(rewardsCoordinator, "Rewards Coordinator Proxy"); + + console2.log("Proxy Admin Owner Account", proxyAdminOwner); + console2.log("ServiceManager Owner Account", serviceManagerOwner); + console2.log("Service Manager:", serviceManager); + console2.log("Stake Registry:", stakeRegistry); + console2.log("Registry Coordinator:", registryCoordinator); + console2.log("Index Registry:", indexRegistry); + console2.log("BLS APK Registry:", blsApkRegistry); + console2.log("AVS Directory:", avsDirectory); + console2.log("Delegation Manager:", delegationManager); + console2.log("Rewards Coordinator:", rewardsCoordinator); + + address oldServiceManagerImpl = OperatorSetUpgradeLib.getImplementation(serviceManager); + address oldStakeRegistryImpl = OperatorSetUpgradeLib.getImplementation(stakeRegistry); + address oldRegistryCoordinatorImpl = OperatorSetUpgradeLib.getImplementation(registryCoordinator); + address oldAvsDirectoryImpl = OperatorSetUpgradeLib.getImplementation(avsDirectory); + address oldDelegationManagerImpl = OperatorSetUpgradeLib.getImplementation(delegationManager); + + vm.label(oldServiceManagerImpl, "Old Service Manager Implementation"); + vm.label(oldStakeRegistryImpl, "Old Stake Registry Implementation"); + vm.label(oldRegistryCoordinatorImpl, "Old Registry Coordinator Implementation"); + vm.label(oldAvsDirectoryImpl, "Old AVS Directory Implementation"); + vm.label(oldDelegationManagerImpl, "Old Delegation Manager Implementation"); + + console2.log("Old Service Manager Implementation:", oldServiceManagerImpl); + console2.log("Old Stake Registry Implementation:", oldStakeRegistryImpl); + console2.log("Old Registry Coordinator Implementation:", oldRegistryCoordinatorImpl); + console2.log("Old AVS Directory Implementation:", oldAvsDirectoryImpl); + console2.log("Old Delegation Manager Implementation:", oldDelegationManagerImpl); + } + + function loadAddressesSetup(string memory middlewareJson, string memory coreJson) internal virtual { + serviceManager = middlewareJson.readAddress(".addresses.eigenDAServiceManager"); + stakeRegistry = middlewareJson.readAddress(".addresses.stakeRegistry"); + registryCoordinator = middlewareJson.readAddress(".addresses.registryCoordinator"); + blsApkRegistry = middlewareJson.readAddress(".addresses.blsApkRegistry"); + indexRegistry = middlewareJson.readAddress(".addresses.indexRegistry"); + + avsDirectory = coreJson.readAddress(".addresses.avsDirectory"); + delegationManager = coreJson.readAddress(".addresses.delegationManager"); + rewardsCoordinator = coreJson.readAddress(".addresses.rewardsCoordinator"); + } + + function _upgrade() internal virtual { + address newServiceManagerImpl = address(new ServiceManagerMock( + IAVSDirectory(avsDirectory), + IRewardsCoordinator(rewardsCoordinator), + IRegistryCoordinator(registryCoordinator), + IStakeRegistry(stakeRegistry) + )); + address newRegistryCoordinatorImpl = address(new RegistryCoordinator( + IServiceManager(serviceManager), + IStakeRegistry(stakeRegistry), + IBLSApkRegistry(blsApkRegistry), + IIndexRegistry(indexRegistry), + IAVSDirectory(avsDirectory) + )); + address newStakeRegistryImpl = address(new StakeRegistry( + IRegistryCoordinator(registryCoordinator), + IDelegationManager(delegationManager), + IAVSDirectory(avsDirectory), + IServiceManager(serviceManager) + )); + + console2.log("New Service Manager Implementation:", newServiceManagerImpl); + console2.log("New Registry Coordinator Implementation:", newRegistryCoordinatorImpl); + console2.log("New Stake Registry Implementation:", newStakeRegistryImpl); + + vm.label(newServiceManagerImpl, "New Service Manager Implementation"); + vm.label(newRegistryCoordinatorImpl, "New Registry Coordinator Implementation"); + vm.label(newStakeRegistryImpl, "New Stake Registry Implementation"); + + OperatorSetUpgradeLib.upgrade(serviceManager, newServiceManagerImpl); + OperatorSetUpgradeLib.upgrade(registryCoordinator, newRegistryCoordinatorImpl); + OperatorSetUpgradeLib.upgrade(stakeRegistry, newStakeRegistryImpl); + } + + function _migrateToOperatorSets() internal virtual { + IServiceManagerMigration serviceManager = IServiceManagerMigration(serviceManager); + ( + uint32[] memory operatorSetsToCreate, + uint32[][] memory operatorSetIdsToMigrate, + address[] memory operators + ) = serviceManager.getOperatorsToMigrate(); + + serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); + serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); + serviceManager.finalizeMigration(); + } +} \ No newline at end of file diff --git a/script/utils/UpgradeLib.sol b/script/utils/UpgradeLib.sol new file mode 100644 index 00000000..0b136c8e --- /dev/null +++ b/script/utils/UpgradeLib.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; +// Deploy L2AVS proxy + +import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; + +import {Vm} from "forge-std/Vm.sol"; +import {stdJson} from "forge-std/StdJson.sol"; + +library OperatorSetUpgradeLib { + using stdJson for string; + Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + bytes32 internal constant IMPLEMENTATION_SLOT = + 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + + bytes32 internal constant ADMIN_SLOT = + 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + + + function upgrade(address proxy, address implementation, bytes memory data) internal { + ProxyAdmin admin = ProxyAdmin(getAdmin(proxy)); + admin.upgradeAndCall(TransparentUpgradeableProxy(payable(proxy)), implementation, data); + } + + function upgrade(address proxy, address implementation) internal { + ProxyAdmin admin = ProxyAdmin(getAdmin(proxy)); + admin.upgrade(TransparentUpgradeableProxy(payable(proxy)), implementation); + } + + function getAdmin(address proxy) internal view returns (address){ + bytes32 value = vm.load(proxy, ADMIN_SLOT); + return address(uint160(uint256(value))); + } + + function getImplementation(address proxy) internal view returns (address) { + bytes32 value = vm.load(proxy, IMPLEMENTATION_SLOT); + return address(uint160(uint256(value))); + } +} \ No newline at end of file diff --git a/script/utils/testdata/17000/core_testdata.json b/script/utils/testdata/17000/core_testdata.json new file mode 100644 index 00000000..2ebdc8fb --- /dev/null +++ b/script/utils/testdata/17000/core_testdata.json @@ -0,0 +1,23 @@ +{ + "addresses":{ + "avsDirectory": "0x141d6995556135D4997b2ff72EB443Be300353bC", + "avsDirectoryImplementation": "0x357978adC03375BD6a3605DE055fABb84695d79A", + "baseStrategyImplementation": "0x62450517EfA1CE60d79801daf8f95973865e8D40", + "beaconOracle": "0x4C116BB629bff7A8373c2378bBd919f8349B8f25", + "delayedWithdrawalRouter": "0xC4BC46a87A67a531eCF7f74338E1FA79533334Fa", + "delayedWithdrawalRouterImplementation": "0x0011FA2c512063C495f77296Af8d195F33A8Dd38", + "delegationManager": "0x75dfE5B44C2E530568001400D3f704bC8AE350CC", + "delegationManagerImplementation": "0x56E88cb4f0136fC27D95499dE4BE2acf47946Fa1", + "eigenLayerPauserReg": "0x9Ab2FEAf0465f0eD51Fc2b663eF228B418c9Dad1", + "eigenLayerProxyAdmin": "0x1BEF05C7303d44e0E2FCD2A19d993eDEd4c51b5B", + "eigenPodBeacon": "0x92Cc4a800A1513E85C481dDDf3A06C6921211eaC", + "eigenPodImplementation": "0x2D6c7f9862BD80Cf0d9d93FC6b513D69E7Db7869", + "eigenPodManager": "0xB8d8952f572e67B11e43bC21250967772fa883Ff", + "eigenPodManagerImplementation": "0xc5B857A92245f64e9D90cCc5b096Db82eB77eB5c", + "emptyContract": "0x9690d52B1Ce155DB2ec5eCbF5a262ccCc7B3A6D2", + "rewardsCoordinator": "0xb22Ef643e1E067c994019A4C19e403253C05c2B0", + "rewardsCoordinatorImplementation": "0x76d4D84c90a2AFf213F7D859d2a288685A1a2Ede", + "slasher": "0x12699471dF8dca329C76D72823B1b79d55709384", + "slasherImplementation": "0x9460fCe11E1e0365419fa860599903B4E5097cf0" + } +} \ No newline at end of file diff --git a/script/utils/testdata/17000/middlware_testdata.json b/script/utils/testdata/17000/middlware_testdata.json new file mode 100644 index 00000000..6c25eeee --- /dev/null +++ b/script/utils/testdata/17000/middlware_testdata.json @@ -0,0 +1,18 @@ +{ + "addresses":{ + "blsApkRegistry": "0xAd7f9e558170a149Ca8E90f41Ab2444A5d3bd6aD", + "blsApkRegistryImplementation": "0x482a96D5879e32347d8df125f038D7eC8Ab358dd", + "eigenDAProxyAdmin": "0x9Fd7E279f5bD692Dc04792151E14Ad814FC60eC1", + "eigenDAServiceManager": "0x54A03db2784E3D0aCC08344D05385d0b62d4F432", + "eigenDAServiceManagerImplementation": "0xEB11a0f320E39d3371Fec4Bf5C76944DfBA8ee10", + "indexRegistry": "0x8cE5F2a53cBd29710eb94A04e40C07A4DdF15d10", + "indexRegistryImplementation": "0x1D4d6054BD11A5711ad7c5d3E376C987a603e17C", + "mockRollup": "0x0433646AdCeE95fbF89b3BFDb8157e75c19b6C2e", + "operatorStateRetriever": "0x17cA8C41a59466710443143b2ECF08CaA35d80ad", + "registryCoordinator": "0x2c61EA360D6500b58E7f481541A36B443Bc858c6", + "registryCoordinatorImplementation": "0x6f21A84E7f185cCBA248B436e3b583E609d1dE1D", + "serviceManagerRouter": "0xDb028E067fe81e9f406C2DE382Ba82e9cD7cBD03", + "stakeRegistry": "0x53668EBf2e28180e38B122c641BC51Ca81088871", + "stakeRegistryImplementation": "0x854dc9e5d011B060bf77B1a492302C349f2f00b5" + } +} \ No newline at end of file From eb0d6ad8f6ea25894fcdf8dd25230afe4cfcd117 Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:05:56 -0400 Subject: [PATCH 18/52] chore: bump slashing core dependency (#312) * chore: bump to slashing branch * chore: bump compiler version * fix: dep interface changes * fix: compiler errors from interface changes and type changes * fix: compiler errors * chore: bump dependencies * chore: bump core dependency and resolve issues * chore: bump core dependency and fix compiler errors * feat: integrate AllocationManager * feat: add a slashing permission to the service manager * chore: remove unneeded casting * feat: implement a slasher permission and forward call to AllocationManager * feat: add simiple slasher starting point * chore: bump slashing magnitudes * chore: bump core slashing-magnitudes branch --- foundry.toml | 2 +- lib/eigenlayer-contracts | 2 +- script/OperatorSetUpgrade.s.sol | 7 +- src/BLSSignatureChecker.sol | 8 +- src/RegistryCoordinator.sol | 6 +- src/ServiceManagerBase.sol | 53 +- src/ServiceManagerBaseStorage.sol | 13 +- src/StakeRegistry.sol | 7 +- src/interfaces/IServiceManager.sol | 6 +- src/libraries/SignatureCheckerLib.sol | 9 +- src/slashers/SimpleSlasher.sol | 33 ++ src/slashers/SlasherStorage.sol | 8 + src/unaudited/ECDSAServiceManagerBase.sol | 6 +- src/unaudited/ECDSAStakeRegistry.sol | 10 +- test/harnesses/AVSDirectoryHarness.sol | 4 +- test/integration/CoreRegistration.t.sol | 30 +- test/integration/IntegrationBase.t.sol | 10 +- test/integration/IntegrationChecks.t.sol | 2 +- test/integration/IntegrationDeployer.t.sol | 39 +- test/integration/User.t.sol | 17 +- ...ll_Register_CoreBalanceChange_Update.t.sol | 4 +- test/mocks/AVSDirectoryMock.sol | 357 ++++++------ test/mocks/AllocationManagerMock.sol | 83 +++ test/mocks/DelegationMock.sol | 506 +++++++++++------- test/mocks/ECDSAServiceManagerMock.sol | 5 + test/mocks/EigenPodManagerMock.sol | 80 +++ test/mocks/RewardsCoordinatorMock.sol | 165 +++--- test/mocks/ServiceManagerMock.sol | 16 +- test/unit/ECDSAServiceManager.t.sol | 17 +- test/unit/RegistryCoordinatorMigration.t.sol | 34 +- test/unit/ServiceManagerBase.t.sol | 36 +- test/unit/ServiceManagerMigration.t.sol | 25 +- test/unit/ServiceManagerRouter.t.sol | 3 +- test/utils/MockAVSDeployer.sol | 51 +- 34 files changed, 1032 insertions(+), 622 deletions(-) create mode 100644 src/slashers/SimpleSlasher.sol create mode 100644 src/slashers/SlasherStorage.sol create mode 100644 test/mocks/AllocationManagerMock.sol create mode 100644 test/mocks/EigenPodManagerMock.sol diff --git a/foundry.toml b/foundry.toml index fd0aac0f..a4b33112 100644 --- a/foundry.toml +++ b/foundry.toml @@ -15,7 +15,7 @@ optimizer_runs = 200 # Whether or not to use the Yul intermediate representation compilation pipeline via_ir = false # Override the Solidity version (this overrides `auto_detect_solc`) -solc_version = '0.8.12' +solc_version = '0.8.27' [etherscan] mainnet = { key = "${ETHERSCAN_API_KEY}" } diff --git a/lib/eigenlayer-contracts b/lib/eigenlayer-contracts index d8a8341c..d98c5a7d 160000 --- a/lib/eigenlayer-contracts +++ b/lib/eigenlayer-contracts @@ -1 +1 @@ -Subproject commit d8a8341c5d5c960e6da7c08a845f2584da579cf7 +Subproject commit d98c5a7df7634e25073b9a508be1a6606d7caf0c diff --git a/script/OperatorSetUpgrade.s.sol b/script/OperatorSetUpgrade.s.sol index 39158e0a..32cd80fe 100644 --- a/script/OperatorSetUpgrade.s.sol +++ b/script/OperatorSetUpgrade.s.sol @@ -12,6 +12,7 @@ import {IBLSApkRegistry} from "../src/interfaces/IBLSApkRegistry.sol"; import {IIndexRegistry} from "../src/interfaces/IIndexRegistry.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; interface IServiceManagerMigration { function getOperatorsToMigrate() @@ -46,6 +47,7 @@ contract OperatorSetUpgradeScript is Script { address public delegationManager; address public blsApkRegistry; address public indexRegistry; + address public allocationManager; function setUp() public { vm.label(DEFAULT_FORGE_SENDER, "DEFAULT FORGE SENDER"); @@ -145,7 +147,7 @@ contract OperatorSetUpgradeScript is Script { function _upgradeAvsDirectory() internal { address proxyAdmin = OperatorSetUpgradeLib.getAdmin(avsDirectory); address avsDirectoryOwner = Ownable(proxyAdmin).owner(); - AVSDirectory avsDirectoryImpl = new AVSDirectory(IDelegationManager(delegationManager)); + AVSDirectory avsDirectoryImpl = new AVSDirectory(IDelegationManager(delegationManager), 0); // TODO: config vm.startPrank(avsDirectoryOwner); OperatorSetUpgradeLib.upgrade(avsDirectory, address(avsDirectoryImpl)); @@ -211,7 +213,8 @@ contract OperatorSetUpgradeScript is Script { IAVSDirectory(avsDirectory), IRewardsCoordinator(rewardsCoordinator), IRegistryCoordinator(registryCoordinator), - IStakeRegistry(stakeRegistry) + IStakeRegistry(stakeRegistry), + IAllocationManager(allocationManager) )); address newRegistryCoordinatorImpl = address(new RegistryCoordinator( IServiceManager(serviceManager), diff --git a/src/BLSSignatureChecker.sol b/src/BLSSignatureChecker.sol index 5392289c..b3a66ae8 100644 --- a/src/BLSSignatureChecker.sol +++ b/src/BLSSignatureChecker.sol @@ -193,9 +193,11 @@ contract BLSSignatureChecker is IBLSSignatureChecker { */ { bool _staleStakesForbidden = staleStakesForbidden; - uint256 withdrawalDelayBlocks = _staleStakesForbidden - ? delegation.minWithdrawalDelayBlocks() - : 0; + /// TODO: FIX + uint256 withdrawalDelayBlocks = 0; + // uint256 withdrawalDelayBlocks = _staleStakesForbidden + // ? delegation.minWithdrawalDelayBlocks() + // : 0; for (uint256 i = 0; i < quorumNumbers.length; i++) { // If we're disallowing stale stake updates, check that each quorum's last update block diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 818f0541..c71e7278 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.12; import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; -import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IAVSDirectory, OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {ISocketUpdater} from "./interfaces/ISocketUpdater.sol"; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; @@ -676,7 +676,7 @@ contract RegistryCoordinator is for (uint256 i = 0; i < quorumBytes.length; i++) { /// We need to track forceDeregistrations so we don't pass an id that was already deregistered on the AVSDirectory /// but hasnt yet been recorded in the middleware contracts - if (!avsDirectory.isMember(operator, IAVSDirectory.OperatorSet(address(serviceManager), uint8(quorumBytes[i])))){ + if (!avsDirectory.isMember(operator, OperatorSet(address(serviceManager), uint8(quorumBytes[i])))){ forceDeregistrationCount++; } operatorSetIds[i] = uint8(quorumBytes[i]); @@ -687,7 +687,7 @@ contract RegistryCoordinator is uint32[] memory filteredOperatorSetIds = new uint32[](operatorSetIds.length - forceDeregistrationCount); uint256 offset; for (uint256 i; i < operatorSetIds.length; i++){ - if (avsDirectory.isMember(operator, IAVSDirectory.OperatorSet(address(serviceManager), operatorSetIds[i]))){ + if (avsDirectory.isMember(operator, OperatorSet(address(serviceManager), operatorSetIds[i]))){ filteredOperatorSetIds[i] = operatorSetIds[i+offset]; } else { offset++; diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index 2fbacea2..47ac07f1 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -6,6 +6,7 @@ import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISi import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {ServiceManagerBaseStorage} from "./ServiceManagerBaseStorage.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; @@ -38,11 +39,10 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _; } - function _checkRewardsInitiator() internal view { - require( - msg.sender == rewardsInitiator, - "ServiceManagerBase.onlyRewardsInitiator: caller is not the rewards initiator" - ); + /// @notice only slasher can call functions with this modifier + modifier onlySlasher() { + _checkSlasher(); + _; } /// @notice Sets the (immutable) `_registryCoordinator` address @@ -50,13 +50,15 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { IAVSDirectory __avsDirectory, IRewardsCoordinator __rewardsCoordinator, IRegistryCoordinator __registryCoordinator, - IStakeRegistry __stakeRegistry + IStakeRegistry __stakeRegistry, + IAllocationManager __allocationManager ) ServiceManagerBaseStorage( __avsDirectory, __rewardsCoordinator, __registryCoordinator, - __stakeRegistry + __stakeRegistry, + __allocationManager ) { _disableInitializers(); @@ -64,10 +66,12 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { function __ServiceManagerBase_init( address initialOwner, - address _rewardsInitiator + address _rewardsInitiator, + address _slasher ) internal virtual onlyInitializing { _transferOwnership(initialOwner); _setRewardsInitiator(_rewardsInitiator); + _setSlasher(_slasher); } /** @@ -79,6 +83,10 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _avsDirectory.updateAVSMetadataURI(_metadataURI); } + function slashOperator(IAllocationManager.SlashingParams memory params) external onlySlasher { + _allocationManager.slashOperator(params); + } + /** * @notice Creates a new rewards submission to the EigenLayer RewardsCoordinator contract, to be split amongst the * set of stakers delegated to operators who are registered to this `avs` @@ -168,6 +176,15 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _setRewardsInitiator(newRewardsInitiator); } + /** + * @notice Sets the slasher address + * @param newSlasher The new slasher address + * @dev only callable by the owner + */ + function setSlasher(address newSlasher) external onlyOwner { + _setSlasher(newSlasher); + } + /** * @notice Migrates the AVS to use operator sets and creates new operator set IDs. * @param operatorSetsToCreate An array of operator set IDs to create. @@ -325,6 +342,11 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { rewardsInitiator = newRewardsInitiator; } + function _setSlasher(address newSlasher) internal { + emit SlasherUpdated(slasher, newSlasher); + slasher = newSlasher; + } + /** * @notice Returns the list of strategies that the AVS supports for restaking * @dev This function is intended to be called off-chain @@ -402,4 +424,19 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { function avsDirectory() external view override returns (address) { return address(_avsDirectory); } + + function _checkRewardsInitiator() internal view { + require( + msg.sender == rewardsInitiator, + "ServiceManagerBase.onlyRewardsInitiator: caller is not the rewards initiator" + ); + } + + + function _checkSlasher() internal view { + require( + msg.sender == slasher, + "ServiceManagerBase.onlySlasher: caller is not the slasher" + ); + } } diff --git a/src/ServiceManagerBaseStorage.sol b/src/ServiceManagerBaseStorage.sol index 4d0c1fec..71d54d98 100644 --- a/src/ServiceManagerBaseStorage.sol +++ b/src/ServiceManagerBaseStorage.sol @@ -9,6 +9,7 @@ import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; /** * @title Storage variables for the `ServiceManagerBase` contract. @@ -25,6 +26,7 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab IRewardsCoordinator internal immutable _rewardsCoordinator; IRegistryCoordinator internal immutable _registryCoordinator; IStakeRegistry internal immutable _stakeRegistry; + IAllocationManager internal immutable _allocationManager; /** * @@ -35,21 +37,26 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab /// @notice The address of the entity that can initiate rewards address public rewardsInitiator; + /// @notice The address of the slasher account + address public slasher; + bool public migrationFinalized; - /// @notice Sets the (immutable) `_avsDirectory`, `_rewardsCoordinator`, `_registryCoordinator`, and `_stakeRegistry` addresses + /// @notice Sets the (immutable) `_avsDirectory`, `_rewardsCoordinator`, `_registryCoordinator`, `_stakeRegistry`, and `_allocationManager` addresses constructor( IAVSDirectory __avsDirectory, IRewardsCoordinator __rewardsCoordinator, IRegistryCoordinator __registryCoordinator, - IStakeRegistry __stakeRegistry + IStakeRegistry __stakeRegistry, + IAllocationManager __allocationManager ) { _avsDirectory = __avsDirectory; _rewardsCoordinator = __rewardsCoordinator; _registryCoordinator = __registryCoordinator; _stakeRegistry = __stakeRegistry; + _allocationManager = __allocationManager; } // storage gap for upgradeability - uint256[49] private __GAP; + uint256[48] private __GAP; } diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index ca4b55fb..9d4da097 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.12; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; -import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IAVSDirectory, OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {StakeRegistryStorage, IStrategy} from "./StakeRegistryStorage.sol"; @@ -182,7 +182,7 @@ contract StakeRegistry is StakeRegistryStorage { // Query the AVSDirectory to check if the operator is directly unregistered operatorRegistered = avsDirectory.isMember( operator, - IAVSDirectory.OperatorSet(address(serviceManager), operatorSetId) + OperatorSet(address(serviceManager), operatorSetId) ); if (!hasMinimumStake || (isOperatorSetAVS && !operatorRegistered)) { @@ -491,7 +491,8 @@ contract StakeRegistry is StakeRegistryStorage { uint256 stratsLength = strategyParamsLength(quorumNumber); StrategyParams memory strategyAndMultiplier; - uint256[] memory strategyShares = delegation.getOperatorShares(operator, strategiesPerQuorum[quorumNumber]); + uint256[] memory strategyShares; + // = delegation.getDelegatableShares(operator, strategiesPerQuorum[quorumNumber]); for (uint256 i = 0; i < stratsLength; i++) { // accessing i^th StrategyParams struct for the quorumNumber strategyAndMultiplier = strategyParams[quorumNumber][i]; diff --git a/src/interfaces/IServiceManager.sol b/src/interfaces/IServiceManager.sol index 8807e9df..5057525e 100644 --- a/src/interfaces/IServiceManager.sol +++ b/src/interfaces/IServiceManager.sol @@ -4,6 +4,7 @@ pragma solidity >=0.5.0; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; import {IServiceManagerUI} from "./IServiceManagerUI.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; +import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; /** * @title Minimal interface for a ServiceManager-type contract that forms the single point for an AVS to push updates to EigenLayer @@ -23,7 +24,7 @@ interface IServiceManager is IServiceManagerUI { */ function createAVSRewardsSubmission(IRewardsCoordinator.RewardsSubmission[] calldata rewardsSubmissions) external; - function createOperatorSets(uint32[] memory operatorSetIds) external ; + function createOperatorSets(uint32[] memory operatorSetIds) external; /** * @notice Forwards a call to EigenLayer's AVSDirectory contract to register an operator to operator sets @@ -44,6 +45,9 @@ interface IServiceManager is IServiceManagerUI { */ function deregisterOperatorFromOperatorSets(address operator, uint32[] calldata operatorSetIds) external; + function slashOperator(IAllocationManagerTypes.SlashingParams memory params) external; + // EVENTS event RewardsInitiatorUpdated(address prevRewardsInitiator, address newRewardsInitiator); + event SlasherUpdated(address prevSlasher, address newSlasher); } diff --git a/src/libraries/SignatureCheckerLib.sol b/src/libraries/SignatureCheckerLib.sol index fa2fb137..c01fd3a7 100644 --- a/src/libraries/SignatureCheckerLib.sol +++ b/src/libraries/SignatureCheckerLib.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.12; -import {EIP1271SignatureUtils} from - "eigenlayer-contracts/src/contracts/libraries/EIP1271SignatureUtils.sol"; +import "@openzeppelin-upgrades/contracts/utils/cryptography/SignatureCheckerUpgradeable.sol"; /** * @title SignatureCheckerLib @@ -11,6 +10,8 @@ import {EIP1271SignatureUtils} from * validation logic to this external library. */ library SignatureCheckerLib { + error InvalidSignature(); + /** * @notice Validates a signature using EIP-1271 standard. * @param signer The address of the signer. @@ -22,6 +23,8 @@ library SignatureCheckerLib { bytes32 digestHash, bytes memory signature ) external view { - EIP1271SignatureUtils.checkSignature_EIP1271(signer, digestHash, signature); + if (!SignatureCheckerUpgradeable.isValidSignatureNow(signer, digestHash, signature)) { + revert InvalidSignature(); + } } } diff --git a/src/slashers/SimpleSlasher.sol b/src/slashers/SimpleSlasher.sol new file mode 100644 index 00000000..faa4f49b --- /dev/null +++ b/src/slashers/SimpleSlasher.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; +import {IServiceManager} from "../interfaces/IServiceManager.sol"; +import {SlasherStorage} from "./SlasherStorage.sol"; +import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; + +contract SimpleSlasher is Initializable, SlasherStorage { + function initialize(address _serviceManager) public initializer { + serviceManager = _serviceManager; + } + + function slashOperator( + address operator, + uint32 operatorSetId, + IStrategy[] memory strategies, + uint256 wadToSlash, + string memory description + ) external { + + IAllocationManagerTypes.SlashingParams memory params = IAllocationManagerTypes.SlashingParams({ + operator: operator, + operatorSetId: operatorSetId, + strategies: strategies, + wadToSlash: wadToSlash, + description: description + }); + + IServiceManager(serviceManager).slashOperator(params); + } +} diff --git a/src/slashers/SlasherStorage.sol b/src/slashers/SlasherStorage.sol new file mode 100644 index 00000000..1b3d61de --- /dev/null +++ b/src/slashers/SlasherStorage.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +contract SlasherStorage { + address public serviceManager; + + uint256[49] private __gap; +} \ No newline at end of file diff --git a/src/unaudited/ECDSAServiceManagerBase.sol b/src/unaudited/ECDSAServiceManagerBase.sol index 57326bea..3d30f451 100644 --- a/src/unaudited/ECDSAServiceManagerBase.sol +++ b/src/unaudited/ECDSAServiceManagerBase.sol @@ -238,8 +238,10 @@ abstract contract ECDSAServiceManagerBase is for (uint256 i; i < count; i++) { strategies[i] = quorum.strategies[i].strategy; } - uint256[] memory shares = IDelegationManager(delegationManager) - .getOperatorShares(_operator, strategies); + uint256[] memory shares; + // TODO: Fix + // = IDelegationManager(delegationManager) + // .getOperatorShares(_operator, strategies); uint256 activeCount; for (uint256 i; i < count; i++) { diff --git a/src/unaudited/ECDSAStakeRegistry.sol b/src/unaudited/ECDSAStakeRegistry.sol index ab4bdbeb..a8dff79a 100644 --- a/src/unaudited/ECDSAStakeRegistry.sol +++ b/src/unaudited/ECDSAStakeRegistry.sol @@ -248,10 +248,12 @@ contract ECDSAStakeRegistry is for (uint256 i; i < strategyParams.length; i++) { strategies[i] = strategyParams[i].strategy; } - uint256[] memory shares = DELEGATION_MANAGER.getOperatorShares( - _operator, - strategies - ); + uint256[] memory shares; + /// TODO: FIX + // = DELEGATION_MANAGER.getOperatorShares( + // _operator, + // strategies + // ); for (uint256 i; i < strategyParams.length; i++) { weight += shares[i] * strategyParams[i].multiplier; } diff --git a/test/harnesses/AVSDirectoryHarness.sol b/test/harnesses/AVSDirectoryHarness.sol index 99efedec..94598058 100644 --- a/test/harnesses/AVSDirectoryHarness.sol +++ b/test/harnesses/AVSDirectoryHarness.sol @@ -7,7 +7,7 @@ import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory // wrapper around the AVSDirectory contract that exposes internal functionality, for unit testing contract AVSDirectoryHarness is AVSDirectory { - constructor(IDelegationManager _delegation) AVSDirectory(_delegation) {} + constructor(IDelegationManager _delegation) AVSDirectory(_delegation, 0) {} // TODO: config update function setOperatorSaltIsSpent(address operator, bytes32 salt, bool isSpent) external { operatorSaltIsSpent[operator][salt] = isSpent; @@ -59,7 +59,7 @@ contract AVSDirectoryHarness is AVSDirectory { } function _calculateDigestHashExternal(bytes32 structHash) external view returns (bytes32) { - return _calculateDigestHash(structHash); + // return calculateOperatorSetRegistrationDigestHash(structHash); // TODO: Fix } function _calculateDomainSeparatorExternal() external view returns (bytes32) { diff --git a/test/integration/CoreRegistration.t.sol b/test/integration/CoreRegistration.t.sol index f6cbf571..b9784dc6 100644 --- a/test/integration/CoreRegistration.t.sol +++ b/test/integration/CoreRegistration.t.sol @@ -3,9 +3,10 @@ pragma solidity ^0.8.12; import "../utils/MockAVSDeployer.sol"; import { AVSDirectory } from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; -import { IAVSDirectory } from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import { IAVSDirectory, IAVSDirectoryTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import { IStrategyManager } from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; import { DelegationManager } from "eigenlayer-contracts/src/contracts/core/DelegationManager.sol"; -import { IDelegationManager } from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import { IDelegationManager, IDelegationManagerTypes } from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import { RewardsCoordinator } from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; import { IRewardsCoordinator } from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; @@ -26,7 +27,7 @@ contract Test_CoreRegistration is MockAVSDeployer { _deployMockEigenLayerAndAVS(); // Deploy New DelegationManager - DelegationManager delegationManagerImplementation = new DelegationManager(strategyManagerMock, slasher, eigenPodManagerMock); + DelegationManager delegationManagerImplementation = new DelegationManager(avsDirectoryMock, IStrategyManager(address(strategyManagerMock)), eigenPodManagerMock, allocationManagerMock, 0); IStrategy[] memory initializeStrategiesToSetDelayBlocks = new IStrategy[](0); uint256[] memory initializeWithdrawalDelayBlocks = new uint256[](0); delegationManager = DelegationManager( @@ -48,7 +49,7 @@ contract Test_CoreRegistration is MockAVSDeployer { ); // Deploy New AVS Directory - AVSDirectory avsDirectoryImplementation = new AVSDirectory(delegationManager); + AVSDirectory avsDirectoryImplementation = new AVSDirectory(delegationManager, 0); // TODO: Fix Config avsDirectory = AVSDirectory( address( new TransparentUpgradeableProxy( @@ -72,7 +73,8 @@ contract Test_CoreRegistration is MockAVSDeployer { avsDirectory, rewardsCoordinatorMock, registryCoordinator, - stakeRegistry + stakeRegistry, + allocationManager ); registryCoordinatorImplementation = new RegistryCoordinatorHarness( @@ -102,11 +104,13 @@ contract Test_CoreRegistration is MockAVSDeployer { // Register operator to EigenLayer cheats.prank(operator); delegationManager.registerAsOperator( - IDelegationManager.OperatorDetails({ + IDelegationManagerTypes.OperatorDetails({ __deprecated_earningsReceiver: operator, delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 + __deprecated_stakerOptOutWindowBlocks: 0 }), + // TODO: fix or parameterize + 0, emptyStringForMetadataURI ); @@ -137,8 +141,8 @@ contract Test_CoreRegistration is MockAVSDeployer { registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, operatorSignature); // Check operator is registered - IAVSDirectory.OperatorAVSRegistrationStatus operatorStatus = avsDirectory.avsOperatorStatus(address(serviceManager), operator); - assertEq(uint8(operatorStatus), uint8(IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED)); + IAVSDirectoryTypes.OperatorAVSRegistrationStatus operatorStatus = avsDirectory.avsOperatorStatus(address(serviceManager), operator); + assertEq(uint8(operatorStatus), uint8(IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED)); } function test_deregisterOperator_coreStateChanges() public { @@ -151,8 +155,8 @@ contract Test_CoreRegistration is MockAVSDeployer { registryCoordinator.deregisterOperator(quorumNumbers); // Check operator is deregistered - IAVSDirectory.OperatorAVSRegistrationStatus operatorStatus = avsDirectory.avsOperatorStatus(address(serviceManager), operator); - assertEq(uint8(operatorStatus), uint8(IAVSDirectory.OperatorAVSRegistrationStatus.UNREGISTERED)); + IAVSDirectoryTypes.OperatorAVSRegistrationStatus operatorStatus = avsDirectory.avsOperatorStatus(address(serviceManager), operator); + assertEq(uint8(operatorStatus), uint8(IAVSDirectoryTypes.OperatorAVSRegistrationStatus.UNREGISTERED)); } function test_deregisterOperator_notGloballyDeregistered() public { @@ -167,8 +171,8 @@ contract Test_CoreRegistration is MockAVSDeployer { registryCoordinator.deregisterOperator(quorumNumbers); // Check operator is still registered - IAVSDirectory.OperatorAVSRegistrationStatus operatorStatus = avsDirectory.avsOperatorStatus(address(serviceManager), operator); - assertEq(uint8(operatorStatus), uint8(IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED)); + IAVSDirectoryTypes.OperatorAVSRegistrationStatus operatorStatus = avsDirectory.avsOperatorStatus(address(serviceManager), operator); + assertEq(uint8(operatorStatus), uint8(IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED)); } function test_setMetadataURI_fail_notServiceManagerOwner() public { diff --git a/test/integration/IntegrationBase.t.sol b/test/integration/IntegrationBase.t.sol index c9695d70..7a0265f9 100644 --- a/test/integration/IntegrationBase.t.sol +++ b/test/integration/IntegrationBase.t.sol @@ -166,15 +166,15 @@ abstract contract IntegrationBase is IntegrationConfig { /// AVSDirectory: function assert_NotRegisteredToAVS(User operator, string memory err) internal { - IAVSDirectory.OperatorAVSRegistrationStatus status = avsDirectory.avsOperatorStatus(address(serviceManager), address(operator)); + IAVSDirectoryTypes.OperatorAVSRegistrationStatus status = avsDirectory.avsOperatorStatus(address(serviceManager), address(operator)); - assertTrue(status == IAVSDirectory.OperatorAVSRegistrationStatus.UNREGISTERED, err); + assertTrue(status == IAVSDirectoryTypes.OperatorAVSRegistrationStatus.UNREGISTERED, err); } function assert_IsRegisteredToAVS(User operator, string memory err) internal { IAVSDirectory.OperatorAVSRegistrationStatus status = avsDirectory.avsOperatorStatus(address(serviceManager), address(operator)); - assertTrue(status == IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED, err); + assertTrue(status == IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED, err); } /******************************************************************************* @@ -591,7 +591,7 @@ abstract contract IntegrationBase is IntegrationConfig { function assert_Snap_Removed_OperatorShares( User operator, IStrategy[] memory strategies, - uint[] memory removedShares, + uint256[] memory removedShares, string memory err ) internal { uint[] memory curShares = _getOperatorShares(operator, strategies); @@ -773,7 +773,7 @@ abstract contract IntegrationBase is IntegrationConfig { for (uint i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; - curShares[i] = strategyManager.stakerStrategyShares(address(staker), strat); + curShares[i] = strategyManager.stakerDepositShares(address(staker), strat); } return curShares; diff --git a/test/integration/IntegrationChecks.t.sol b/test/integration/IntegrationChecks.t.sol index b54f8568..67ee38f5 100644 --- a/test/integration/IntegrationChecks.t.sol +++ b/test/integration/IntegrationChecks.t.sol @@ -245,7 +245,7 @@ contract IntegrationChecks is IntegrationBase { User operator, bytes memory quorums, IStrategy[] memory strategies, - uint[] memory shares + uint256[] memory shares ) internal { _log("check_Withdraw_State", operator); diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index ee3722a7..7b9705f9 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -14,9 +14,9 @@ import "@openzeppelin/contracts/utils/Strings.sol"; // Core contracts import "eigenlayer-contracts/src/contracts/core/DelegationManager.sol"; import "eigenlayer-contracts/src/contracts/core/StrategyManager.sol"; -import "eigenlayer-contracts/src/contracts/core/Slasher.sol"; import "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; import "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; +import "eigenlayer-contracts/src/contracts/core/AllocationManager.sol"; import "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; import "eigenlayer-contracts/src/contracts/pods/EigenPodManager.sol"; import "eigenlayer-contracts/src/contracts/pods/EigenPod.sol"; @@ -51,10 +51,10 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { EigenPodManager eigenPodManager; RewardsCoordinator rewardsCoordinator; PauserRegistry pauserRegistry; - Slasher slasher; IBeacon eigenPodBeacon; EigenPod pod; ETHPOSDepositMock ethPOSDeposit; + AllocationManager allocationManager; // Base strategy implementation in case we want to create more strategies later StrategyBase baseStrategyImplementation; @@ -131,17 +131,18 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") ) ); - slasher = Slasher( + eigenPodManager = EigenPodManager( address( new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") ) ); - eigenPodManager = EigenPodManager( + avsDirectory = AVSDirectory( address( new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") ) ); - avsDirectory = AVSDirectory( + + allocationManager = AllocationManager( address( new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") ) @@ -161,14 +162,13 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs DelegationManager delegationImplementation = - new DelegationManager(strategyManager, slasher, eigenPodManager); + new DelegationManager(avsDirectory, strategyManager, eigenPodManager, allocationManager, 0); StrategyManager strategyManagerImplementation = - new StrategyManager(delegationManager, eigenPodManager, slasher); - Slasher slasherImplementation = new Slasher(strategyManager, delegationManager); + new StrategyManager(delegationManager); EigenPodManager eigenPodManagerImplementation = new EigenPodManager( - ethPOSDeposit, eigenPodBeacon, strategyManager, slasher, delegationManager + ethPOSDeposit, eigenPodBeacon, strategyManager, delegationManager ); - AVSDirectory avsDirectoryImplemntation = new AVSDirectory(delegationManager); + AVSDirectory avsDirectoryImplemntation = new AVSDirectory(delegationManager, 0); // TODO: fix config // RewardsCoordinator rewardsCoordinatorImplementation = new RewardsCoordinator( // delegationManager, // IStrategyManager(address(strategyManager)), @@ -208,17 +208,6 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { 0 // initialPausedStatus ) ); - // Slasher - proxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(slasher))), - address(slasherImplementation), - abi.encodeWithSelector( - Slasher.initialize.selector, - eigenLayerReputedMultisig, - pauserRegistry, - 0 // initialPausedStatus - ) - ); // EigenPodManager proxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(eigenPodManager))), @@ -312,7 +301,8 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { IAVSDirectory(avsDirectory), rewardsCoordinator, IRegistryCoordinator(registryCoordinator), - stakeRegistry + stakeRegistry, + allocationManager ); proxyAdmin.upgrade( @@ -337,7 +327,8 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { serviceManager.initialize({ initialOwner: registryCoordinatorOwner, - rewardsInitiator: address(msg.sender) + rewardsInitiator: address(msg.sender), + slasher: address(msg.sender) }); RegistryCoordinator registryCoordinatorImplementation = @@ -389,7 +380,7 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { strategies[0] = strategy; cheats.prank(strategyManager.strategyWhitelister()); strategyManager.addStrategiesToDepositWhitelist( - strategies, thirdPartyTransfersForbiddenValues + strategies ); // Add to allStrats diff --git a/test/integration/User.t.sol b/test/integration/User.t.sol index 9e5e5990..ff31a7ed 100644 --- a/test/integration/User.t.sol +++ b/test/integration/User.t.sol @@ -11,6 +11,7 @@ import "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; // Core import "eigenlayer-contracts/src/contracts/core/DelegationManager.sol"; +import "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import "eigenlayer-contracts/src/contracts/core/StrategyManager.sol"; import "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; @@ -243,13 +244,13 @@ contract User is Test { function registerAsOperator() public createSnapshot virtual { _log("registerAsOperator (core)"); - IDelegationManager.OperatorDetails memory details = IDelegationManager.OperatorDetails({ + IDelegationManagerTypes.OperatorDetails memory details = IDelegationManagerTypes.OperatorDetails({ __deprecated_earningsReceiver: address(this), delegationApprover: address(0), - stakerOptOutWindowBlocks: 0 + __deprecated_stakerOptOutWindowBlocks: 0 }); - delegationManager.registerAsOperator(details, NAME); + delegationManager.registerAsOperator(details,0, NAME); } // Deposit LSTs into the StrategyManager. This setup does not use the EPMgr or native ETH. @@ -266,13 +267,15 @@ contract User is Test { } } - function exitEigenlayer() public createSnapshot virtual returns (IStrategy[] memory, uint[] memory) { + function exitEigenlayer() public createSnapshot virtual returns (IStrategy[] memory, uint256[] memory) { _log("exitEigenlayer (core)"); - (IStrategy[] memory strategies, uint[] memory shares) = delegationManager.getDelegatableShares(address(this)); + IStrategy[] memory strategies; + uint256[] memory shares; + // = delegationManager.getDelegatableShares(address(this)); // TODO: Fix - IDelegationManager.QueuedWithdrawalParams[] memory params = new IDelegationManager.QueuedWithdrawalParams[](1); - params[0] = IDelegationManager.QueuedWithdrawalParams({ + IDelegationManagerTypes.QueuedWithdrawalParams[] memory params = new IDelegationManager.QueuedWithdrawalParams[](1); + params[0] = IDelegationManagerTypes.QueuedWithdrawalParams({ strategies: strategies, shares: shares, withdrawer: address(this) diff --git a/test/integration/tests/NonFull_Register_CoreBalanceChange_Update.t.sol b/test/integration/tests/NonFull_Register_CoreBalanceChange_Update.t.sol index 43daf518..a4ffe3e6 100644 --- a/test/integration/tests/NonFull_Register_CoreBalanceChange_Update.t.sol +++ b/test/integration/tests/NonFull_Register_CoreBalanceChange_Update.t.sol @@ -118,7 +118,7 @@ contract Integration_NonFull_Register_CoreBalanceChange_Update is IntegrationChe check_Register_State(operator, quorums); // 2. (core) queue full withdrawal - (IStrategy[] memory strategies, uint[] memory shares) = operator.exitEigenlayer(); + (IStrategy[] memory strategies, uint256[] memory shares) = operator.exitEigenlayer(); check_Withdraw_State(operator, quorums, strategies, shares); // 3. Update stakes @@ -151,7 +151,7 @@ contract Integration_NonFull_Register_CoreBalanceChange_Update is IntegrationChe check_Register_State(operator, quorums); // 2. (core) queue full withdrawal - (IStrategy[] memory strategies, uint[] memory shares) = operator.exitEigenlayer(); + (IStrategy[] memory strategies, uint256[] memory shares) = operator.exitEigenlayer(); check_Withdraw_State(operator, quorums, strategies, shares); // 3. Deregister from all quorums diff --git a/test/mocks/AVSDirectoryMock.sol b/test/mocks/AVSDirectoryMock.sol index 46bfb5db..a6bf2a3c 100644 --- a/test/mocks/AVSDirectoryMock.sol +++ b/test/mocks/AVSDirectoryMock.sol @@ -1,194 +1,173 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.12; -import { - IAVSDirectory, - ISignatureUtils -} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IAVSDirectory, OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; +import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; +import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; contract AVSDirectoryMock is IAVSDirectory { - /** - * @notice Called by an AVS to create a list of new operatorSets. - * - * @param operatorSetIds The IDs of the operator set to initialize. - * - * @dev msg.sender must be the AVS. - * @dev The AVS may create operator sets before it becomes an operator set AVS. - */ - function createOperatorSets(uint32[] calldata operatorSetIds) external {} - - /** - * @notice Sets the AVS as an operator set AVS, preventing legacy M2 operator registrations. - * - * @dev msg.sender must be the AVS. - */ - function becomeOperatorSetAVS() external {} - - /** - * @notice Called by an AVS to migrate operators that have a legacy M2 registration to operator sets. - * - * @param operators The list of operators to migrate - * @param operatorSetIds The list of operatorSets to migrate the operators to - * - * @dev The msg.sender used is the AVS - * @dev The operator can only be migrated at most once per AVS - * @dev The AVS can no longer register operators via the legacy M2 registration path once it begins migration - * @dev The operator is deregistered from the M2 legacy AVS once migrated - */ - function migrateOperatorsToOperatorSets( - address[] calldata operators, - uint32[][] calldata operatorSetIds - ) external {} - - /** - * @notice Called by AVSs to add an operator to list of operatorSets. - * - * @param operator The address of the operator to be added to the operator set. - * @param operatorSetIds The IDs of the operator sets. - * @param operatorSignature The signature of the operator on their intent to register. - * - * @dev msg.sender is used as the AVS. - * @dev The operator must not have a pending deregistration from the operator set. - */ - function registerOperatorToOperatorSets( - address operator, - uint32[] calldata operatorSetIds, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature - ) external {} - - /** - * @notice Called by AVSs to remove an operator from an operator set. - * - * @param operator The address of the operator to be removed from the operator set. - * @param operatorSetIds The IDs of the operator sets. - * - * @dev msg.sender is used as the AVS. - */ - function deregisterOperatorFromOperatorSets( - address operator, - uint32[] calldata operatorSetIds - ) external {} - - /** - * @notice Called by an operator to deregister from an operator set - * - * @param operator The operator to deregister from the operatorSets. - * @param avs The address of the AVS to deregister the operator from. - * @param operatorSetIds The IDs of the operator sets. - * @param operatorSignature the signature of the operator on their intent to deregister or empty if the operator itself is calling - * - * @dev if the operatorSignature is empty, the caller must be the operator - * @dev this will likely only be called in case the AVS contracts are in a state that prevents operators from deregistering - */ - function forceDeregisterFromOperatorSets( - address operator, - address avs, - uint32[] calldata operatorSetIds, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature - ) external {} - - /** - * @notice Called by an avs to register an operator with the avs. - * @param operator The address of the operator to register. - * @param operatorSignature The signature, salt, and expiry of the operator's signature. - */ - function registerOperatorToAVS( - address operator, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature - ) external {} - - /** - * @notice Called by an avs to deregister an operator with the avs. - * @param operator The address of the operator to deregister. - */ - function deregisterOperatorFromAVS(address operator) external {} - - /** - * @notice Called by an AVS to emit an `AVSMetadataURIUpdated` event indicating the information has updated. - * @param metadataURI The URI for metadata associated with an AVS - * @dev Note that the `metadataURI` is *never stored * and is only emitted in the `AVSMetadataURIUpdated` event - */ - function updateAVSMetadataURI(string calldata metadataURI) external {} - - /** - * @notice Called by an operator to cancel a salt that has been used to register with an AVS. - * - * @param salt A unique and single use value associated with the approver signature. - */ - function cancelSalt(bytes32 salt) external {} - - /** - * @notice Returns whether or not the salt has already been used by the operator. - * @dev Salts is used in the `registerOperatorToAVS` function. - */ - function operatorSaltIsSpent(address operator, bytes32 salt) external view returns (bool) {} - - function isMember( - address avs, - address operator, - uint32 operatorSetId - ) external view returns (bool) {} - - /** - * @notice Calculates the digest hash to be signed by an operator to register with an AVS - * @param operator The account registering as an operator - * @param avs The AVS the operator is registering to - * @param salt A unique and single use value associated with the approver signature. - * @param expiry Time after which the approver's signature becomes invalid - */ - function calculateOperatorAVSRegistrationDigestHash( - address operator, - address avs, - bytes32 salt, - uint256 expiry - ) external view returns (bytes32) {} - - /** - * @notice Calculates the digest hash to be signed by an operator to register with an operator set. - * - * @param avs The AVS that operator is registering to operator sets for. - * @param operatorSetIds An array of operator set IDs the operator is registering to. - * @param salt A unique and single use value associated with the approver signature. - * @param expiry Time after which the approver's signature becomes invalid. - */ - function calculateOperatorSetRegistrationDigestHash( - address avs, - uint32[] calldata operatorSetIds, - bytes32 salt, - uint256 expiry - ) external view returns (bytes32) {} - - /** - * @notice Calculates the digest hash to be signed by an operator to force deregister from an operator set. - * - * @param avs The AVS that operator is deregistering from. - * @param operatorSetIds An array of operator set IDs the operator is deregistering from. - * @param salt A unique and single use value associated with the approver signature. - * @param expiry Time after which the approver's signature becomes invalid. - */ - function calculateOperatorSetForceDeregistrationTypehash( - address avs, - uint32[] calldata operatorSetIds, - bytes32 salt, - uint256 expiry - ) external view returns (bytes32) {} - - /// @notice Getter function for the current EIP-712 domain separator for this contract. - /// @dev The domain separator will change in the event of a fork that changes the ChainID. - function domainSeparator() external view returns (bytes32) {} - - /// @notice The EIP-712 typehash for the Registration struct used by the contract - function OPERATOR_AVS_REGISTRATION_TYPEHASH() external view returns (bytes32) {} - - /// @notice The EIP-712 typehash for the OperatorSetRegistration struct used by the contract. - function OPERATOR_SET_REGISTRATION_TYPEHASH() external view returns (bytes32) {} - - function isOperatorSetAVS(address avs) external view returns (bool) {} - - function isOperatorSet(address avs, uint32 operatorSetId) external view returns (bool) {} - - function isMember( - address operator, - OperatorSet memory operatorSet - ) external view returns (bool) {} -} + function createOperatorSets( + uint32[] calldata operatorSetIds + ) external {} + + function becomeOperatorSetAVS() external {} + + function migrateOperatorsToOperatorSets( + address[] calldata operators, + uint32[][] calldata operatorSetIds + ) external {} + + function registerOperatorToOperatorSets( + address operator, + uint32[] calldata operatorSetIds, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external {} + + function deregisterOperatorFromOperatorSets( + address operator, + uint32[] calldata operatorSetIds + ) external {} + + function forceDeregisterFromOperatorSets( + address operator, + address avs, + uint32[] calldata operatorSetIds, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external {} + + function registerOperatorToAVS( + address operator, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external {} + + function deregisterOperatorFromAVS(address operator) external {} + + function updateAVSMetadataURI( + string calldata metadataURI + ) external {} + + function cancelSalt(bytes32 salt) external {} + + function operatorSaltIsSpent( + address operator, + bytes32 salt + ) external view returns (bool) {} + + function isMember( + address operator, + OperatorSet memory operatorSet + ) external view returns (bool) {} + + function isOperatorSlashable( + address operator, + OperatorSet memory operatorSet + ) external view returns (bool) {} + + function isOperatorSetAVS( + address avs + ) external view returns (bool) {} + + function isOperatorSet( + address avs, + uint32 operatorSetId + ) external view returns (bool) {} + + function isOperatorSetBatch( + OperatorSet[] calldata operatorSets + ) external view returns (bool) {} + + function operatorSetsMemberOfAtIndex( + address operator, + uint256 index + ) external view returns (OperatorSet memory) {} + + function operatorSetMemberAtIndex( + OperatorSet memory operatorSet, + uint256 index + ) external view returns (address) {} + + function getOperatorSetsOfOperator( + address operator, + uint256 start, + uint256 length + ) external view returns (OperatorSet[] memory operatorSets) {} + + function getOperatorsInOperatorSet( + OperatorSet memory operatorSet, + uint256 start, + uint256 length + ) external view returns (address[] memory operators) {} + + function getNumOperatorsInOperatorSet( + OperatorSet memory operatorSet + ) external view returns (uint256) {} + + function inTotalOperatorSets( + address operator + ) external view returns (uint256) {} + + function calculateOperatorAVSRegistrationDigestHash( + address operator, + address avs, + bytes32 salt, + uint256 expiry + ) external view returns (bytes32) {} + + function calculateOperatorSetRegistrationDigestHash( + address avs, + uint32[] calldata operatorSetIds, + bytes32 salt, + uint256 expiry + ) external view returns (bytes32) {} + + function calculateOperatorSetForceDeregistrationTypehash( + address avs, + uint32[] calldata operatorSetIds, + bytes32 salt, + uint256 expiry + ) external view returns (bytes32) {} + + function OPERATOR_AVS_REGISTRATION_TYPEHASH() + external + view + returns (bytes32) + {} + + function OPERATOR_SET_REGISTRATION_TYPEHASH() + external + view + returns (bytes32) + {} + + function operatorSetStatus( + address avs, + address operator, + uint32 operatorSetId + ) + external + view + returns (bool registered, uint32 lastDeregisteredTimestamp) + {} + + function getNumOperatorSetsOfOperator( + address operator + ) external view returns (uint256) {} + + function getStrategiesInOperatorSet( + OperatorSet memory operatorSet + ) external view returns (IStrategy[] memory) {} + + function initialize( + address initialOwner, + IPauserRegistry _pauserRegistry, + uint256 initialPausedStatus + ) external {} + + function removeStrategiesFromOperatorSet( + uint32 operatorSetId, + IStrategy[] calldata strategies + ) external {} + + function addStrategiesToOperatorSet(uint32 operatorSetId, IStrategy[] calldata strategies) external {} +} \ No newline at end of file diff --git a/test/mocks/AllocationManagerMock.sol b/test/mocks/AllocationManagerMock.sol new file mode 100644 index 00000000..1436882e --- /dev/null +++ b/test/mocks/AllocationManagerMock.sol @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; +import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; +import {OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; + +contract AllocationManagerMock is IAllocationManager { + function initialize( + address initialOwner, + IPauserRegistry _pauserRegistry, + uint256 initialPausedStatus + ) external override {} + + function slashOperator(SlashingParams calldata params) external override {} + + function modifyAllocations( + MagnitudeAllocation[] calldata allocations + ) external override {} + + function clearDeallocationQueue( + address operator, + IStrategy[] calldata strategies, + uint16[] calldata numToComplete + ) external override {} + + function setAllocationDelay( + address operator, + uint32 delay + ) external override {} + + function setAllocationDelay(uint32 delay) external override {} + + function getAllocationInfo( + address operator, + IStrategy strategy + ) + external + view + override + returns (OperatorSet[] memory, MagnitudeInfo[] memory) + {} + + function getAllocationInfo( + address operator, + IStrategy strategy, + OperatorSet[] calldata operatorSets + ) external view override returns (MagnitudeInfo[] memory) {} + + function getAllocationInfo( + OperatorSet calldata operatorSet, + IStrategy[] calldata strategies, + address[] calldata operators + ) external view override returns (MagnitudeInfo[][] memory) {} + + function getAllocatableMagnitude( + address operator, + IStrategy strategy + ) external view override returns (uint64) {} + + function getMaxMagnitudes( + address operator, + IStrategy[] calldata strategies + ) external view override returns (uint64[] memory) {} + + function getMaxMagnitudesAtTimestamp( + address operator, + IStrategy[] calldata strategies, + uint32 timestamp + ) external view override returns (uint64[] memory) {} + + function getAllocationDelay( + address operator + ) external view override returns (bool isSet, uint32 delay) {} + + function getMinDelegatedAndSlashableOperatorShares( + OperatorSet calldata operatorSet, + address[] calldata operators, + IStrategy[] calldata strategies, + uint32 beforeTimestamp + ) external view override returns (uint256[][] memory, uint256[][] memory) {} +} \ No newline at end of file diff --git a/test/mocks/DelegationMock.sol b/test/mocks/DelegationMock.sol index 88cd9d20..9743fb14 100644 --- a/test/mocks/DelegationMock.sol +++ b/test/mocks/DelegationMock.sol @@ -5,199 +5,325 @@ import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; +import {StrategyManager} from "eigenlayer-contracts/src/contracts/core/StrategyManager.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; +import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; +import {SlashingLib} from "eigenlayer-contracts/src/contracts/libraries/SlashingLib.sol"; contract DelegationMock is IDelegationManager { - mapping(address => bool) public isOperator; - mapping(address => mapping(IStrategy => uint256)) public operatorShares; - - function setIsOperator(address operator, bool _isOperatorReturnValue) external { - isOperator[operator] = _isOperatorReturnValue; - } - - /// @notice returns the total number of shares in `strategy` that are delegated to `operator`. - function setOperatorShares(address operator, IStrategy strategy, uint256 shares) external { - operatorShares[operator][strategy] = shares; - } - - mapping (address => address) public delegatedTo; - - function registerAsOperator(OperatorDetails calldata /*registeringOperatorDetails*/, string calldata /*metadataURI*/) external pure {} - - function updateOperatorMetadataURI(string calldata /*metadataURI*/) external pure {} - - function updateAVSMetadataURI(string calldata /*metadataURI*/) external pure {} - - function delegateTo(address operator, SignatureWithExpiry memory /*approverSignatureAndExpiry*/, bytes32 /*approverSalt*/) external { - delegatedTo[msg.sender] = operator; - } - - function modifyOperatorDetails(OperatorDetails calldata /*newOperatorDetails*/) external pure {} - - function delegateToBySignature( - address /*staker*/, - address /*operator*/, - SignatureWithExpiry memory /*stakerSignatureAndExpiry*/, - SignatureWithExpiry memory /*approverSignatureAndExpiry*/, - bytes32 /*approverSalt*/ - ) external pure {} - - function undelegate(address staker) external returns (bytes32[] memory withdrawalRoot) { - delegatedTo[staker] = address(0); - return withdrawalRoot; - } - - function increaseDelegatedShares(address /*staker*/, IStrategy /*strategy*/, uint256 /*shares*/) external pure {} - - function decreaseDelegatedShares( - address /*staker*/, - IStrategy /*strategy*/, - uint256 /*shares*/ - ) external pure {} - - function operatorDetails(address operator) external pure returns (OperatorDetails memory) { - OperatorDetails memory returnValue = OperatorDetails({ - __deprecated_earningsReceiver: operator, - delegationApprover: operator, - stakerOptOutWindowBlocks: 0 - }); - return returnValue; - } - - function beaconChainETHStrategy() external pure returns (IStrategy) {} - - function earningsReceiver(address operator) external pure returns (address) { - return operator; - } - - function delegationApprover(address operator) external pure returns (address) { - return operator; - } - - function stakerOptOutWindowBlocks(address /*operator*/) external pure returns (uint256) { - return 0; - } - - function minWithdrawalDelayBlocks() external view returns (uint256) { - return 50400; - } - - /** - * @notice Minimum delay enforced by this contract per Strategy for completing queued withdrawals. Measured in blocks, and adjustable by this contract's owner, - * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced). - */ - function strategyWithdrawalDelayBlocks(IStrategy /*strategy*/) external view returns (uint256) { - return 0; - } - - function getOperatorShares( - address operator, - IStrategy[] memory strategies - ) external view returns (uint256[] memory) { - uint256[] memory shares = new uint256[](strategies.length); - for (uint256 i = 0; i < strategies.length; ++i) { - shares[i] = operatorShares[operator][strategies[i]]; - } - return shares; - } - - function getWithdrawalDelay(IStrategy[] calldata /*strategies*/) public view returns (uint256) { - return 0; - } - - function isDelegated(address staker) external view returns (bool) { - return (delegatedTo[staker] != address(0)); - } - - function isNotDelegated(address /*staker*/) external pure returns (bool) {} - - // function isOperator(address /*operator*/) external pure returns (bool) {} - - function stakerNonce(address /*staker*/) external pure returns (uint256) {} - - function delegationApproverSaltIsSpent(address /*delegationApprover*/, bytes32 /*salt*/) external pure returns (bool) {} - - function calculateCurrentStakerDelegationDigestHash(address /*staker*/, address /*operator*/, uint256 /*expiry*/) external view returns (bytes32) {} - - function calculateStakerDelegationDigestHash(address /*staker*/, uint256 /*stakerNonce*/, address /*operator*/, uint256 /*expiry*/) external view returns (bytes32) {} - - function calculateDelegationApprovalDigestHash( - address /*staker*/, - address /*operator*/, - address /*_delegationApprover*/, - bytes32 /*approverSalt*/, - uint256 /*expiry*/ - ) external view returns (bytes32) {} - - function calculateStakerDigestHash(address /*staker*/, address /*operator*/, uint256 /*expiry*/) - external pure returns (bytes32 stakerDigestHash) {} - - function calculateApproverDigestHash(address /*staker*/, address /*operator*/, uint256 /*expiry*/) - external pure returns (bytes32 approverDigestHash) {} - - function calculateOperatorAVSRegistrationDigestHash(address /*operator*/, address /*avs*/, bytes32 /*salt*/, uint256 /*expiry*/) - external pure returns (bytes32 digestHash) {} - - function DOMAIN_TYPEHASH() external view returns (bytes32) {} - - function STAKER_DELEGATION_TYPEHASH() external view returns (bytes32) {} - - function DELEGATION_APPROVAL_TYPEHASH() external view returns (bytes32) {} - - function domainSeparator() external view returns (bytes32) {} - - function cumulativeWithdrawalsQueued(address staker) external view returns (uint256) {} - - function calculateWithdrawalRoot(Withdrawal memory withdrawal) external pure returns (bytes32) {} - - function operatorSaltIsSpent(address avs, bytes32 salt) external view returns (bool) {} - - function queueWithdrawals( - QueuedWithdrawalParams[] calldata queuedWithdrawalParams - ) external returns (bytes32[] memory) {} - - function completeQueuedWithdrawal( - Withdrawal calldata withdrawal, - IERC20[] calldata tokens, - uint256 middlewareTimesIndex, - bool receiveAsTokens - ) external {} - - function completeQueuedWithdrawals( - Withdrawal[] calldata withdrawals, - IERC20[][] calldata tokens, - uint256[] calldata middlewareTimesIndexes, - bool[] calldata receiveAsTokens - ) external {} - - // onlyDelegationManager functions in StrategyManager - function addShares( - IStrategyManager strategyManager, - address staker, - IERC20 token, - IStrategy strategy, - uint256 shares - ) external { - strategyManager.addShares(staker, token, strategy, shares); - } - - function removeShares( - IStrategyManager strategyManager, - address staker, - IStrategy strategy, - uint256 shares - ) external { - strategyManager.removeShares(staker, strategy, shares); - } - - function withdrawSharesAsTokens( - IStrategyManager strategyManager, - address recipient, - IStrategy strategy, - uint256 shares, - IERC20 token - ) external { - strategyManager.withdrawSharesAsTokens(recipient, strategy, shares, token); + using SlashingLib for uint256; + + mapping(address => bool) public isOperator; + mapping(address => mapping(IStrategy => uint256)) public operatorShares; + + function setIsOperator( + address operator, + bool _isOperatorReturnValue + ) external { + isOperator[operator] = _isOperatorReturnValue; + } + + /// @notice returns the total number of shares in `strategy` that are delegated to `operator`. + function setOperatorShares( + address operator, + IStrategy strategy, + uint256 shares + ) external { + operatorShares[operator][strategy] = shares; + } + + mapping(address => address) public delegatedTo; + + function registerAsOperator( + OperatorDetails calldata /*registeringOperatorDetails*/, + string calldata /*metadataURI*/ + ) external pure {} + + function updateOperatorMetadataURI( + string calldata /*metadataURI*/ + ) external pure {} + + function updateAVSMetadataURI( + string calldata /*metadataURI*/ + ) external pure {} + + function delegateTo( + address operator, + SignatureWithExpiry memory /*approverSignatureAndExpiry*/, + bytes32 /*approverSalt*/ + ) external { + delegatedTo[msg.sender] = operator; + } + + function modifyOperatorDetails( + OperatorDetails calldata /*newOperatorDetails*/ + ) external pure {} + + function delegateToBySignature( + address /*staker*/, + address /*operator*/, + SignatureWithExpiry memory /*stakerSignatureAndExpiry*/, + SignatureWithExpiry memory /*approverSignatureAndExpiry*/, + bytes32 /*approverSalt*/ + ) external pure {} + + function undelegate( + address staker + ) external returns (bytes32[] memory withdrawalRoot) { + delegatedTo[staker] = address(0); + return withdrawalRoot; + } + + function increaseDelegatedShares( + address /*staker*/, + IStrategy /*strategy*/, + uint256 /*shares*/ + ) external pure {} + + function operatorDetails( + address operator + ) external pure returns (OperatorDetails memory) { + OperatorDetails memory returnValue = OperatorDetails({ + __deprecated_earningsReceiver: operator, + delegationApprover: operator, + __deprecated_stakerOptOutWindowBlocks: 0 + }); + return returnValue; + } + + function beaconChainETHStrategy() external pure returns (IStrategy) {} + + function earningsReceiver(address operator) external pure returns (address) { + return operator; + } + + function delegationApprover( + address operator + ) external pure returns (address) { + return operator; + } + + function stakerOptOutWindowBlocks( + address /*operator*/ + ) external pure returns (uint256) { + return 0; + } + + function minWithdrawalDelayBlocks() external view returns (uint256) { + return 50400; + } + + /** + * @notice Minimum delay enforced by this contract per Strategy for completing queued withdrawals. Measured in blocks, and adjustable by this contract's owner, + * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced). + */ + function strategyWithdrawalDelayBlocks( + IStrategy /*strategy*/ + ) external view returns (uint256) { + return 0; + } + + function getOperatorShares( + address operator, + IStrategy[] memory strategies + ) external view returns (uint256[] memory) { + uint256[] memory shares = new uint256[](strategies.length); + for (uint256 i = 0; i < strategies.length; ++i) { + shares[i] = operatorShares[operator][strategies[i]]; } + return shares; + } + + function getWithdrawalDelay( + IStrategy[] calldata /*strategies*/ + ) public view returns (uint256) { + return 0; + } + + function isDelegated(address staker) external view returns (bool) { + return (delegatedTo[staker] != address(0)); + } + + function isNotDelegated(address /*staker*/) external pure returns (bool) {} + + // function isOperator(address /*operator*/) external pure returns (bool) {} + + function stakerNonce(address /*staker*/) external pure returns (uint256) {} + + function delegationApproverSaltIsSpent( + address /*delegationApprover*/, + bytes32 /*salt*/ + ) external pure returns (bool) {} + + function calculateCurrentStakerDelegationDigestHash( + address /*staker*/, + address /*operator*/, + uint256 /*expiry*/ + ) external view returns (bytes32) {} + + function calculateStakerDelegationDigestHash( + address /*staker*/, + uint256 /*stakerNonce*/, + address /*operator*/, + uint256 /*expiry*/ + ) external view returns (bytes32) {} + + function calculateDelegationApprovalDigestHash( + address /*staker*/, + address /*operator*/, + address /*_delegationApprover*/, + bytes32 /*approverSalt*/, + uint256 /*expiry*/ + ) external view returns (bytes32) {} + + function calculateStakerDigestHash( + address /*staker*/, + address /*operator*/, + uint256 /*expiry*/ + ) external pure returns (bytes32 stakerDigestHash) {} + + function calculateApproverDigestHash( + address /*staker*/, + address /*operator*/, + uint256 /*expiry*/ + ) external pure returns (bytes32 approverDigestHash) {} + + function calculateOperatorAVSRegistrationDigestHash( + address /*operator*/, + address /*avs*/, + bytes32 /*salt*/, + uint256 /*expiry*/ + ) external pure returns (bytes32 digestHash) {} + + function DOMAIN_TYPEHASH() external view returns (bytes32) {} + + function STAKER_DELEGATION_TYPEHASH() external view returns (bytes32) {} + + function DELEGATION_APPROVAL_TYPEHASH() external view returns (bytes32) {} + + function domainSeparator() external view returns (bytes32) {} + + function cumulativeWithdrawalsQueued( + address staker + ) external view returns (uint256) {} + + function calculateWithdrawalRoot( + Withdrawal memory withdrawal + ) external pure returns (bytes32) {} + + function operatorSaltIsSpent( + address avs, + bytes32 salt + ) external view returns (bool) {} + + function queueWithdrawals( + QueuedWithdrawalParams[] calldata queuedWithdrawalParams + ) external returns (bytes32[] memory) {} + + function completeQueuedWithdrawal( + Withdrawal calldata withdrawal, + IERC20[] calldata tokens, + uint256 middlewareTimesIndex, + bool receiveAsTokens + ) external {} + + function completeQueuedWithdrawals( + Withdrawal[] calldata withdrawals, + IERC20[][] calldata tokens, + uint256[] calldata middlewareTimesIndexes, + bool[] calldata receiveAsTokens + ) external {} + + // onlyDelegationManager functions in StrategyManager + function addShares( + IStrategyManager strategyManager, + address staker, + IERC20 token, + IStrategy strategy, + uint256 shares + ) external { + strategyManager.addShares(staker, strategy, token, shares); + } + + function removeShares( + IStrategyManager strategyManager, + address staker, + IStrategy strategy, + uint256 shares + ) external { + strategyManager.removeDepositShares(staker, strategy, shares); + } + + function withdrawSharesAsTokens( + IStrategyManager strategyManager, + address recipient, + IStrategy strategy, + uint256 shares, + IERC20 token + ) external { + strategyManager.withdrawSharesAsTokens(recipient, strategy, token, shares); + } + + function registerAsOperator( + OperatorDetails calldata registeringOperatorDetails, + uint32 allocationDelay, + string calldata metadataURI + ) external override {} + + function completeQueuedWithdrawal( + Withdrawal calldata withdrawal, + IERC20[] calldata tokens, + bool receiveAsTokens + ) external override {} + + function completeQueuedWithdrawals( + Withdrawal[] calldata withdrawals, + IERC20[][] calldata tokens, + bool[] calldata receiveAsTokens + ) external override {} + + function decreaseBeaconChainScalingFactor( + address staker, + uint256 existingDepositShares, + uint64 proportionOfOldBalance + ) external override {} + + function decreaseOperatorShares( + address operator, + IStrategy strategy, + uint64 previousTotalMagnitude, + uint64 newTotalMagnitude + ) external override {} + + function increaseDelegatedShares( + address staker, + IStrategy strategy, + uint256 existingDepositShares, + uint256 addedShares + ) external override {} + + function initialize( + address initialOwner, + IPauserRegistry _pauserRegistry, + uint256 initialPausedStatus + ) external override {} + + function getOperatorsShares( + address[] memory operators, + IStrategy[] memory strategies + ) external view override returns (uint256[][] memory) {} + + function getWithdrawableShares( + address staker, + IStrategy[] memory strategies + ) external view override returns (uint256[] memory withdrawableShares) {} + + function getDepositedShares( + address staker + ) external view override returns (IStrategy[] memory, uint256[] memory) {} + + function getCompletableTimestamp( + uint32 startTimestamp + ) external view override returns (uint32 completableTimestamp) {} } diff --git a/test/mocks/ECDSAServiceManagerMock.sol b/test/mocks/ECDSAServiceManagerMock.sol index 88e3ac6f..5be1d82d 100644 --- a/test/mocks/ECDSAServiceManagerMock.sol +++ b/test/mocks/ECDSAServiceManagerMock.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.12; import "../../src/unaudited/ECDSAServiceManagerBase.sol"; +import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; contract ECDSAServiceManagerMock is ECDSAServiceManagerBase { constructor( @@ -34,4 +35,8 @@ contract ECDSAServiceManagerMock is ECDSAServiceManagerBase { ) external {} function deregisterOperatorFromOperatorSets(address operator, uint32[] calldata operatorSetIds) external{} + + function slashOperator(IAllocationManagerTypes.SlashingParams memory params) external override { + // Mock implementation - no actual slashing occurs + } } diff --git a/test/mocks/EigenPodManagerMock.sol b/test/mocks/EigenPodManagerMock.sol new file mode 100644 index 00000000..afdd6189 --- /dev/null +++ b/test/mocks/EigenPodManagerMock.sol @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.9; + +import "forge-std/Test.sol"; +import "eigenlayer-contracts/src/contracts/permissions/Pausable.sol"; +import "eigenlayer-contracts/src/contracts/interfaces/IEigenPodManager.sol"; + +contract EigenPodManagerMock is Test, Pausable, IEigenPodManager { + receive() external payable {} + fallback() external payable {} + + mapping(address => int256) public podShares; + + constructor(IPauserRegistry _pauserRegistry) { + _initializePauser(_pauserRegistry, 0); + } + + function podOwnerShares(address podOwner) external view returns (int256) { + return podShares[podOwner]; + } + + function setPodOwnerShares(address podOwner, int256 shares) external { + podShares[podOwner] = shares; + } + + function denebForkTimestamp() external pure returns (uint64) { + return type(uint64).max; + } + + function createPod() external returns (address) { + } + + function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable { + } + + function recordBeaconChainETHBalanceUpdate( + address podOwner, + int256 sharesDelta, + uint64 proportionPodBalanceDecrease + ) external { + } + + function ownerToPod(address podOwner) external view returns (IEigenPod) { + } + + function getPod(address podOwner) external view returns (IEigenPod) { + } + + function ethPOS() external view returns (IETHPOSDeposit) { + } + + function eigenPodBeacon() external view returns (IBeacon) { + } + + function strategyManager() external view returns (IStrategyManager) { + } + + function hasPod(address podOwner) external view returns (bool) { + } + + function numPods() external view returns (uint256) { + } + + function podOwnerDepositShares(address podOwner) external view returns (int256) { + } + + function beaconChainETHStrategy() external view returns (IStrategy) { + } + + function addShares(address staker, IStrategy strategy, IERC20 token, uint256 shares) external { + } + + function removeDepositShares(address staker, IStrategy strategy, uint256 depositSharesToRemove) external { + } + + function stakerDepositShares(address user, IStrategy strategy) external view returns (uint256 depositShares) { + } + + function withdrawSharesAsTokens(address staker, IStrategy strategy, IERC20 token, uint256 shares) external{} +} \ No newline at end of file diff --git a/test/mocks/RewardsCoordinatorMock.sol b/test/mocks/RewardsCoordinatorMock.sol index 2be3cd6c..cc8404a0 100644 --- a/test/mocks/RewardsCoordinatorMock.sol +++ b/test/mocks/RewardsCoordinatorMock.sol @@ -3,112 +3,131 @@ pragma solidity ^0.8.12; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; import "./AVSDirectoryMock.sol"; contract RewardsCoordinatorMock is IRewardsCoordinator { - /// @notice The address of the entity that can update the contract with new merkle roots - function rewardsUpdater() external view returns (address) {} + /// @notice The address of the entity that can update the contract with new merkle roots + function rewardsUpdater() external view returns (address) {} - function CALCULATION_INTERVAL_SECONDS() external view returns (uint32) {} + function CALCULATION_INTERVAL_SECONDS() external view returns (uint32) {} - function MAX_REWARDS_DURATION() external view returns (uint32) {} + function MAX_REWARDS_DURATION() external view returns (uint32) {} - function MAX_RETROACTIVE_LENGTH() external view returns (uint32) {} + function MAX_RETROACTIVE_LENGTH() external view returns (uint32) {} - function MAX_FUTURE_LENGTH() external view returns (uint32) {} + function MAX_FUTURE_LENGTH() external view returns (uint32) {} - function GENESIS_REWARDS_TIMESTAMP() external view returns (uint32) {} + function GENESIS_REWARDS_TIMESTAMP() external view returns (uint32) {} - function activationDelay() external view returns (uint32) {} + function activationDelay() external view returns (uint32) {} - function claimerFor(address earner) external view returns (address) {} + function claimerFor(address earner) external view returns (address) {} - function cumulativeClaimed(address claimer, IERC20 token) external view returns (uint256) {} + function cumulativeClaimed( + address claimer, + IERC20 token + ) external view returns (uint256) {} - /// @notice the commission for a specific operator for a specific avs - /// NOTE: Currently unused and simply returns the globalOperatorCommissionBips value but will be used in future release - function getOperatorCommissionBips( - address operator, - IAVSDirectory.OperatorSet calldata operatorSet, - RewardType rewardType - ) external view returns (uint16) {} + function globalOperatorCommissionBips() external view returns (uint16) {} - /// @notice returns the length of the operator commission update history - function getOperatorCommissionUpdateHistoryLength( - address operator, - IAVSDirectory.OperatorSet calldata operatorSet, - RewardType rewardType - ) external view returns (uint256) {} + function operatorCommissionBips( + address operator, + address avs + ) external view returns (uint16) {} - function globalOperatorCommissionBips() external view returns (uint16) {} + function calculateEarnerLeafHash( + EarnerTreeMerkleLeaf calldata leaf + ) external pure returns (bytes32) {} - function operatorCommissionBips(address operator, address avs) external view returns (uint16) {} + function calculateTokenLeafHash( + TokenTreeMerkleLeaf calldata leaf + ) external pure returns (bytes32) {} - function calculateEarnerLeafHash(EarnerTreeMerkleLeaf calldata leaf) external pure returns (bytes32) {} + function checkClaim( + RewardsMerkleClaim calldata claim + ) external view returns (bool) {} - function calculateTokenLeafHash(TokenTreeMerkleLeaf calldata leaf) external pure returns (bytes32) {} + function currRewardsCalculationEndTimestamp() + external + view + returns (uint32) + {} - function checkClaim(RewardsMerkleClaim calldata claim) external view returns (bool) {} + function getRootIndexFromHash( + bytes32 rootHash + ) external view returns (uint32) {} - function currRewardsCalculationEndTimestamp() external view returns (uint32) {} + function getDistributionRootsLength() external view returns (uint256) {} - function getRootIndexFromHash(bytes32 rootHash) external view returns (uint32) {} + function getDistributionRootAtIndex( + uint256 index + ) external view returns (DistributionRoot memory) {} - function getDistributionRootsLength() external view returns (uint256) {} + function getCurrentClaimableDistributionRoot() + external + view + returns (DistributionRoot memory) + {} - function getDistributionRootAtIndex(uint256 index) external view returns (DistributionRoot memory) {} + function getCurrentDistributionRoot() + external + view + returns (DistributionRoot memory) + {} - function getCurrentClaimableDistributionRoot() external view returns (DistributionRoot memory) {} + /// EXTERNAL FUNCTIONS /// - function getCurrentDistributionRoot() external view returns (DistributionRoot memory) {} + function disableRoot(uint32 rootIndex) external {} - /// EXTERNAL FUNCTIONS /// + function createAVSRewardsSubmission( + RewardsSubmission[] calldata rewardsSubmissions + ) external {} - function disableRoot(uint32 rootIndex) external {} + function createRewardsForAllSubmission( + RewardsSubmission[] calldata rewardsSubmission + ) external {} - function createAVSRewardsSubmission(RewardsSubmission[] calldata rewardsSubmissions) external {} + function processClaim( + RewardsMerkleClaim calldata claim, + address recipient + ) external {} - function createRewardsForAllSubmission(RewardsSubmission[] calldata rewardsSubmission) external {} + function submitRoot( + bytes32 root, + uint32 rewardsCalculationEndTimestamp + ) external {} - function processClaim(RewardsMerkleClaim calldata claim, address recipient) external {} + function setRewardsUpdater(address _rewardsUpdater) external {} - function submitRoot( - bytes32 root, - uint32 rewardsCalculationEndTimestamp - ) external {} + function setActivationDelay(uint32 _activationDelay) external {} - function setRewardsUpdater(address _rewardsUpdater) external {} + function setGlobalOperatorCommission(uint16 _globalCommissionBips) external {} - function setActivationDelay(uint32 _activationDelay) external {} + function setClaimerFor(address claimer) external {} - function setGlobalOperatorCommission(uint16 _globalCommissionBips) external {} + /** + * @notice Sets the permissioned `payAllForRangeSubmitter` address which can submit payAllForRange + * @dev Only callable by the contract owner + * @param _submitter The address of the payAllForRangeSubmitter + * @param _newValue The new value for isPayAllForRangeSubmitter + */ + function setRewardsForAllSubmitter( + address _submitter, + bool _newValue + ) external {} - function setClaimerFor(address claimer) external {} - - /** - * @notice Sets the permissioned `payAllForRangeSubmitter` address which can submit payAllForRange - * @dev Only callable by the contract owner - * @param _submitter The address of the payAllForRangeSubmitter - * @param _newValue The new value for isPayAllForRangeSubmitter - */ - function setRewardsForAllSubmitter(address _submitter, bool _newValue) external {} - - /** - * @notice Sets the commission an operator takes in bips for a given reward type and operatorSet - * @param operatorSet The operatorSet to update commission for - * @param rewardType The associated rewardType to update commission for - * @param commissionBips The commission in bips for the operator, must be <= MAX_COMMISSION_BIPS - * @return effectTimestamp The timestamp at which the operator commission update will take effect - * - * @dev The commission can range from 1 to 10000 - * @dev The commission update takes effect after 7 days - */ - function setOperatorCommissionBips( - IAVSDirectory.OperatorSet calldata operatorSet, - RewardType rewardType, - uint16 commissionBips - ) external returns (uint32) {} - - function rewardOperatorSetForRange(OperatorSetRewardsSubmission[] calldata rewardsSubmissions) external{} + function createRewardsForAllEarners( + RewardsSubmission[] calldata rewardsSubmissions + ) external override {} + + function initialize( + address initialOwner, + IPauserRegistry _pauserRegistry, + uint256 initialPausedStatus, + address _rewardsUpdater, + uint32 _activationDelay, + uint16 _globalCommissionBips + ) external override {} } \ No newline at end of file diff --git a/test/mocks/ServiceManagerMock.sol b/test/mocks/ServiceManagerMock.sol index 8af99426..a9bb5fff 100644 --- a/test/mocks/ServiceManagerMock.sol +++ b/test/mocks/ServiceManagerMock.sol @@ -8,15 +8,23 @@ contract ServiceManagerMock is ServiceManagerBase { IAVSDirectory _avsDirectory, IRewardsCoordinator _rewardsCoordinator, IRegistryCoordinator _registryCoordinator, - IStakeRegistry _stakeRegistry + IStakeRegistry _stakeRegistry, + IAllocationManager _allocationManager ) - ServiceManagerBase(_avsDirectory, _rewardsCoordinator, _registryCoordinator, _stakeRegistry) + ServiceManagerBase( + _avsDirectory, + _rewardsCoordinator, + _registryCoordinator, + _stakeRegistry, + _allocationManager + ) {} function initialize( address initialOwner, - address rewardsInitiator + address rewardsInitiator, + address slasher ) public virtual initializer { - __ServiceManagerBase_init(initialOwner, rewardsInitiator); + __ServiceManagerBase_init(initialOwner, rewardsInitiator, slasher); } } diff --git a/test/unit/ECDSAServiceManager.t.sol b/test/unit/ECDSAServiceManager.t.sol index 3b533d47..1093b77a 100644 --- a/test/unit/ECDSAServiceManager.t.sol +++ b/test/unit/ECDSAServiceManager.t.sol @@ -145,14 +145,15 @@ contract ECDSAServiceManagerSetup is Test { shares[0] = 0; shares[1] = 1; - vm.mockCall( - address(mockDelegationManager), - abi.encodeCall( - IDelegationManager.getOperatorShares, - (operator, strategies) - ), - abi.encode(shares) - ); + // TODO: Fix + // vm.mockCall( + // address(mockDelegationManager), + // abi.encodeCall( + // IDelegationManager.getOperatorShares, + // (operator, strategies) + // ), + // abi.encode(shares) + // ); address[] memory restakedStrategies = serviceManager .getOperatorRestakedStrategies(operator); diff --git a/test/unit/RegistryCoordinatorMigration.t.sol b/test/unit/RegistryCoordinatorMigration.t.sol index 99fd38f4..63e4c837 100644 --- a/test/unit/RegistryCoordinatorMigration.t.sol +++ b/test/unit/RegistryCoordinatorMigration.t.sol @@ -5,12 +5,16 @@ import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; import { RewardsCoordinator, IRewardsCoordinator, + IRewardsCoordinatorTypes, IERC20 } from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {StrategyBase} from "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; import {IServiceManagerBaseEvents} from "../events/IServiceManagerBaseEvents.sol"; +import {IAVSDirectoryTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; import {AVSDirectoryHarness} from "../harnesses/AVSDirectoryHarness.sol"; +import {OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import "../utils/MockAVSDeployer.sol"; @@ -55,7 +59,8 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas avsDirectory, IRewardsCoordinator(address(rewardsCoordinatorMock)), registryCoordinator, - stakeRegistry + stakeRegistry, + allocationManager ); avsDirectoryHarness = new AVSDirectoryHarness(delegationMock); @@ -63,7 +68,8 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas avsDirectory, rewardsCoordinatorMock, registryCoordinator, - stakeRegistry + stakeRegistry, + allocationManager ); /// Needed to upgrade to a service manager that points to an AVS Directory that can track state vm.prank(proxyAdmin.owner()); @@ -90,7 +96,7 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas IERC20 token3 = new ERC20PresetFixedSupply( "pepe wif avs", "MOCK3", mockTokenInitialSupply, address(this) ); - strategyImplementation = new StrategyBase(strategyManagerMock); + strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock))); strategyMock1 = StrategyBase( address( new TransparentUpgradeableProxy( @@ -129,13 +135,13 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas strategyManagerMock.setStrategyWhitelist(strategies[2], true); defaultStrategyAndMultipliers.push( - IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[0])), 1e18) + IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[0])), 1e18) ); defaultStrategyAndMultipliers.push( - IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[1])), 2e18) + IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[1])), 2e18) ); defaultStrategyAndMultipliers.push( - IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[2])), 3e18) + IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[2])), 3e18) ); } @@ -226,7 +232,7 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas AVSDirectoryHarness(address(avsDirectory)).setAvsOperatorStatus( address(serviceManager), operatorAddress, - IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED + IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED ); } } @@ -263,7 +269,7 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas }) ); // sanity check if the operator was unregistered from the intended operator set - bool operatorIsUnRegistered = !avsDirectory.isMember(operators[0], IAVSDirectory.OperatorSet({ + bool operatorIsUnRegistered = !avsDirectory.isMember(operators[0], OperatorSet({ avs: address(serviceManager), operatorSetId: defaultQuorumNumber })); @@ -311,7 +317,7 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas AVSDirectoryHarness(address(avsDirectory)).setAvsOperatorStatus( address(serviceManager), operatorAddress, - IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED + IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED ); } } @@ -337,7 +343,7 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas address operatorToDeregister = operators[0]; - bool isOperatorRegistered = avsDirectory.isMember(operatorToDeregister, IAVSDirectory.OperatorSet({ + bool isOperatorRegistered = avsDirectory.isMember(operatorToDeregister, OperatorSet({ avs: address(serviceManager), operatorSetId: defaultQuorumNumber })); @@ -352,7 +358,7 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas registryCoordinator.deregisterOperator(quorumNumbers); cheats.stopPrank(); - isOperatorRegistered = avsDirectory.isMember(operatorToDeregister, IAVSDirectory.OperatorSet({ + isOperatorRegistered = avsDirectory.isMember(operatorToDeregister, OperatorSet({ avs: address(serviceManager), operatorSetId: defaultQuorumNumber })); @@ -386,7 +392,7 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas AVSDirectoryHarness(address(avsDirectory)).setAvsOperatorStatus( address(serviceManager), operatorAddress, - IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED + IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED ); } } @@ -413,7 +419,7 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas uint256 operatorPk = uint256(keccak256("operator to register")); address operatorToRegister = vm.addr(operatorPk) ; - bool isOperatorRegistered = avsDirectory.isMember(operatorToRegister, IAVSDirectory.OperatorSet({ + bool isOperatorRegistered = avsDirectory.isMember(operatorToRegister, OperatorSet({ avs: address(serviceManager), operatorSetId: defaultQuorumNumber })); @@ -453,7 +459,7 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas registryCoordinator.registerOperator(quorumNumbers, "", params, operatorSignature); cheats.stopPrank(); - isOperatorRegistered = avsDirectory.isMember(operatorToRegister, IAVSDirectory.OperatorSet({ + isOperatorRegistered = avsDirectory.isMember(operatorToRegister, OperatorSet({ avs: address(serviceManager), operatorSetId: defaultQuorumNumber })); diff --git a/test/unit/ServiceManagerBase.t.sol b/test/unit/ServiceManagerBase.t.sol index eba791c3..1d333814 100644 --- a/test/unit/ServiceManagerBase.t.sol +++ b/test/unit/ServiceManagerBase.t.sol @@ -5,9 +5,11 @@ import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; import { RewardsCoordinator, IRewardsCoordinator, + IRewardsCoordinatorTypes, IERC20 } from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; import {StrategyBase} from "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; +import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; import {IServiceManagerBaseEvents} from "../events/IServiceManagerBaseEvents.sol"; import "../utils/MockAVSDeployer.sol"; @@ -53,15 +55,12 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve // Deploy rewards coordinator rewardsCoordinatorImplementation = new RewardsCoordinator( delegationMock, - strategyManagerMock, - avsDirectoryMock, + IStrategyManager(address(strategyManagerMock)), CALCULATION_INTERVAL_SECONDS, MAX_REWARDS_DURATION, MAX_RETROACTIVE_LENGTH, MAX_FUTURE_LENGTH, - GENESIS_REWARDS_TIMESTAMP, - OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP, - OPERATOR_SET_MAX_RETROACTIVE_LENGTH + GENESIS_REWARDS_TIMESTAMP ); rewardsCoordinator = RewardsCoordinator( @@ -86,7 +85,8 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve avsDirectory, rewardsCoordinator, registryCoordinatorImplementation, - stakeRegistryImplementation + stakeRegistryImplementation, + allocationManagerImplementation ); serviceManager = ServiceManagerMock( @@ -146,7 +146,7 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve IERC20 token3 = new ERC20PresetFixedSupply( "pepe wif avs", "MOCK3", mockTokenInitialSupply, address(this) ); - strategyImplementation = new StrategyBase(strategyManagerMock); + strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock))); strategyMock1 = StrategyBase( address( new TransparentUpgradeableProxy( @@ -185,13 +185,13 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve strategyManagerMock.setStrategyWhitelist(strategies[2], true); defaultStrategyAndMultipliers.push( - IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[0])), 1e18) + IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[0])), 1e18) ); defaultStrategyAndMultipliers.push( - IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[1])), 2e18) + IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[1])), 2e18) ); defaultStrategyAndMultipliers.push( - IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[2])), 3e18) + IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[2])), 3e18) ); } @@ -233,9 +233,9 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve "dog wif hat", "MOCK1", mockTokenInitialSupply, rewardsInitiator ); - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = - new IRewardsCoordinator.RewardsSubmission[](1); - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = + new IRewardsCoordinatorTypes.RewardsSubmission[](1); + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: token, amount: 100, @@ -272,9 +272,9 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create reward submission input param - IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions = - new IRewardsCoordinator.RewardsSubmission[](1); - rewardsSubmissions[0] = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission[] memory rewardsSubmissions = + new IRewardsCoordinatorTypes.RewardsSubmission[](1); + rewardsSubmissions[0] = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardToken, amount: amount, @@ -365,7 +365,7 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create reward submission input param - IRewardsCoordinator.RewardsSubmission memory rewardsSubmission = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission memory rewardsSubmission = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardTokens[i], amount: amounts[i], @@ -463,7 +463,7 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create reward submission input param - IRewardsCoordinator.RewardsSubmission memory rewardsSubmission = IRewardsCoordinator.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission memory rewardsSubmission = IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardToken, amount: amounts[i], diff --git a/test/unit/ServiceManagerMigration.t.sol b/test/unit/ServiceManagerMigration.t.sol index 69cd4c7c..67350529 100644 --- a/test/unit/ServiceManagerMigration.t.sol +++ b/test/unit/ServiceManagerMigration.t.sol @@ -5,11 +5,15 @@ import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; import { RewardsCoordinator, IRewardsCoordinator, + IRewardsCoordinatorTypes, IERC20 } from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; import {StrategyBase} from "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; import {IServiceManagerBaseEvents} from "../events/IServiceManagerBaseEvents.sol"; +import {IAVSDirectoryTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; import {AVSDirectoryHarness} from "../harnesses/AVSDirectoryHarness.sol"; +import {OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import "../utils/MockAVSDeployer.sol"; @@ -59,15 +63,12 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa // Deploy rewards coordinator rewardsCoordinatorImplementation = new RewardsCoordinator( delegationMock, - strategyManagerMock, - avsDirectoryMock, + IStrategyManager(address(strategyManagerMock)), CALCULATION_INTERVAL_SECONDS, MAX_REWARDS_DURATION, MAX_RETROACTIVE_LENGTH, MAX_FUTURE_LENGTH, - GENESIS_REWARDS_TIMESTAMP, - OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP, - OPERATOR_SET_MAX_RETROACTIVE_LENGTH + GENESIS_REWARDS_TIMESTAMP ); rewardsCoordinator = RewardsCoordinator( @@ -89,7 +90,7 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa ); // Deploy ServiceManager serviceManagerImplementation = new ServiceManagerMock( - avsDirectory, rewardsCoordinator, registryCoordinator, stakeRegistry + avsDirectory, rewardsCoordinator, registryCoordinator, stakeRegistry, allocationManager ); serviceManager = ServiceManagerMock( @@ -126,7 +127,7 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa IERC20 token3 = new ERC20PresetFixedSupply( "pepe wif avs", "MOCK3", mockTokenInitialSupply, address(this) ); - strategyImplementation = new StrategyBase(strategyManagerMock); + strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock))); strategyMock1 = StrategyBase( address( new TransparentUpgradeableProxy( @@ -165,13 +166,13 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa strategyManagerMock.setStrategyWhitelist(strategies[2], true); defaultStrategyAndMultipliers.push( - IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[0])), 1e18) + IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[0])), 1e18) ); defaultStrategyAndMultipliers.push( - IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[1])), 2e18) + IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[1])), 2e18) ); defaultStrategyAndMultipliers.push( - IRewardsCoordinator.StrategyAndMultiplier(IStrategy(address(strategies[2])), 3e18) + IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[2])), 3e18) ); } @@ -320,7 +321,7 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa AVSDirectoryHarness(address(avsDirectory)).setAvsOperatorStatus( address(serviceManager), operatorAddress, - IAVSDirectory.OperatorAVSRegistrationStatus.REGISTERED + IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED ); } } @@ -339,7 +340,7 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa assertTrue( avsDirectory.isMember( 0x73e2Ce949f15Be901f76b54F5a4554A6C8DCf539, - IAVSDirectory.OperatorSet(address(serviceManager), uint32(3)) + OperatorSet(address(serviceManager), uint32(3)) ), "Operator not migrated to operator set" ); diff --git a/test/unit/ServiceManagerRouter.t.sol b/test/unit/ServiceManagerRouter.t.sol index 9fc2c0f7..6706ade4 100644 --- a/test/unit/ServiceManagerRouter.t.sol +++ b/test/unit/ServiceManagerRouter.t.sol @@ -19,7 +19,8 @@ contract ServiceManagerRouter_UnitTests is MockAVSDeployer { avsDirectory, rewardsCoordinatorImplementation, registryCoordinatorImplementation, - stakeRegistryImplementation + stakeRegistryImplementation, + allocationManagerImplementation ); _registerOperatorWithCoordinator(defaultOperator, MAX_QUORUM_BITMAP, defaultPubKey); diff --git a/test/utils/MockAVSDeployer.sol b/test/utils/MockAVSDeployer.sol index b06364a8..af8ebe78 100644 --- a/test/utils/MockAVSDeployer.sol +++ b/test/utils/MockAVSDeployer.sol @@ -4,8 +4,6 @@ pragma solidity ^0.8.12; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -import {Slasher} from "eigenlayer-contracts/src/contracts/core/Slasher.sol"; -import {ISlasher} from "eigenlayer-contracts/src/contracts/interfaces/ISlasher.sol"; import {PauserRegistry} from "eigenlayer-contracts/src/contracts/permissions/PauserRegistry.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; @@ -26,8 +24,9 @@ import {IRegistryCoordinator} from "../../src/interfaces/IRegistryCoordinator.so import {IServiceManager} from "../../src/interfaces/IServiceManager.sol"; import {StrategyManagerMock} from "eigenlayer-contracts/src/test/mocks/StrategyManagerMock.sol"; -import {EigenPodManagerMock} from "eigenlayer-contracts/src/test/mocks/EigenPodManagerMock.sol"; +import {EigenPodManagerMock} from "../mocks/EigenPodManagerMock.sol"; import {AVSDirectoryMock} from "../mocks/AVSDirectoryMock.sol"; +import {AllocationManagerMock} from "../mocks/AllocationManagerMock.sol"; import {DelegationMock} from "../mocks/DelegationMock.sol"; import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; @@ -53,9 +52,6 @@ contract MockAVSDeployer is Test { ProxyAdmin public proxyAdmin; PauserRegistry public pauserRegistry; - ISlasher public slasher = ISlasher(address(uint160(uint256(keccak256("slasher"))))); - Slasher public slasherImplementation; - EmptyContract public emptyContract; RegistryCoordinatorHarness public registryCoordinatorImplementation; @@ -63,6 +59,7 @@ contract MockAVSDeployer is Test { IBLSApkRegistry public blsApkRegistryImplementation; IIndexRegistry public indexRegistryImplementation; ServiceManagerMock public serviceManagerImplementation; + AllocationManagerMock public allocationManagerImplementation; OperatorStateRetriever public operatorStateRetriever; RegistryCoordinatorHarness public registryCoordinator; @@ -70,6 +67,7 @@ contract MockAVSDeployer is Test { BLSApkRegistryHarness public blsApkRegistry; IIndexRegistry public indexRegistry; ServiceManagerMock public serviceManager; + AllocationManagerMock public allocationManager; StrategyManagerMock public strategyManagerMock; DelegationMock public delegationMock; @@ -77,6 +75,7 @@ contract MockAVSDeployer is Test { AVSDirectory public avsDirectory; AVSDirectory public avsDirectoryImplementation; AVSDirectoryMock public avsDirectoryMock; + AllocationManagerMock public allocationManagerMock; RewardsCoordinator public rewardsCoordinator; RewardsCoordinator public rewardsCoordinatorImplementation; RewardsCoordinatorMock public rewardsCoordinatorMock; @@ -150,23 +149,10 @@ contract MockAVSDeployer is Test { avsDirectoryMock = new AVSDirectoryMock(); eigenPodManagerMock = new EigenPodManagerMock(pauserRegistry); strategyManagerMock = new StrategyManagerMock(); - slasherImplementation = new Slasher(strategyManagerMock, delegationMock); - slasher = Slasher( - address( - new TransparentUpgradeableProxy( - address(slasherImplementation), - address(proxyAdmin), - abi.encodeWithSelector( - Slasher.initialize.selector, - msg.sender, - pauserRegistry, - 0 /*initialPausedStatus*/ - ) - ) - ) - ); + allocationManagerMock = new AllocationManagerMock(); avsDirectoryMock = new AVSDirectoryMock(); - avsDirectoryImplementation = new AVSDirectory(delegationMock); + allocationManagerMock = new AllocationManagerMock(); + avsDirectoryImplementation = new AVSDirectory(delegationMock, 0); // TODO: config value avsDirectory = AVSDirectory( address( new TransparentUpgradeableProxy( @@ -183,7 +169,7 @@ contract MockAVSDeployer is Test { ); rewardsCoordinatorMock = new RewardsCoordinatorMock(); - strategyManagerMock.setAddresses(delegationMock, eigenPodManagerMock, slasher); + strategyManagerMock.setDelegationManager(delegationMock); cheats.stopPrank(); cheats.startPrank(registryCoordinatorOwner); @@ -217,6 +203,12 @@ contract MockAVSDeployer is Test { ) ); + allocationManager = AllocationManagerMock( + address( + new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") + ) + ); + cheats.stopPrank(); cheats.startPrank(proxyAdminOwner); @@ -247,7 +239,8 @@ contract MockAVSDeployer is Test { avsDirectoryMock, IRewardsCoordinator(address(rewardsCoordinatorMock)), registryCoordinator, - stakeRegistry + stakeRegistry, + allocationManager ); proxyAdmin.upgrade( @@ -255,9 +248,17 @@ contract MockAVSDeployer is Test { address(serviceManagerImplementation) ); + allocationManagerImplementation = new AllocationManagerMock(); + + proxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(allocationManager))), + address(allocationManagerImplementation) + ); + serviceManager.initialize({ initialOwner: registryCoordinatorOwner, - rewardsInitiator: address(proxyAdminOwner) + rewardsInitiator: proxyAdminOwner, + slasher: proxyAdminOwner }); // set the public key for an operator, using harnessed function to bypass checks From cb4df12b8a59ad9f5f437f12c0ceae51581bbbda Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Fri, 1 Nov 2024 11:59:28 -0400 Subject: [PATCH 19/52] feat: slasher templates / examples (#310) * chore: bump to slashing branch * chore: bump compiler version * fix: dep interface changes * fix: compiler errors from interface changes and type changes * fix: compiler errors * chore: bump dependencies * chore: bump core dependency and resolve issues * chore: bump core dependency and fix compiler errors * feat: integrate AllocationManager * feat: add a slashing permission to the service manager * chore: remove unneeded casting * feat: implement a slasher permission and forward call to AllocationManager * feat: add simiple slasher starting point * feat: slashers * chore: change around slashed event * fix: call dm * feat: add proposal mechanism for updating slasher * fix: set to completed instead of delete * chore: use struct instead of params directly * chore: clean up params more * chore: simplify and organize files * chore: cleanup logic and couple event with internal func * fix: pass correct params * chore: organize and add interface * chore: nits * chore: cleanup more nits * fix: storage gap * chore: nits refactor * chore: go back to fulfill being onlySlasher * test: fixes from core updates * fix: use delegated stake per operator set instead of per AVS * fix: update to 14 days * feat: configurable lookahead and stake type --- src/ServiceManagerBase.sol | 32 ++++++++-- src/ServiceManagerBaseStorage.sol | 9 ++- src/StakeRegistry.sol | 44 +++++++++++-- src/StakeRegistryStorage.sol | 5 +- src/interfaces/IServiceManager.sol | 2 + src/interfaces/IServiceManagerUI.sol | 3 + src/interfaces/ISlasher.sol | 45 +++++++++++++ src/interfaces/IStakeRegistry.sol | 13 ++++ src/slashers/InstantSlasher.sol | 22 +++++++ src/slashers/SimpleSlasher.sol | 33 ---------- src/slashers/SlasherStorage.sol | 8 --- src/slashers/VetoableSlasher.sol | 77 +++++++++++++++++++++++ src/slashers/base/SlasherBase.sol | 37 +++++++++++ src/slashers/base/SlasherStorage.sol | 11 ++++ src/unaudited/ECDSAServiceManagerBase.sol | 7 ++- src/unaudited/ECDSAStakeRegistry.sol | 10 ++- test/mocks/AVSDirectoryMock.sol | 2 +- test/mocks/ECDSAServiceManagerMock.sol | 6 +- test/mocks/RewardsCoordinatorMock.sol | 2 +- test/unit/ECDSAServiceManager.t.sol | 7 ++- test/unit/RegistryCoordinatorUnit.t.sol | 10 +-- test/unit/ServiceManagerBase.t.sol | 2 +- test/unit/ServiceManagerMigration.t.sol | 2 +- 23 files changed, 319 insertions(+), 70 deletions(-) create mode 100644 src/interfaces/ISlasher.sol create mode 100644 src/slashers/InstantSlasher.sol delete mode 100644 src/slashers/SimpleSlasher.sol delete mode 100644 src/slashers/SlasherStorage.sol create mode 100644 src/slashers/VetoableSlasher.sol create mode 100644 src/slashers/base/SlasherBase.sol create mode 100644 src/slashers/base/SlasherStorage.sol diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index 47ac07f1..74d47510 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -14,7 +14,6 @@ import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; import {BitmapUtils} from "./libraries/BitmapUtils.sol"; import {LibMergeSort} from "./libraries/LibMergeSort.sol"; -import {console} from "forge-std/Test.sol"; /** * @title Minimal implementation of a ServiceManager-type contract. @@ -24,6 +23,8 @@ import {console} from "forge-std/Test.sol"; abstract contract ServiceManagerBase is ServiceManagerBaseStorage { using BitmapUtils for *; + uint256 public constant SLASHER_PROPOSAL_DELAY = 7 days; + /// @notice when applied to a function, only allows the RegistryCoordinator to call it modifier onlyRegistryCoordinator() { require( @@ -177,12 +178,25 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { } /** - * @notice Sets the slasher address + * @notice Proposes a new slasher address * @param newSlasher The new slasher address * @dev only callable by the owner */ - function setSlasher(address newSlasher) external onlyOwner { - _setSlasher(newSlasher); + function proposeNewSlasher(address newSlasher) external onlyOwner { + _proposeNewSlasher(newSlasher); + } + + /** + * @notice Accepts the proposed slasher address after the delay period + * @dev only callable by the owner + */ + function acceptProposedSlasher() external onlyOwner { + require( + block.timestamp >= slasherProposalTimestamp + SLASHER_PROPOSAL_DELAY, + "ServiceManager: Slasher proposal delay not met" + ); + _setSlasher(proposedSlasher); + delete proposedSlasher; } /** @@ -342,6 +356,12 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { rewardsInitiator = newRewardsInitiator; } + function _proposeNewSlasher(address newSlasher) internal { + proposedSlasher = newSlasher; + slasherProposalTimestamp = block.timestamp; + emit SlasherProposed(newSlasher, slasherProposalTimestamp); + } + function _setSlasher(address newSlasher) internal { emit SlasherUpdated(slasher, newSlasher); slasher = newSlasher; @@ -425,6 +445,10 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { return address(_avsDirectory); } + function allocationManager() external view override returns (address) { + return address(_allocationManager); + } + function _checkRewardsInitiator() internal view { require( msg.sender == rewardsInitiator, diff --git a/src/ServiceManagerBaseStorage.sol b/src/ServiceManagerBaseStorage.sol index 71d54d98..0bc52090 100644 --- a/src/ServiceManagerBaseStorage.sol +++ b/src/ServiceManagerBaseStorage.sol @@ -40,6 +40,13 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab /// @notice The address of the slasher account address public slasher; + /// @notice The address of the proposed slasher account + address public proposedSlasher; + + /// @notice The timestamp when the slasher was proposed + uint256 public slasherProposalTimestamp; + + /// @notice Boolean indicating if the migration has been finalized bool public migrationFinalized; /// @notice Sets the (immutable) `_avsDirectory`, `_rewardsCoordinator`, `_registryCoordinator`, `_stakeRegistry`, and `_allocationManager` addresses @@ -58,5 +65,5 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab } // storage gap for upgradeability - uint256[48] private __GAP; + uint256[46] private __GAP; } diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index 9d4da097..e1e4e449 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.12; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IAVSDirectory, OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {StakeRegistryStorage, IStrategy} from "./StakeRegistryStorage.sol"; @@ -229,6 +230,18 @@ contract StakeRegistry is StakeRegistryStorage { _setMinimumStakeForQuorum(quorumNumber, minimumStake); } + /** + * @notice Sets the stake type for the registry + * @param _stakeType The type of stake to track (TOTAL_DELEGATED, TOTAL_SLASHABLE, or BOTH) + */ + function setStakeType(StakeType _stakeType) external onlyCoordinatorOwner { + _setStakeType(_stakeType); + } + + + function setSlashableStakeLookahead(uint32 _lookAheadPeriod) external onlyCoordinatorOwner { + _setLookAheadPeriod(_lookAheadPeriod); + } /** * @notice Adds strategies and weights to the quorum * @dev Checks to make sure that the *same* strategy cannot be added multiple times (checks against both against existing and new strategies). @@ -491,15 +504,17 @@ contract StakeRegistry is StakeRegistryStorage { uint256 stratsLength = strategyParamsLength(quorumNumber); StrategyParams memory strategyAndMultiplier; - uint256[] memory strategyShares; - // = delegation.getDelegatableShares(operator, strategiesPerQuorum[quorumNumber]); + address[] memory operators = new address[](1); + operators[0] = operator; + uint32 beforeTimestamp = uint32(block.timestamp + slashableStakeLookAhead); + (uint256[][] memory strategyShares, ) = IAllocationManager(serviceManager.allocationManager()).getMinDelegatedAndSlashableOperatorShares(OperatorSet(address(serviceManager), quorumNumber), operators ,strategiesPerQuorum[quorumNumber], beforeTimestamp); for (uint256 i = 0; i < stratsLength; i++) { // accessing i^th StrategyParams struct for the quorumNumber strategyAndMultiplier = strategyParams[quorumNumber][i]; // add the weight from the shares for this strategy to the total weight - if (strategyShares[i] > 0) { - weight += uint96(strategyShares[i] * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR); + if (strategyShares[i][0] > 0) { + weight += uint96(strategyShares[i][0] * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR); } } @@ -731,6 +746,27 @@ contract StakeRegistry is StakeRegistryStorage { return indices; } + /** + * @notice Sets the stake type for the registry + * @param _stakeType The type of stake to track (TOTAL_DELEGATED, TOTAL_SLASHABLE, or BOTH) + */ + function _setStakeType(StakeType _stakeType) internal { + StakeType oldStakeType = stakeType; + stakeType = _stakeType; + emit StakeTypeSet(oldStakeType, _stakeType); + } + + /** + * @notice Sets the look ahead time for checking operator shares + * @param _lookAheadDays The number of days to look ahead when checking shares + */ + function _setLookAheadPeriod(uint32 _lookAheadDays) internal { + uint32 oldLookAheadDays = slashableStakeLookAhead; + slashableStakeLookAhead = _lookAheadDays; + emit LookAheadPeriodChanged(oldLookAheadDays, _lookAheadDays); + } + + function _checkRegistryCoordinator() internal view { require( msg.sender == address(registryCoordinator), diff --git a/src/StakeRegistryStorage.sol b/src/StakeRegistryStorage.sol index f76608d2..7fea4fa2 100644 --- a/src/StakeRegistryStorage.sol +++ b/src/StakeRegistryStorage.sol @@ -52,6 +52,9 @@ abstract contract StakeRegistryStorage is IStakeRegistry { mapping(uint8 => StrategyParams[]) public strategyParams; mapping(uint8 => IStrategy[]) public strategiesPerQuorum; + StakeType public stakeType; + + uint32 public slashableStakeLookAhead; constructor( IRegistryCoordinator _registryCoordinator, @@ -67,5 +70,5 @@ abstract contract StakeRegistryStorage is IStakeRegistry { // storage gap for upgradeability // slither-disable-next-line shadowing-state - uint256[45] private __GAP; + uint256[44] private __GAP; } diff --git a/src/interfaces/IServiceManager.sol b/src/interfaces/IServiceManager.sol index 5057525e..6c2bcf94 100644 --- a/src/interfaces/IServiceManager.sol +++ b/src/interfaces/IServiceManager.sol @@ -5,6 +5,7 @@ import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces import {IServiceManagerUI} from "./IServiceManagerUI.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; /** * @title Minimal interface for a ServiceManager-type contract that forms the single point for an AVS to push updates to EigenLayer @@ -50,4 +51,5 @@ interface IServiceManager is IServiceManagerUI { // EVENTS event RewardsInitiatorUpdated(address prevRewardsInitiator, address newRewardsInitiator); event SlasherUpdated(address prevSlasher, address newSlasher); + event SlasherProposed(address newSlasher, uint256 slasherProposalTimestamp); } diff --git a/src/interfaces/IServiceManagerUI.sol b/src/interfaces/IServiceManagerUI.sol index 92cdce9c..7be5a3f0 100644 --- a/src/interfaces/IServiceManagerUI.sol +++ b/src/interfaces/IServiceManagerUI.sol @@ -58,4 +58,7 @@ interface IServiceManagerUI { /// @notice Returns the EigenLayer AVSDirectory contract. function avsDirectory() external view returns (address); + + /// @notice Returns the EigenLayer AllocationManager contract. + function allocationManager() external view returns (address); } diff --git a/src/interfaces/ISlasher.sol b/src/interfaces/ISlasher.sol new file mode 100644 index 00000000..e2d128f1 --- /dev/null +++ b/src/interfaces/ISlasher.sol @@ -0,0 +1,45 @@ + +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; +import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; + +interface ISlasherEvents { + event SlashingRequested( + uint256 indexed requestId, + address indexed operator, + uint32 indexed operatorSetId, + uint256 wadToSlash, + string description + ); + + event SlashingRequestCancelled(uint256 indexed requestId); + + event OperatorSlashed( + uint256 indexed slashingRequestId, + address indexed operator, + uint32 indexed operatorSetId, + IStrategy[] strategies, + uint256 wadToSlash, + string description + ); +} + +interface ISlasherTypes { + enum SlashingStatus { + Null, + Requested, + Completed, + Cancelled + } + + struct SlashingRequest { + IAllocationManager.SlashingParams params; + uint256 requestTimestamp; + SlashingStatus status; + } + +} + +interface ISlasher is ISlasherEvents, ISlasherTypes{} diff --git a/src/interfaces/IStakeRegistry.sol b/src/interfaces/IStakeRegistry.sol index 044ccd58..c4ebd195 100644 --- a/src/interfaces/IStakeRegistry.sol +++ b/src/interfaces/IStakeRegistry.sol @@ -11,6 +11,12 @@ import {IRegistry} from "./IRegistry.sol"; * @author Layr Labs, Inc. */ interface IStakeRegistry is IRegistry { + + enum StakeType { + TOTAL_DELEGATED, + TOTAL_SLASHABLE, + BOTH + } // DATA STRUCTURES @@ -42,6 +48,13 @@ interface IStakeRegistry is IRegistry { uint8 quorumNumber, uint96 stake ); + + + /// @notice emitted when the look ahead time for checking operator shares is updated + event LookAheadPeriodChanged(uint32 oldLookAheadDays, uint32 newLookAheadDays); + + /// @notice emitted when the stake type is updated + event StakeTypeSet(StakeType previousStakeType, StakeType newStakeType); /// @notice emitted when the minimum stake for a quorum is updated event MinimumStakeForQuorumUpdated(uint8 indexed quorumNumber, uint96 minimumStake); /// @notice emitted when a new quorum is created diff --git a/src/slashers/InstantSlasher.sol b/src/slashers/InstantSlasher.sol new file mode 100644 index 00000000..b30d5881 --- /dev/null +++ b/src/slashers/InstantSlasher.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; +import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {SlasherBase} from "./base/SlasherBase.sol"; + +contract InstantSlasher is SlasherBase { + + function initialize(address _serviceManager, address _slasher) external initializer { + __SlasherBase_init(_serviceManager, _slasher); + } + + function fulfillSlashingRequest( + IAllocationManager.SlashingParams memory _slashingParams + ) external virtual onlySlasher { + uint256 requestId = nextRequestId++; + _fulfillSlashingRequest(requestId, _slashingParams); + } + + +} \ No newline at end of file diff --git a/src/slashers/SimpleSlasher.sol b/src/slashers/SimpleSlasher.sol deleted file mode 100644 index faa4f49b..00000000 --- a/src/slashers/SimpleSlasher.sol +++ /dev/null @@ -1,33 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; -import {IServiceManager} from "../interfaces/IServiceManager.sol"; -import {SlasherStorage} from "./SlasherStorage.sol"; -import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; - -contract SimpleSlasher is Initializable, SlasherStorage { - function initialize(address _serviceManager) public initializer { - serviceManager = _serviceManager; - } - - function slashOperator( - address operator, - uint32 operatorSetId, - IStrategy[] memory strategies, - uint256 wadToSlash, - string memory description - ) external { - - IAllocationManagerTypes.SlashingParams memory params = IAllocationManagerTypes.SlashingParams({ - operator: operator, - operatorSetId: operatorSetId, - strategies: strategies, - wadToSlash: wadToSlash, - description: description - }); - - IServiceManager(serviceManager).slashOperator(params); - } -} diff --git a/src/slashers/SlasherStorage.sol b/src/slashers/SlasherStorage.sol deleted file mode 100644 index 1b3d61de..00000000 --- a/src/slashers/SlasherStorage.sol +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -contract SlasherStorage { - address public serviceManager; - - uint256[49] private __gap; -} \ No newline at end of file diff --git a/src/slashers/VetoableSlasher.sol b/src/slashers/VetoableSlasher.sol new file mode 100644 index 00000000..b65442b6 --- /dev/null +++ b/src/slashers/VetoableSlasher.sol @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; +import {SlasherBase} from "./base/SlasherBase.sol"; +import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; + +contract VetoableSlashing is SlasherBase { + uint256 public constant VETO_PERIOD = 3 days; + address public vetoCommittee; + + mapping(uint256 => SlashingRequest) public slashingRequests; + + modifier onlyVetoCommittee() { + _checkVetoCommittee(msg.sender); + _; + } + + function initialize( + address _serviceManager, + address _vetoCommittee, + address _slasher + ) external virtual initializer { + __SlasherBase_init(_serviceManager, _slasher); + vetoCommittee = _vetoCommittee; + } + + function queueSlashingRequest(IAllocationManager.SlashingParams memory params) external virtual onlySlasher { + _queueSlashingRequest(params); + } + + function cancelSlashingRequest(uint256 requestId) external virtual onlyVetoCommittee { + require( + block.timestamp < slashingRequests[requestId].requestTimestamp + VETO_PERIOD, + "VetoableSlashing: veto period has passed" + ); + require(slashingRequests[requestId].status == SlashingStatus.Requested, "VetoableSlashing: request is not in Requested status"); + + _cancelSlashingRequest(requestId); + } + + function fulfillSlashingRequest(uint256 requestId) external virtual onlySlasher { + SlashingRequest storage request = slashingRequests[requestId]; + require( + block.timestamp >= request.requestTimestamp + VETO_PERIOD, + "VetoableSlashing: veto period has not passed" + ); + require(request.status == SlashingStatus.Requested, "VetoableSlashing: request has been cancelled"); + + request.status = SlashingStatus.Completed; + + _fulfillSlashingRequest( + requestId, + request.params + ); + } + + function _queueSlashingRequest(IAllocationManager.SlashingParams memory params) internal virtual { + uint256 requestId = nextRequestId++; + slashingRequests[requestId] = SlashingRequest({ + params: params, + requestTimestamp: block.timestamp, + status: SlashingStatus.Requested + }); + + emit SlashingRequested(requestId, params.operator, params.operatorSetId, params.wadToSlash, params.description); + } + + function _cancelSlashingRequest(uint256 requestId) internal virtual { + slashingRequests[requestId].status = SlashingStatus.Cancelled; + emit SlashingRequestCancelled(requestId); + } + + function _checkVetoCommittee(address account) internal view virtual { + require(account == vetoCommittee, "VetoableSlashing: caller is not the veto committee"); + } +} \ No newline at end of file diff --git a/src/slashers/base/SlasherBase.sol b/src/slashers/base/SlasherBase.sol new file mode 100644 index 00000000..c62513d3 --- /dev/null +++ b/src/slashers/base/SlasherBase.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; +import {IServiceManager} from "../../interfaces/IServiceManager.sol"; +import {SlasherStorage} from "./SlasherStorage.sol"; +import {IAllocationManagerTypes, IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; + +abstract contract SlasherBase is Initializable, SlasherStorage { + + modifier onlySlasher() { + _checkSlasher(msg.sender); + _; + } + + function __SlasherBase_init(address _serviceManager, address _slasher) internal onlyInitializing { + serviceManager = _serviceManager; + slasher = _slasher; + } + + function _fulfillSlashingRequest( + uint256 _requestId, + IAllocationManager.SlashingParams memory _params + ) internal virtual { + IServiceManager(serviceManager).slashOperator(_params); + emit OperatorSlashed(_requestId, _params.operator, _params.operatorSetId, _params.strategies, _params.wadToSlash, _params.description); + } + + function _checkSlasher(address account) internal view virtual { + require(account == slasher, "InstantSlasher: caller is not the slasher"); + } +} + + + + diff --git a/src/slashers/base/SlasherStorage.sol b/src/slashers/base/SlasherStorage.sol new file mode 100644 index 00000000..1024811a --- /dev/null +++ b/src/slashers/base/SlasherStorage.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import {ISlasher} from "../../interfaces/ISlasher.sol"; +contract SlasherStorage is ISlasher { + address public serviceManager; + address public slasher; + uint256 public nextRequestId; + + uint256[47] private __gap; +} \ No newline at end of file diff --git a/src/unaudited/ECDSAServiceManagerBase.sol b/src/unaudited/ECDSAServiceManagerBase.sol index 3d30f451..facb6813 100644 --- a/src/unaudited/ECDSAServiceManagerBase.sol +++ b/src/unaudited/ECDSAServiceManagerBase.sol @@ -23,6 +23,9 @@ abstract contract ECDSAServiceManagerBase is /// @notice Address of the AVS directory contract, which manages AVS-related data for registered operators. address public immutable avsDirectory; + /// @notice Address of the AllocationManager contract + address public immutable allocationManager; + /// @notice Address of the rewards coordinator contract, which handles rewards distributions. address internal immutable rewardsCoordinator; @@ -70,12 +73,14 @@ abstract contract ECDSAServiceManagerBase is address _avsDirectory, address _stakeRegistry, address _rewardsCoordinator, - address _delegationManager + address _delegationManager, + address _allocationManager ) { avsDirectory = _avsDirectory; stakeRegistry = _stakeRegistry; rewardsCoordinator = _rewardsCoordinator; delegationManager = _delegationManager; + allocationManager = _allocationManager; _disableInitializers(); } diff --git a/src/unaudited/ECDSAStakeRegistry.sol b/src/unaudited/ECDSAStakeRegistry.sol index a8dff79a..b333d504 100644 --- a/src/unaudited/ECDSAStakeRegistry.sol +++ b/src/unaudited/ECDSAStakeRegistry.sol @@ -248,12 +248,10 @@ contract ECDSAStakeRegistry is for (uint256 i; i < strategyParams.length; i++) { strategies[i] = strategyParams[i].strategy; } - uint256[] memory shares; - /// TODO: FIX - // = DELEGATION_MANAGER.getOperatorShares( - // _operator, - // strategies - // ); + uint256[] memory shares = DELEGATION_MANAGER.getOperatorShares( + _operator, + strategies + ); for (uint256 i; i < strategyParams.length; i++) { weight += shares[i] * strategyParams[i].multiplier; } diff --git a/test/mocks/AVSDirectoryMock.sol b/test/mocks/AVSDirectoryMock.sol index a6bf2a3c..597a09a1 100644 --- a/test/mocks/AVSDirectoryMock.sol +++ b/test/mocks/AVSDirectoryMock.sol @@ -170,4 +170,4 @@ contract AVSDirectoryMock is IAVSDirectory { ) external {} function addStrategiesToOperatorSet(uint32 operatorSetId, IStrategy[] calldata strategies) external {} -} \ No newline at end of file +} diff --git a/test/mocks/ECDSAServiceManagerMock.sol b/test/mocks/ECDSAServiceManagerMock.sol index 5be1d82d..2c3c872b 100644 --- a/test/mocks/ECDSAServiceManagerMock.sol +++ b/test/mocks/ECDSAServiceManagerMock.sol @@ -9,13 +9,15 @@ contract ECDSAServiceManagerMock is ECDSAServiceManagerBase { address _avsDirectory, address _stakeRegistry, address _rewardsCoordinator, - address _delegationManager + address _delegationManager, + address _allocationManager ) ECDSAServiceManagerBase( _avsDirectory, _stakeRegistry, _rewardsCoordinator, - _delegationManager + _delegationManager, + _allocationManager ) {} diff --git a/test/mocks/RewardsCoordinatorMock.sol b/test/mocks/RewardsCoordinatorMock.sol index cc8404a0..db403ac6 100644 --- a/test/mocks/RewardsCoordinatorMock.sol +++ b/test/mocks/RewardsCoordinatorMock.sol @@ -129,5 +129,5 @@ contract RewardsCoordinatorMock is IRewardsCoordinator { address _rewardsUpdater, uint32 _activationDelay, uint16 _globalCommissionBips - ) external override {} + ) external {} } \ No newline at end of file diff --git a/test/unit/ECDSAServiceManager.t.sol b/test/unit/ECDSAServiceManager.t.sol index 1093b77a..a20c6d00 100644 --- a/test/unit/ECDSAServiceManager.t.sol +++ b/test/unit/ECDSAServiceManager.t.sol @@ -40,6 +40,8 @@ contract MockAVSDirectory { function updateAVSMetadataURI(string memory) external pure {} } +contract MockAllocationManager {} + contract MockRewardsCoordinator { function createAVSRewardsSubmission( IRewardsCoordinator.RewardsSubmission[] calldata @@ -49,6 +51,7 @@ contract MockRewardsCoordinator { contract ECDSAServiceManagerSetup is Test { MockDelegationManager public mockDelegationManager; MockAVSDirectory public mockAVSDirectory; + MockAllocationManager public mockAllocationManager; ECDSAStakeRegistryMock public mockStakeRegistry; MockRewardsCoordinator public mockRewardsCoordinator; ECDSAServiceManagerMock public serviceManager; @@ -60,6 +63,7 @@ contract ECDSAServiceManagerSetup is Test { function setUp() public { mockDelegationManager = new MockDelegationManager(); mockAVSDirectory = new MockAVSDirectory(); + mockAllocationManager = new MockAllocationManager(); mockStakeRegistry = new ECDSAStakeRegistryMock( IDelegationManager(address(mockDelegationManager)) ); @@ -69,7 +73,8 @@ contract ECDSAServiceManagerSetup is Test { address(mockAVSDirectory), address(mockStakeRegistry), address(mockRewardsCoordinator), - address(mockDelegationManager) + address(mockDelegationManager), + address(mockAllocationManager) ); operator1Pk = 1; diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index 6ae55d59..4129b8cb 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -260,7 +260,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni registryCoordinator.pause(2 ** PAUSED_REGISTER_OPERATOR); cheats.startPrank(defaultOperator); - cheats.expectRevert(bytes("Pausable: index is paused")); + cheats.expectRevert(bytes4(keccak256("CurrentlyPaused()"))); registryCoordinator.registerOperator(emptyQuorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); } @@ -591,7 +591,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.prank(pauser); registryCoordinator.pause(2 ** PAUSED_DEREGISTER_OPERATOR); - cheats.expectRevert(bytes("Pausable: index is paused")); + cheats.expectRevert(bytes4(keccak256("CurrentlyPaused()"))); cheats.prank(defaultOperator); registryCoordinator.deregisterOperator(quorumNumbers); } @@ -1526,7 +1526,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord hex"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001B"; signatureWithSaltAndExpiry.salt = defaultSalt; cheats.prank(operatorToRegister); - cheats.expectRevert("ECDSA: invalid signature"); + cheats.expectRevert(bytes4(keccak256("InvalidSignature()"))); registryCoordinator.registerOperatorWithChurn( quorumNumbers, defaultSocket, @@ -1576,7 +1576,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit address[] memory operatorsToUpdate = new address[](1); operatorsToUpdate[0] = defaultOperator; - cheats.expectRevert(bytes("Pausable: index is paused")); + cheats.expectRevert(bytes4(keccak256("CurrentlyPaused()"))); registryCoordinator.updateOperators(operatorsToUpdate); } @@ -1657,7 +1657,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); - cheats.expectRevert(bytes("Pausable: index is paused")); + cheats.expectRevert(bytes4(keccak256("CurrentlyPaused()"))); registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); } diff --git a/test/unit/ServiceManagerBase.t.sol b/test/unit/ServiceManagerBase.t.sol index 1d333814..609e8d2b 100644 --- a/test/unit/ServiceManagerBase.t.sol +++ b/test/unit/ServiceManagerBase.t.sol @@ -95,7 +95,7 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve address(serviceManagerImplementation), address(proxyAdmin), abi.encodeWithSelector( - ServiceManagerMock.initialize.selector, msg.sender, msg.sender + ServiceManagerMock.initialize.selector, serviceManager.owner(), msg.sender, msg.sender ) ) ) diff --git a/test/unit/ServiceManagerMigration.t.sol b/test/unit/ServiceManagerMigration.t.sol index 67350529..5fd86846 100644 --- a/test/unit/ServiceManagerMigration.t.sol +++ b/test/unit/ServiceManagerMigration.t.sol @@ -99,7 +99,7 @@ contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBa address(serviceManagerImplementation), address(proxyAdmin), abi.encodeWithSelector( - ServiceManagerMock.initialize.selector, msg.sender, msg.sender + ServiceManagerMock.initialize.selector, serviceManager.owner(), msg.sender, msg.sender ) ) ) From 145bdaf311b6774c060a7fc9de87004171b28bac Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Mon, 18 Nov 2024 13:52:12 -0500 Subject: [PATCH 20/52] chore: remove unused test util contracts (#319) * feat: remove both option * chore: remove unused test util contracts * chore: remove diff --- src/interfaces/IStakeRegistry.sol | 26 +-- test/utils/Greeter.sol | 11 -- test/utils/GreeterProxiable.sol | 65 ------- test/utils/GreeterV2.sol | 14 -- test/utils/GreeterV2Proxiable.sol | 17 -- test/utils/NoInitializer.sol | 13 -- test/utils/ProxyTestContracts.sol | 9 - test/utils/UpgradeableProxyUtils.sol | 241 ------------------------- test/utils/UpgradeableProxyUtils.t.sol | 87 --------- test/utils/WithConstructor.sol | 19 -- 10 files changed, 13 insertions(+), 489 deletions(-) delete mode 100644 test/utils/Greeter.sol delete mode 100644 test/utils/GreeterProxiable.sol delete mode 100644 test/utils/GreeterV2.sol delete mode 100644 test/utils/GreeterV2Proxiable.sol delete mode 100644 test/utils/NoInitializer.sol delete mode 100644 test/utils/ProxyTestContracts.sol delete mode 100644 test/utils/UpgradeableProxyUtils.sol delete mode 100644 test/utils/UpgradeableProxyUtils.t.sol delete mode 100644 test/utils/WithConstructor.sol diff --git a/src/interfaces/IStakeRegistry.sol b/src/interfaces/IStakeRegistry.sol index c4ebd195..fde01379 100644 --- a/src/interfaces/IStakeRegistry.sol +++ b/src/interfaces/IStakeRegistry.sol @@ -12,12 +12,12 @@ import {IRegistry} from "./IRegistry.sol"; */ interface IStakeRegistry is IRegistry { - enum StakeType { - TOTAL_DELEGATED, - TOTAL_SLASHABLE, - BOTH - } - + enum StakeType { + TOTAL_DELEGATED, + TOTAL_SLASHABLE, + BOTH + } + // DATA STRUCTURES /// @notice struct used to store the stakes of an individual operator or the sum of all operators' stakes, for storage @@ -80,8 +80,8 @@ interface IStakeRegistry is IRegistry { * 4) the operator is not already registered */ function registerOperator( - address operator, - bytes32 operatorId, + address operator, + bytes32 operatorId, bytes memory quorumNumbers ) external returns (uint96[] memory, uint96[] memory); @@ -200,7 +200,7 @@ interface IStakeRegistry is IRegistry { /** * @notice Returns the stake weight corresponding to `operatorId` for quorum `quorumNumber`, at the - * `index`-th entry in the `operatorIdToStakeHistory[operatorId][quorumNumber]` array if the entry + * `index`-th entry in the `operatorIdToStakeHistory[operatorId][quorumNumber]` array if the entry * corresponds to the operator's stake at `blockNumber`. Reverts otherwise. * @param quorumNumber The quorum number to get the stake for. * @param operatorId The id of the operator of interest. @@ -215,8 +215,8 @@ interface IStakeRegistry is IRegistry { returns (uint96); /** - * @notice Returns the total stake weight for quorum `quorumNumber`, at the `index`-th entry in the - * `totalStakeHistory[quorumNumber]` array if the entry corresponds to the total stake at `blockNumber`. + * @notice Returns the total stake weight for quorum `quorumNumber`, at the `index`-th entry in the + * `totalStakeHistory[quorumNumber]` array if the entry corresponds to the total stake at `blockNumber`. * Reverts otherwise. * @param quorumNumber The quorum number to get the stake for. * @param index Array index for lookup, within the dynamic array `totalStakeHistory[quorumNumber]`. @@ -254,8 +254,8 @@ interface IStakeRegistry is IRegistry { * and should be deregistered. */ function updateOperatorStake( - address operator, - bytes32 operatorId, + address operator, + bytes32 operatorId, bytes calldata quorumNumbers ) external returns (uint192); } diff --git a/test/utils/Greeter.sol b/test/utils/Greeter.sol deleted file mode 100644 index 35948a85..00000000 --- a/test/utils/Greeter.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; - -contract Greeter { - string public greeting; - - function initialize(string memory _greeting) public { - greeting = _greeting; - } -} - diff --git a/test/utils/GreeterProxiable.sol b/test/utils/GreeterProxiable.sol deleted file mode 100644 index e6a6e17c..00000000 --- a/test/utils/GreeterProxiable.sol +++ /dev/null @@ -1,65 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; - -interface IERC1822Proxiable { - function proxiableUUID() external view returns (bytes32); -} - -contract Proxiable { - bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; - - string public constant UPGRADE_INTERFACE_VERSION = "5.0.0"; - - function upgradeToAndCall(address newImplementation, bytes calldata data) external { - try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { - if (slot != _IMPLEMENTATION_SLOT) { - revert("slot is unsupported as a uuid"); - } - _setImplementation(newImplementation); - if (data.length > 0) { - /** - * Note that using delegate call can make your implementation contract vulnerable if this function - * is not protected with the `onlyProxy` modifier. Again, this contract is for testing only, it is - * not safe for use in production. Instead, use the `UUPSUpgradeable` contract available in - * @openzeppelin/contracts-upgradeable - */ - /// @custom:oz-upgrades-unsafe-allow delegatecall - (bool success, ) = newImplementation.delegatecall(data); - require(success, "upgrade call reverted"); - } else { - _checkNonPayable(); - } - } catch { - revert("the implementation is not UUPS"); - } - } - - function proxiableUUID() external view virtual returns (bytes32) { - return _IMPLEMENTATION_SLOT; - } - - function _checkNonPayable() private { - if (msg.value > 0) { - revert("non-payable upgrade call"); - } - } - - function _setImplementation(address newImplementation) private { - bytes32 slot = _IMPLEMENTATION_SLOT; - // solhint-disable-next-line no-inline-assembly - assembly { - sstore(slot, newImplementation) - } - } -} - - -contract GreeterProxiable is Proxiable { - string public greeting; - - function initialize(string memory _greeting) public { - greeting = _greeting; - } -} - - diff --git a/test/utils/GreeterV2.sol b/test/utils/GreeterV2.sol deleted file mode 100644 index 15a2b9b8..00000000 --- a/test/utils/GreeterV2.sol +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; - -contract GreeterV2 { - string public greeting; - - function initialize(string memory _greeting) public { - greeting = _greeting; - } - - function resetGreeting() public { - greeting = "resetted"; - } -} diff --git a/test/utils/GreeterV2Proxiable.sol b/test/utils/GreeterV2Proxiable.sol deleted file mode 100644 index ca2d82c9..00000000 --- a/test/utils/GreeterV2Proxiable.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; - -import {Proxiable} from "./GreeterProxiable.sol"; - -contract GreeterV2Proxiable is Proxiable { - string public greeting; - - function initialize(string memory _greeting) public { - greeting = _greeting; - } - - function resetGreeting() public { - greeting = "resetted"; - } -} - diff --git a/test/utils/NoInitializer.sol b/test/utils/NoInitializer.sol deleted file mode 100644 index e70616ae..00000000 --- a/test/utils/NoInitializer.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; - -contract NoInitializer { - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - uint256 public immutable a; - - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(uint256 _a) { - a = _a; - } -} - diff --git a/test/utils/ProxyTestContracts.sol b/test/utils/ProxyTestContracts.sol deleted file mode 100644 index af2bc907..00000000 --- a/test/utils/ProxyTestContracts.sol +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; - -import {Greeter} from "./Greeter.sol"; -import {GreeterProxiable} from "./GreeterProxiable.sol"; -import {GreeterV2} from "./GreeterV2.sol"; -import {GreeterV2Proxiable} from "./GreeterV2Proxiable.sol"; -import {WithConstructor} from "./WithConstructor.sol"; -import {NoInitializer} from "./NoInitializer.sol"; diff --git a/test/utils/UpgradeableProxyUtils.sol b/test/utils/UpgradeableProxyUtils.sol deleted file mode 100644 index 6ce5471a..00000000 --- a/test/utils/UpgradeableProxyUtils.sol +++ /dev/null @@ -1,241 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; - -import {Vm} from "forge-std/Vm.sol"; -import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; -import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; -import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; -import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; - -/// Modified from the Openzeppelin foundry upgrades library -/// Modifications: -/// - Made compatible with OZ ^4.x releases -/// - Removed OZ Defender functionality -library UpgradeableProxyUtils { - address private constant CHEATCODE_ADDRESS = 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D; - - // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 - bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; - - /** - * @dev Storage slot with the address of the current implementation. - * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is - * validated in the constructor. - */ - bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; - - /** - * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. - * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. - */ - bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; - - /** - * @dev Storage slot with the admin of the contract. - * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is - * validated in the constructor. - */ - bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; - - Vm private constant vm = Vm(CHEATCODE_ADDRESS); - - /** - * @dev Deploys a transparent proxy using the given contract as the implementation. - * - * @param contractName Name of the contract to use as the implementation, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory - * @param initialOwner Address to set as the owner of the ProxyAdmin contract which gets deployed by the proxy - * @param initializerData Encoded call data of the initializer function to call during creation of the proxy, or empty if no initialization is required - * @return Proxy address - */ - function deployTransparentProxy( - string memory contractName, - address initialOwner, - bytes memory initializerData - ) internal returns (address) { - return deployTransparentProxy(contractName, initialOwner, initializerData, ""); - } - - /** - * @dev Deploys a transparent proxy using the given contract as the implementation. - * - * @param contractName Name of the contract to use as the implementation, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory - * @param initialOwner Address to set as the owner of the ProxyAdmin contract which gets deployed by the proxy - * @param initializerData Encoded call data of the initializer function to call during creation of the proxy, or empty if no initialization is required - * @return Proxy address - */ - function deployTransparentProxy( - string memory contractName, - address initialOwner, - bytes memory initializerData, - bytes memory implConstructorArgs - ) internal returns (address) { - address impl = deployImplementation(contractName, implConstructorArgs); - return - address( - _deploy( - "TransparentUpgradeableProxy.sol:TransparentUpgradeableProxy", - abi.encode(impl, initialOwner, initializerData) - ) - ); - } - - /** - * @dev Deploys an upgradeable beacon using the given contract as the implementation. - * - * @param contractName Name of the contract to use as the implementation, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory - * @param initialOwner Address to set as the owner of the UpgradeableBeacon contract which gets deployed - * @return Beacon address - */ - function deployBeacon( - string memory contractName, - address initialOwner, - bytes memory implConstructorArgs - ) internal returns (address) { - address impl = deployImplementation(contractName, implConstructorArgs); - return _deploy("UpgradeableBeacon.sol:UpgradeableBeacon", abi.encode(impl, initialOwner)); - } - - /** - * @dev Deploys a beacon proxy using the given beacon and call data. - * - * @param beacon Address of the beacon to use - * @param data Encoded call data of the initializer function to call during creation of the proxy, or empty if no initialization is required - * @return Proxy address - */ - function deployBeaconProxy(address beacon, bytes memory data) internal returns (address) { - return _deploy("BeaconProxy.sol:BeaconProxy", abi.encode(beacon, data)); - } - - /** - * @dev Validates and deploys an implementation contract, and returns its address. - * - * @param contractName Name of the contract to deploy, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory - * @return Address of the implementation contract - */ - function deployImplementation(string memory contractName, bytes memory implConstructorArgs) internal returns (address) { - return _deploy(contractName, implConstructorArgs); - } - /** - * @dev Gets the admin address of a transparent proxy from its ERC1967 admin storage slot. - * @param proxy Address of a transparent proxy - * @return Admin address - */ - function getAdminAddress(address proxy) internal view returns (address) { - bytes32 adminSlot = vm.load(proxy, _ADMIN_SLOT); - return address(uint160(uint256(adminSlot))); - } - - /** - * @dev Gets the implementation address of a transparent or UUPS proxy from its ERC1967 implementation storage slot. - * @param proxy Address of a transparent or UUPS proxy - * @return Implementation address - */ - function getImplementationAddress(address proxy) internal view returns (address) { - bytes32 implSlot = vm.load(proxy, _IMPLEMENTATION_SLOT); - return address(uint160(uint256(implSlot))); - } - - /** - * @dev Gets the beacon address of a beacon proxy from its ERC1967 beacon storage slot. - * @param proxy Address of a beacon proxy - * @return Beacon address - */ - function getBeaconAddress(address proxy) internal view returns (address) { - bytes32 beaconSlot = vm.load(proxy, _BEACON_SLOT); - return address(uint160(uint256(beaconSlot))); - } - - /** - * @dev Upgrades a proxy to a new implementation contract. - * @param proxy Address of the proxy to upgrade - * @param contractName Name of the new implementation contract to upgrade to, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory - * @param data Encoded call data of an arbitrary function to call during the upgrade process, or empty if no function needs to be called during the upgrade - * @param implConstructorArgs abi encoded constructor arguments for deploying the implementation contract - */ - function upgradeProxy( - address proxy, - string memory contractName, - bytes memory data, - bytes memory implConstructorArgs - ) internal { - address newImpl = _deploy(contractName, implConstructorArgs); - - bytes32 adminSlot = vm.load(proxy, _ADMIN_SLOT); - if (adminSlot == bytes32(0)) { - // No admin contract: upgrade directly using interface - TransparentUpgradeableProxy(payable(proxy)).upgradeToAndCall(newImpl, data); - } else { - ProxyAdmin admin = ProxyAdmin(address(uint160(uint256(adminSlot)))); - admin.upgradeAndCall(TransparentUpgradeableProxy(payable(proxy)), newImpl, data); - } - } - - /** - * @dev Upgrades a proxy to a new implementation contract. - * @param proxy Address of the proxy to upgrade - * @param contractName Name of the new implementation contract to upgrade to, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory - * @param data Encoded call data of an arbitrary function to call during the upgrade process, or empty if no function needs to be called during the upgrade - */ - function upgradeProxy(address proxy, string memory contractName, bytes memory data) internal { - upgradeProxy(proxy, contractName, data, ""); - } - - /** - * @dev Upgrades a beacon to a new implementation contract. - * @param beacon Address of the beacon to upgrade - * @param contractName Name of the new implementation contract to upgrade to, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory - * @param implConstructorArgs abi encoded constructor arguments for deploying the implementation contract - */ - function upgradeBeacon(address beacon, string memory contractName, bytes memory implConstructorArgs) internal { - address newImpl = _deploy(contractName, implConstructorArgs); - UpgradeableBeacon(beacon).upgradeTo(newImpl); - } - - /* - * @param beacon Address of the beacon to upgrade - * @param contractName Name of the new implementation contract to upgrade to, e.g. "MyContract.sol" or "MyContract.sol:MyContract" or artifact path relative to the project root directory - */ - function upgradeBeacon(address beacon, string memory contractName) internal { - upgradeBeacon(beacon, contractName, ""); - } - - function _deploy(string memory contractName, bytes memory implConstructorArgs) private returns (address) { - bytes memory creationCode = Vm(CHEATCODE_ADDRESS).getCode(contractName); - address deployedAddress = _deployFromBytecode(abi.encodePacked(creationCode, implConstructorArgs)); - if (deployedAddress == address(0)) { - revert( - string.concat( - "Failed to deploy contract ", - contractName, - ' using constructor data "', - string(implConstructorArgs), - '"' - ) - ); - } - return deployedAddress; - } - - function _deployFromBytecode(bytes memory bytecode) private returns (address) { - address addr; - assembly { - addr := create(0, add(bytecode, 32), mload(bytecode)) - } - return addr; - } - - /** - * @dev Precompile proxy contracts so that they can be deployed by name via the `_deploy` function. - * - * NOTE: This function is never called and has no effect, but must be kept to ensure that the proxy contracts are included in the compilation. - */ - function _precompileProxyContracts() private pure { - bytes memory dummy; - dummy = type(ERC1967Proxy).creationCode; - dummy = type(TransparentUpgradeableProxy).creationCode; - dummy = type(ProxyAdmin).creationCode; - dummy = type(UpgradeableBeacon).creationCode; - dummy = type(BeaconProxy).creationCode; - } -} diff --git a/test/utils/UpgradeableProxyUtils.t.sol b/test/utils/UpgradeableProxyUtils.t.sol deleted file mode 100644 index f0197078..00000000 --- a/test/utils/UpgradeableProxyUtils.t.sol +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; - -import {Test, console} from "forge-std/Test.sol"; -import {Vm} from "forge-std/Vm.sol"; - -import {UpgradeableProxyUtils} from "./UpgradeableProxyUtils.sol"; -import {Proxy} from "@openzeppelin/contracts/proxy/Proxy.sol"; -import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; -import {IBeacon} from "@openzeppelin/contracts/proxy/beacon/IBeacon.sol"; -import {Greeter, GreeterV2, NoInitializer, WithConstructor, GreeterProxiable, GreeterV2Proxiable} from "./ProxyTestContracts.sol"; - -contract UpgradeableProxyUtilsTest is Test { - ProxyAdmin internal admin; - - function setUp() public { - admin = new ProxyAdmin(); - } - - function testTransparent() public { - address proxy = UpgradeableProxyUtils.deployTransparentProxy( - "Greeter.sol", - address(admin), - abi.encodeCall(Greeter.initialize, ("hello")) - ); - Greeter instance = Greeter(proxy); - address implAddressV1 = UpgradeableProxyUtils.getImplementationAddress(proxy); - address adminAddress = UpgradeableProxyUtils.getAdminAddress(proxy); - - assertFalse(adminAddress == address(0)); - assertEq(instance.greeting(), "hello"); - - UpgradeableProxyUtils.upgradeProxy(proxy, "GreeterV2.sol", abi.encodeCall(GreeterV2.resetGreeting, ())); - - address implAddressV2 = UpgradeableProxyUtils.getImplementationAddress(proxy); - - assertEq(UpgradeableProxyUtils.getAdminAddress(proxy), adminAddress); - assertEq(instance.greeting(), "resetted"); - assertFalse(implAddressV2 == implAddressV1); - } - - function testBeacon() public { - address beacon = UpgradeableProxyUtils.deployBeacon("Greeter.sol", address(admin), abi.encode()); - address implAddressV1 = IBeacon(beacon).implementation(); - - address proxy = UpgradeableProxyUtils.deployBeaconProxy(beacon, abi.encodeCall(Greeter.initialize, ("hello"))); - Greeter instance = Greeter(proxy); - - assertEq(UpgradeableProxyUtils.getBeaconAddress(proxy), beacon); - assertEq(instance.greeting(), "hello"); - - UpgradeableProxyUtils.upgradeBeacon(beacon, "GreeterV2.sol"); - address implAddressV2 = IBeacon(beacon).implementation(); - - GreeterV2(address(instance)).resetGreeting(); - - assertEq(instance.greeting(), "resetted"); - assertFalse(implAddressV2 == implAddressV1); - } - - function testUpgradeBeaconWithoutCaller() public { - address beacon = UpgradeableProxyUtils.deployBeacon("Greeter.sol", address(admin), abi.encode()); - UpgradeableProxyUtils.upgradeBeacon(beacon, "GreeterV2.sol", abi.encode()); - } - - function testWithConstructor() public { - bytes memory constructorData = abi.encode(123); - address proxy = UpgradeableProxyUtils.deployTransparentProxy( - "WithConstructor.sol", - msg.sender, - abi.encodeCall(WithConstructor.initialize, (456)), - constructorData - ); - - assertEq(WithConstructor(proxy).a(), 123); - assertEq(WithConstructor(proxy).b(), 456); - } - - function testNoInitializer() public { - /// Can access getCode by File:Contract - bytes memory constructorData = abi.encode(123); - address proxy = UpgradeableProxyUtils.deployTransparentProxy("NoInitializer.sol", msg.sender, "", constructorData); - - assertEq(WithConstructor(proxy).a(), 123); - } - -} diff --git a/test/utils/WithConstructor.sol b/test/utils/WithConstructor.sol deleted file mode 100644 index 146b3ecd..00000000 --- a/test/utils/WithConstructor.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; - -contract WithConstructor { - /// @custom:oz-upgrades-unsafe-allow state-variable-immutable - uint256 public immutable a; - - uint256 public b; - - /// @custom:oz-upgrades-unsafe-allow constructor - constructor(uint256 _a) { - a = _a; - } - - function initialize(uint256 _b) public { - b = _b; - } -} - From 9a975dfee5c3b0031df0794530dcf6fffecc5da7 Mon Sep 17 00:00:00 2001 From: steven Date: Fri, 8 Nov 2024 14:03:33 -0500 Subject: [PATCH 21/52] feat: remove both option --- src/interfaces/IStakeRegistry.sol | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/interfaces/IStakeRegistry.sol b/src/interfaces/IStakeRegistry.sol index fde01379..ecc5b542 100644 --- a/src/interfaces/IStakeRegistry.sol +++ b/src/interfaces/IStakeRegistry.sol @@ -12,11 +12,10 @@ import {IRegistry} from "./IRegistry.sol"; */ interface IStakeRegistry is IRegistry { - enum StakeType { - TOTAL_DELEGATED, - TOTAL_SLASHABLE, - BOTH - } + enum StakeType { + TOTAL_DELEGATED, + TOTAL_SLASHABLE + } // DATA STRUCTURES From fa04f06212978dc3c66c23976cd34498f73aad41 Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Wed, 20 Nov 2024 11:58:19 -0500 Subject: [PATCH 22/52] fix: storage gap remove one slot (#320) --- src/ServiceManagerBaseStorage.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ServiceManagerBaseStorage.sol b/src/ServiceManagerBaseStorage.sol index 0bc52090..51365228 100644 --- a/src/ServiceManagerBaseStorage.sol +++ b/src/ServiceManagerBaseStorage.sol @@ -65,5 +65,5 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab } // storage gap for upgradeability - uint256[46] private __GAP; + uint256[45] private __GAP; } From 388e9f9a46c8249d12f9fd62d994bc81fef2bb15 Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Wed, 20 Nov 2024 12:42:15 -0500 Subject: [PATCH 23/52] feat: track total slashable stake and total delegated stake per quorum (#317) * feat: remove both option * feat: total delegated stake and total slashable stake per quorum config * test: resolve some breaking changes to tests * chore: move stake type to file level definition * chore: refactor loop * test: add unit test for slashble stake quorum init * test: assert on state and event * test: delegated stake quorum and assertions --- foundry.toml | 4 +- src/RegistryCoordinator.sol | 38 +++- src/StakeRegistry.sol | 134 ++++++++---- src/StakeRegistryStorage.sol | 10 +- src/interfaces/IStakeRegistry.sol | 27 ++- test/integration/IntegrationConfig.t.sol | 34 +-- test/integration/IntegrationDeployer.t.sol | 9 +- test/mocks/StakeRegistryMock.sol | 27 ++- test/unit/OperatorStateRetrieverUnit.t.sol | 4 +- test/unit/RegistryCoordinatorMigration.t.sol | 8 +- test/unit/RegistryCoordinatorUnit.t.sol | 216 ++++++++++--------- test/unit/StakeRegistryUnit.t.sol | 69 +++++- test/utils/MockAVSDeployer.sol | 16 +- 13 files changed, 380 insertions(+), 216 deletions(-) diff --git a/foundry.toml b/foundry.toml index a4b33112..e3775cb1 100644 --- a/foundry.toml +++ b/foundry.toml @@ -9,9 +9,7 @@ ffi = true no-match-contract = "FFI" # Enables or disables the optimizer -optimizer = true -# The number of optimizer runs -optimizer_runs = 200 +optimizer = false # Whether or not to use the Yul intermediate representation compilation pipeline via_ir = false # Override the Solidity version (this overrides `auto_detect_solc`) diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index c71e7278..101cd935 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -6,7 +6,7 @@ import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISi import {IAVSDirectory, OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {ISocketUpdater} from "./interfaces/ISocketUpdater.sol"; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; -import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; +import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; @@ -87,11 +87,15 @@ contract RegistryCoordinator is uint256 _initialPausedStatus, OperatorSetParam[] memory _operatorSetParams, uint96[] memory _minimumStakes, - IStakeRegistry.StrategyParams[][] memory _strategyParams + IStakeRegistry.StrategyParams[][] memory _strategyParams, + StakeType[] memory _stakeTypes, + uint32[] memory _lookAheadPeriods ) external initializer { require( _operatorSetParams.length == _minimumStakes.length - && _minimumStakes.length == _strategyParams.length, + && _minimumStakes.length == _strategyParams.length + && _strategyParams.length == _stakeTypes.length + && _stakeTypes.length == _lookAheadPeriods.length, "RegistryCoordinator.initialize: input length mismatch" ); @@ -108,7 +112,7 @@ contract RegistryCoordinator is // Create quorums for (uint256 i = 0; i < _operatorSetParams.length; i++) { - _createQuorum(_operatorSetParams[i], _minimumStakes[i], _strategyParams[i]); + _createQuorum(_operatorSetParams[i], _minimumStakes[i], _strategyParams[i], _stakeTypes[i], _lookAheadPeriods[i]); } } @@ -404,12 +408,21 @@ contract RegistryCoordinator is * @param strategyParams a list of strategies and multipliers used by the StakeRegistry to * calculate an operator's stake weight for the quorum */ - function createQuorum( + function createTotalDelegatedStakeQuorum( OperatorSetParam memory operatorSetParams, uint96 minimumStake, IStakeRegistry.StrategyParams[] memory strategyParams ) external virtual onlyOwner { - _createQuorum(operatorSetParams, minimumStake, strategyParams); + _createQuorum(operatorSetParams, minimumStake, strategyParams, StakeType.TOTAL_DELEGATED, 0); + } + + function createSlashableStakeQuorum( + OperatorSetParam memory operatorSetParams, + uint96 minimumStake, + IStakeRegistry.StrategyParams[] memory strategyParams, + uint32 lookAheadPeriod + ) external virtual onlyOwner { + _createQuorum(operatorSetParams, minimumStake, strategyParams, StakeType.TOTAL_SLASHABLE, lookAheadPeriod); } /** @@ -809,7 +822,9 @@ contract RegistryCoordinator is function _createQuorum( OperatorSetParam memory operatorSetParams, uint96 minimumStake, - IStakeRegistry.StrategyParams[] memory strategyParams + IStakeRegistry.StrategyParams[] memory strategyParams, + StakeType stakeType, + uint32 lookAheadPeriod ) internal { // Increment the total quorum count. Fails if we're already at the max uint8 prevQuorumCount = quorumCount; @@ -824,7 +839,14 @@ contract RegistryCoordinator is // Initialize the quorum here and in each registry _setOperatorSetParams(quorumNumber, operatorSetParams); - stakeRegistry.initializeQuorum(quorumNumber, minimumStake, strategyParams); + + // Initialize stake registry based on stake type + if (stakeType == StakeType.TOTAL_DELEGATED) { + stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); + } else if (stakeType == StakeType.TOTAL_SLASHABLE) { + stakeRegistry.initializeSlashableStakeQuorum(quorumNumber, minimumStake, lookAheadPeriod, strategyParams); + } + indexRegistry.initializeQuorum(quorumNumber); blsApkRegistry.initializeQuorum(quorumNumber); // Check if the AVS has migrated to operator sets diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index e1e4e449..4a0ceca8 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -9,7 +9,7 @@ import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {StakeRegistryStorage, IStrategy} from "./StakeRegistryStorage.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; -import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; +import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; import {BitmapUtils} from "./libraries/BitmapUtils.sol"; @@ -25,7 +25,7 @@ import {BitmapUtils} from "./libraries/BitmapUtils.sol"; contract StakeRegistry is StakeRegistryStorage { using BitmapUtils for *; - + modifier onlyRegistryCoordinator() { _checkRegistryCoordinator(); _; @@ -73,8 +73,8 @@ contract StakeRegistry is StakeRegistryStorage { uint96[] memory currentStakes = new uint96[](quorumNumbers.length); uint96[] memory totalStakes = new uint96[](quorumNumbers.length); - for (uint256 i = 0; i < quorumNumbers.length; i++) { - + for (uint256 i = 0; i < quorumNumbers.length; i++) { + uint8 quorumNumber = uint8(quorumNumbers[i]); _checkQuorumExists(quorumNumber); @@ -88,7 +88,7 @@ contract StakeRegistry is StakeRegistryStorage { // Update the operator's stake int256 stakeDelta = _recordOperatorStakeUpdate({ - operatorId: operatorId, + operatorId: operatorId, quorumNumber: quorumNumber, newStake: currentStake }); @@ -127,8 +127,8 @@ contract StakeRegistry is StakeRegistryStorage { // Update the operator's stake for the quorum and retrieve the shares removed int256 stakeDelta = _recordOperatorStakeUpdate({ - operatorId: operatorId, - quorumNumber: quorumNumber, + operatorId: operatorId, + quorumNumber: quorumNumber, newStake: 0 }); @@ -147,8 +147,8 @@ contract StakeRegistry is StakeRegistryStorage { * and should be deregistered. */ function updateOperatorStake( - address operator, - bytes32 operatorId, + address operator, + bytes32 operatorId, bytes calldata quorumNumbers ) external onlyRegistryCoordinator returns (uint192) { uint192 quorumsToRemove; @@ -173,7 +173,7 @@ contract StakeRegistry is StakeRegistryStorage { // against the minimum stake requirements for the quorum. (uint96 stakeWeight, bool hasMinimumStake) = _weightOfOperatorForQuorum(quorumNumber, operator); // If the operator no longer meets the minimum stake, set their stake to zero and mark them for removal - /// also handle setting the operator's stake to 0 and remove them from the quorum + /// also handle setting the operator's stake to 0 and remove them from the quorum /// if they directly unregistered from the AVSDirectory bubbles up info via registry coordinator to deregister them bool operatorRegistered; // Convert quorumNumber to operatorSetId @@ -207,7 +207,7 @@ contract StakeRegistry is StakeRegistryStorage { } /// @notice Initialize a new quorum and push its first history update - function initializeQuorum( + function initializeDelegatedStakeQuorum( uint8 quorumNumber, uint96 minimumStake, StrategyParams[] memory _strategyParams @@ -215,6 +215,28 @@ contract StakeRegistry is StakeRegistryStorage { require(!_quorumExists(quorumNumber), "StakeRegistry.initializeQuorum: quorum already exists"); _addStrategyParams(quorumNumber, _strategyParams); _setMinimumStakeForQuorum(quorumNumber, minimumStake); + _setStakeType(quorumNumber, StakeType.TOTAL_DELEGATED); + + _totalStakeHistory[quorumNumber].push(StakeUpdate({ + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0, + stake: 0 + })); + } + + + /// @notice Initialize a new quorum and push its first history update + function initializeSlashableStakeQuorum( + uint8 quorumNumber, + uint96 minimumStake, + uint32 lookAheadPeriod, + StrategyParams[] memory _strategyParams + ) public virtual onlyRegistryCoordinator { + require(!_quorumExists(quorumNumber), "StakeRegistry.initializeQuorum: quorum already exists"); + _addStrategyParams(quorumNumber, _strategyParams); + _setMinimumStakeForQuorum(quorumNumber, minimumStake); + _setStakeType(quorumNumber, StakeType.TOTAL_SLASHABLE); + _setLookAheadPeriod(quorumNumber, lookAheadPeriod); _totalStakeHistory[quorumNumber].push(StakeUpdate({ updateBlockNumber: uint32(block.number), @@ -224,32 +246,37 @@ contract StakeRegistry is StakeRegistryStorage { } function setMinimumStakeForQuorum( - uint8 quorumNumber, + uint8 quorumNumber, uint96 minimumStake ) public virtual onlyCoordinatorOwner quorumExists(quorumNumber) { _setMinimumStakeForQuorum(quorumNumber, minimumStake); } /** - * @notice Sets the stake type for the registry + * @notice Sets the stake type for the registry for a specific quorum + * @param quorumNumber The quorum number to set the stake type for * @param _stakeType The type of stake to track (TOTAL_DELEGATED, TOTAL_SLASHABLE, or BOTH) */ - function setStakeType(StakeType _stakeType) external onlyCoordinatorOwner { - _setStakeType(_stakeType); + function setStakeType(uint8 quorumNumber, StakeType _stakeType) external onlyCoordinatorOwner { + _setStakeType(quorumNumber, _stakeType); } - - function setSlashableStakeLookahead(uint32 _lookAheadPeriod) external onlyCoordinatorOwner { - _setLookAheadPeriod(_lookAheadPeriod); + /** + * @notice Sets the look ahead time for checking operator shares for a specific quorum + * @param quorumNumber The quorum number to set the look ahead period for + * @param _lookAheadPeriod The number of days to look ahead when checking shares + */ + function setSlashableStakeLookahead(uint8 quorumNumber, uint32 _lookAheadPeriod) external onlyCoordinatorOwner { + _setLookAheadPeriod(quorumNumber, _lookAheadPeriod); } - /** + /** * @notice Adds strategies and weights to the quorum * @dev Checks to make sure that the *same* strategy cannot be added multiple times (checks against both against existing and new strategies). * @dev This function has no check to make sure that the strategies for a single quorum have the same underlying asset. This is a concious choice, * since a middleware may want, e.g., a stablecoin quorum that accepts USDC, USDT, DAI, etc. as underlying assets and trades them as "equivalent". */ function addStrategies( - uint8 quorumNumber, + uint8 quorumNumber, StrategyParams[] memory _strategyParams ) public virtual onlyCoordinatorOwner quorumExists(quorumNumber) { _addStrategyParams(quorumNumber, _strategyParams); @@ -357,7 +384,7 @@ contract StakeRegistry is StakeRegistryStorage { })); } else { // We have prior stake history - fetch our last-recorded stake - StakeUpdate storage lastUpdate = operatorStakeHistory[operatorId][quorumNumber][historyLength-1]; + StakeUpdate storage lastUpdate = operatorStakeHistory[operatorId][quorumNumber][historyLength-1]; prevStake = lastUpdate.stake; // Short-circuit in case there's no change in stake @@ -368,7 +395,7 @@ contract StakeRegistry is StakeRegistryStorage { /** * If our last stake entry was made in the current block, update the entry * Otherwise, push a new entry and update the previous entry's "next" field - */ + */ if (lastUpdate.updateBlockNumber == uint32(block.number)) { lastUpdate.stake = newStake; } else { @@ -397,7 +424,7 @@ contract StakeRegistry is StakeRegistryStorage { if (stakeDelta == 0) { return lastStakeUpdate.stake; } - + // Calculate the new total stake by applying the delta to our previous stake uint96 newStake = _applyDelta(lastStakeUpdate.stake, stakeDelta); @@ -419,7 +446,7 @@ contract StakeRegistry is StakeRegistryStorage { return newStake; } - /** + /** * @notice Adds `strategyParams` to the `quorumNumber`-th quorum. * @dev Checks to make sure that the *same* strategy cannot be added multiple times (checks against both against existing and new strategies). * @dev This function has no check to make sure that the strategies for a single quorum have the same underlying asset. This is a conscious choice, @@ -493,6 +520,23 @@ contract StakeRegistry is StakeRegistryStorage { ); } + /// Returns total Slashable stake for an operator per strategy that can have the weights applied based on strategy multipliers + function _getSlashableStakePerStrategy(uint8 quorumNumber, address operator) internal view returns (uint256[] memory) { + address[] memory operators = new address[](1); + operators[0] = operator; + uint32 beforeTimestamp = uint32(block.timestamp + slashableStakeLookAheadPerQuorum[quorumNumber]); + + (,uint256[][] memory slashableShares) = IAllocationManager(serviceManager.allocationManager()) + .getMinDelegatedAndSlashableOperatorShares( + OperatorSet(address(serviceManager), quorumNumber), + operators, + strategiesPerQuorum[quorumNumber], + beforeTimestamp + ); + + return slashableShares[0]; + } + /** * @notice This function computes the total weight of the @param operator in the quorum @param quorumNumber. * @dev this method DOES NOT check that the quorum exists @@ -503,18 +547,21 @@ contract StakeRegistry is StakeRegistryStorage { uint96 weight; uint256 stratsLength = strategyParamsLength(quorumNumber); StrategyParams memory strategyAndMultiplier; + uint256[] memory strategyShares; - address[] memory operators = new address[](1); - operators[0] = operator; - uint32 beforeTimestamp = uint32(block.timestamp + slashableStakeLookAhead); - (uint256[][] memory strategyShares, ) = IAllocationManager(serviceManager.allocationManager()).getMinDelegatedAndSlashableOperatorShares(OperatorSet(address(serviceManager), quorumNumber), operators ,strategiesPerQuorum[quorumNumber], beforeTimestamp); + if (stakeTypePerQuorum[quorumNumber]== StakeType.TOTAL_SLASHABLE) { + strategyShares = _getSlashableStakePerStrategy(quorumNumber, operator); + } else { + /// M2 Concept of delegated stake + strategyShares = delegation.getOperatorShares(operator, strategiesPerQuorum[quorumNumber]); + } for (uint256 i = 0; i < stratsLength; i++) { // accessing i^th StrategyParams struct for the quorumNumber strategyAndMultiplier = strategyParams[quorumNumber][i]; // add the weight from the shares for this strategy to the total weight - if (strategyShares[i][0] > 0) { - weight += uint96(strategyShares[i][0] * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR); + if (strategyShares[i] > 0) { + weight += uint96(strategyShares[i] * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR); } } @@ -537,7 +584,7 @@ contract StakeRegistry is StakeRegistryStorage { * @dev reverts if the quorum does not exist */ function weightOfOperatorForQuorum( - uint8 quorumNumber, + uint8 quorumNumber, address operator ) public virtual view quorumExists(quorumNumber) returns (uint96) { (uint96 stake, ) = _weightOfOperatorForQuorum(quorumNumber, operator); @@ -551,7 +598,7 @@ contract StakeRegistry is StakeRegistryStorage { /// @notice Returns the strategy and weight multiplier for the `index`'th strategy in the quorum `quorumNumber` function strategyParamsByIndex( - uint8 quorumNumber, + uint8 quorumNumber, uint256 index ) public view returns (StrategyParams memory) { @@ -578,7 +625,7 @@ contract StakeRegistry is StakeRegistryStorage { * @param quorumNumber The quorum number to get the stake for. */ function getStakeHistory( - bytes32 operatorId, + bytes32 operatorId, uint8 quorumNumber ) external view returns (StakeUpdate[] memory) { return operatorStakeHistory[operatorId][quorumNumber]; @@ -697,7 +744,7 @@ contract StakeRegistry is StakeRegistryStorage { uint256 index ) external view returns (StakeUpdate memory) { return _totalStakeHistory[quorumNumber][index]; - } + } /** * @notice Returns the total stake weight for quorum `quorumNumber`, at the `index`-th entry in the @@ -747,22 +794,23 @@ contract StakeRegistry is StakeRegistryStorage { } /** - * @notice Sets the stake type for the registry + * @notice Sets the stake type for the registry for a specific quorum + * @param quorumNumber The quorum number to set the stake type for * @param _stakeType The type of stake to track (TOTAL_DELEGATED, TOTAL_SLASHABLE, or BOTH) */ - function _setStakeType(StakeType _stakeType) internal { - StakeType oldStakeType = stakeType; - stakeType = _stakeType; - emit StakeTypeSet(oldStakeType, _stakeType); + function _setStakeType(uint8 quorumNumber, StakeType _stakeType) internal { + stakeTypePerQuorum[quorumNumber] = _stakeType; + emit StakeTypeSet(_stakeType); } /** - * @notice Sets the look ahead time for checking operator shares + * @notice Sets the look ahead time for checking operator shares for a specific quorum + * @param quorumNumber The quorum number to set the look ahead period for * @param _lookAheadDays The number of days to look ahead when checking shares */ - function _setLookAheadPeriod(uint32 _lookAheadDays) internal { - uint32 oldLookAheadDays = slashableStakeLookAhead; - slashableStakeLookAhead = _lookAheadDays; + function _setLookAheadPeriod(uint8 quorumNumber, uint32 _lookAheadDays) internal { + uint32 oldLookAheadDays = slashableStakeLookAheadPerQuorum[quorumNumber]; + slashableStakeLookAheadPerQuorum[quorumNumber] = _lookAheadDays; emit LookAheadPeriodChanged(oldLookAheadDays, _lookAheadDays); } diff --git a/src/StakeRegistryStorage.sol b/src/StakeRegistryStorage.sol index 7fea4fa2..2cfcba43 100644 --- a/src/StakeRegistryStorage.sol +++ b/src/StakeRegistryStorage.sol @@ -7,7 +7,7 @@ import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {IStrategyManager, IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; -import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; +import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; /** * @title Storage variables for the `StakeRegistry` contract. @@ -15,7 +15,7 @@ import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; * @notice This storage contract is separate from the logic to simplify the upgrade process. */ abstract contract StakeRegistryStorage is IStakeRegistry { - + /// @notice Constant used as a divisor in calculating weights. uint256 public constant WEIGHTING_DIVISOR = 1e18; /// @notice Maximum length of dynamic arrays in the `strategyParams` mapping. @@ -52,12 +52,12 @@ abstract contract StakeRegistryStorage is IStakeRegistry { mapping(uint8 => StrategyParams[]) public strategyParams; mapping(uint8 => IStrategy[]) public strategiesPerQuorum; - StakeType public stakeType; + mapping(uint8 => StakeType) public stakeTypePerQuorum; - uint32 public slashableStakeLookAhead; + mapping(uint8 => uint32) public slashableStakeLookAheadPerQuorum; constructor( - IRegistryCoordinator _registryCoordinator, + IRegistryCoordinator _registryCoordinator, IDelegationManager _delegationManager, IAVSDirectory _avsDirectory, IServiceManager _serviceManager diff --git a/src/interfaces/IStakeRegistry.sol b/src/interfaces/IStakeRegistry.sol index ecc5b542..17770b3a 100644 --- a/src/interfaces/IStakeRegistry.sol +++ b/src/interfaces/IStakeRegistry.sol @@ -6,17 +6,17 @@ import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy import {IRegistry} from "./IRegistry.sol"; +enum StakeType { + TOTAL_DELEGATED, + TOTAL_SLASHABLE +} + /** * @title Interface for a `Registry` that keeps track of stakes of operators for up to 256 quorums. * @author Layr Labs, Inc. */ interface IStakeRegistry is IRegistry { - enum StakeType { - TOTAL_DELEGATED, - TOTAL_SLASHABLE - } - // DATA STRUCTURES /// @notice struct used to store the stakes of an individual operator or the sum of all operators' stakes, for storage @@ -53,7 +53,7 @@ interface IStakeRegistry is IRegistry { event LookAheadPeriodChanged(uint32 oldLookAheadDays, uint32 newLookAheadDays); /// @notice emitted when the stake type is updated - event StakeTypeSet(StakeType previousStakeType, StakeType newStakeType); + event StakeTypeSet(StakeType newStakeType); /// @notice emitted when the minimum stake for a quorum is updated event MinimumStakeForQuorumUpdated(uint8 indexed quorumNumber, uint96 minimumStake); /// @notice emitted when a new quorum is created @@ -101,7 +101,20 @@ interface IStakeRegistry is IRegistry { /** * @notice Initialize a new quorum created by the registry coordinator by setting strategies, weights, and minimum stake */ - function initializeQuorum(uint8 quorumNumber, uint96 minimumStake, StrategyParams[] memory strategyParams) external; + /// @notice Initialize a new quorum and push its first history update + function initializeDelegatedStakeQuorum( + uint8 quorumNumber, + uint96 minimumStake, + StrategyParams[] memory _strategyParams + ) external; + + /// @notice Initialize a new quorum and push its first history update + function initializeSlashableStakeQuorum( + uint8 quorumNumber, + uint96 minimumStake, + uint32 lookAheadPeriod, + StrategyParams[] memory _strategyParams + ) external; /// @notice Adds new strategies and the associated multipliers to the @param quorumNumber. function addStrategies( diff --git a/test/integration/IntegrationConfig.t.sol b/test/integration/IntegrationConfig.t.sol index d1cd2ac6..e1a341e8 100644 --- a/test/integration/IntegrationConfig.t.sol +++ b/test/integration/IntegrationConfig.t.sol @@ -94,10 +94,10 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { * so this is the best way to speed things up when running multiple tests. */ constructor() { - for (uint i = 0; i < NUM_GENERATED_OPERATORS; i++) { + for (uint i = 0; i < NUM_GENERATED_OPERATORS; i++) { IBLSApkRegistry.PubkeyRegistrationParams memory pubkey; uint privKey = uint(keccak256(abi.encodePacked(i + 1))); - + pubkey.pubkeyG1 = BN254.generatorG1().scalar_mul(privKey); pubkey.pubkeyG2 = G2Operations.mul(privKey); @@ -125,7 +125,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /** * @param _randomSeed Fuzz tests supply a random u24 as input - * @param _userTypes [DEFAULT | ALT_METHODS] - every time a user is generated, it will use these values + * @param _userTypes [DEFAULT | ALT_METHODS] - every time a user is generated, it will use these values * @param _quorumConfig Quorums that are created/initialized in this method will be configured according * to this struct. See `QuorumConfig` above for details on each parameter. */ @@ -175,7 +175,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { emit log_named_uint("- Minimum stake", minimumStake); cheats.prank(registryCoordinatorOwner); - registryCoordinator.createQuorum({ + registryCoordinator.createTotalDelegatedStakeQuorum({ operatorSetParams: operatorSet, minimumStake: minimumStake, strategyParams: strategyParams @@ -211,7 +211,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { numOperators++; (User operator, IStrategy[] memory strategies, uint[] memory tokenBalances) = _randUser(operatorName); - + operator.registerAsOperator(); operator.depositIntoEigenlayer(strategies, tokenBalances); @@ -246,7 +246,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { IStrategy[] memory strategies = new IStrategy[](allStrats.length); uint[] memory balances = new uint[](allStrats.length); emit log_named_string("_dealRandTokens: dealing assets to", user.NAME()); - + // Deal the user a random balance between [MIN_BALANCE, MAX_BALANCE] for each existing strategy for (uint i = 0; i < allStrats.length; i++) { IStrategy strat = allStrats[i]; @@ -266,7 +266,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { IStrategy[] memory strategies = new IStrategy[](allStrats.length); uint[] memory balances = new uint[](allStrats.length); emit log_named_string("_dealMaxTokens: dealing assets to", user.NAME()); - + // Deal the user the 100 * MAX_BALANCE for each existing strategy for (uint i = 0; i < allStrats.length; i++) { IStrategy strat = allStrats[i]; @@ -287,7 +287,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// @param standardQuorums the quorums that we want to register for WITHOUT churn /// @return churnTargets: one churnable operator for each churnQuorum function _getChurnTargets( - User incomingOperator, + User incomingOperator, bytes memory churnQuorums, bytes memory standardQuorums ) internal returns (User[] memory) { @@ -304,7 +304,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { for (uint i = 0; i < churnQuorums.length; i++) { uint8 quorum = uint8(churnQuorums[i]); - IRegistryCoordinator.OperatorSetParam memory params + IRegistryCoordinator.OperatorSetParam memory params = registryCoordinator.getOperatorSetParams(quorum); // Sanity check - make sure we're at the operator cap @@ -337,7 +337,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// From RegistryCoordinator._individualKickThreshold function _individualKickThreshold( - uint96 operatorStake, + uint96 operatorStake, IRegistryCoordinator.OperatorSetParam memory setParams ) internal pure returns (uint96) { return operatorStake * setParams.kickBIPsOfOperatorStake / BIPS_DENOMINATOR; @@ -345,7 +345,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// From RegistryCoordinator._totalKickThreshold function _totalKickThreshold( - uint96 totalStake, + uint96 totalStake, IRegistryCoordinator.OperatorSetParam memory setParams ) internal pure returns (uint96) { return totalStake * setParams.kickBIPsOfTotalStake / BIPS_DENOMINATOR; @@ -380,7 +380,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { function _selectRandRegisteredOperator(uint8 quorum) internal returns (User) { uint32 curNumOperators = indexRegistry.totalOperatorsForQuorum(quorum); - + bytes32 randId = indexRegistry.getLatestOperatorUpdate({ quorumNumber: quorum, operatorIndex: uint32(_randUint({ min: 0, max: curNumOperators - 1 })) @@ -404,7 +404,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// @dev Uses `random` to return a random uint, with a range given by `min` and `max` (inclusive) /// @return `min` <= result <= `max` - function _randUint(uint min, uint max) internal returns (uint) { + function _randUint(uint min, uint max) internal returns (uint) { uint range = max - min + 1; // calculate the number of bits needed for the range @@ -459,7 +459,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// @dev Select a random value from `arr` and return it. Reverts if arr is empty function _randValue(bytes memory arr) internal returns (uint) { assertTrue(arr.length > 0, "_randValue: tried to select value from empty array"); - + uint idx = _randUint({ min: 0, max: arr.length - 1 }); return uint(uint8(arr[idx])); } @@ -470,7 +470,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// NOTE: This should only be used when initializing quorums for the first time (in _configRand) function _randQuorumCount() private returns (uint) { uint quorumFlag = _randValue(numQuorumFlags); - + if (quorumFlag == ONE) { return 1; } else if (quorumFlag == TWO) { @@ -520,7 +520,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { return params; } - /** + /** * @dev Uses _randFillType to determine how many operators to register for a quorum initially * @return The number of operators to register */ @@ -541,7 +541,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// @dev Select a random number of quorums to initialize function _randMinStake() private returns (uint96) { uint minStakeFlag = _randValue(minStakeFlags); - + if (minStakeFlag == NO_MINIMUM) { return 0; } else if (minStakeFlag == HAS_MINIMUM) { diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index 7b9705f9..2c33bfa5 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -331,6 +331,9 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { slasher: address(msg.sender) }); + StakeType[] memory quorumStakeTypes = new StakeType[](0); + uint32[] memory slashableStakeQuorumLookAheadPeriods = new uint32[](0); + RegistryCoordinator registryCoordinatorImplementation = new RegistryCoordinator(serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, avsDirectory); proxyAdmin.upgradeAndCall( @@ -345,7 +348,9 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { 0, /*initialPausedStatus*/ new IRegistryCoordinator.OperatorSetParam[](0), new uint96[](0), - new IStakeRegistry.StrategyParams[][](0) + new IStakeRegistry.StrategyParams[][](0), + quorumStakeTypes, + slashableStakeQuorumLookAheadPeriods ) ); @@ -380,7 +385,7 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { strategies[0] = strategy; cheats.prank(strategyManager.strategyWhitelister()); strategyManager.addStrategiesToDepositWhitelist( - strategies + strategies ); // Add to allStrats diff --git a/test/mocks/StakeRegistryMock.sol b/test/mocks/StakeRegistryMock.sol index f86b938f..2dcecce3 100644 --- a/test/mocks/StakeRegistryMock.sol +++ b/test/mocks/StakeRegistryMock.sol @@ -18,6 +18,19 @@ contract StakeRegistryMock is IStakeRegistry { function registryCoordinator() external view returns (address) {} + function initializeDelegatedStakeQuorum( + uint8 quorumNumber, + uint96 minimumStake, + StrategyParams[] memory _strategyParams + ) external {} + + function initializeSlashableStakeQuorum( + uint8 quorumNumber, + uint96 minimumStake, + uint32 lookAheadPeriod, + StrategyParams[] memory _strategyParams + ) external {} + /** * @notice Registers the `operator` with `operatorId` for the specified `quorumNumbers`. * @param operator The address of the operator to register. @@ -32,8 +45,8 @@ contract StakeRegistryMock is IStakeRegistry { * 4) the operator is not already registered */ function registerOperator( - address operator, - bytes32 operatorId, + address operator, + bytes32 operatorId, bytes memory quorumNumbers ) external returns (uint96[] memory, uint96[] memory) {} @@ -149,7 +162,7 @@ contract StakeRegistryMock is IStakeRegistry { /** * @notice Returns the stake weight corresponding to `operatorId` for quorum `quorumNumber`, at the - * `index`-th entry in the `operatorIdToStakeHistory[operatorId][quorumNumber]` array if the entry + * `index`-th entry in the `operatorIdToStakeHistory[operatorId][quorumNumber]` array if the entry * corresponds to the operator's stake at `blockNumber`. Reverts otherwise. * @param quorumNumber The quorum number to get the stake for. * @param operatorId The id of the operator of interest. @@ -164,8 +177,8 @@ contract StakeRegistryMock is IStakeRegistry { returns (uint96) {} /** - * @notice Returns the total stake weight for quorum `quorumNumber`, at the `index`-th entry in the - * `totalStakeHistory[quorumNumber]` array if the entry corresponds to the total stake at `blockNumber`. + * @notice Returns the total stake weight for quorum `quorumNumber`, at the `index`-th entry in the + * `totalStakeHistory[quorumNumber]` array if the entry corresponds to the total stake at `blockNumber`. * Reverts otherwise. * @param quorumNumber The quorum number to get the stake for. * @param index Array index for lookup, within the dynamic array `totalStakeHistory[quorumNumber]`. @@ -201,8 +214,8 @@ contract StakeRegistryMock is IStakeRegistry { * added to the */ function updateOperatorStake( - address /*operator*/, - bytes32 /*operatorId*/, + address /*operator*/, + bytes32 /*operatorId*/, bytes calldata /*quorumNumbers*/ ) external returns (uint192) { return updateOperatorStakeReturnBitmap; diff --git a/test/unit/OperatorStateRetrieverUnit.t.sol b/test/unit/OperatorStateRetrieverUnit.t.sol index 78b634d7..2fe360ca 100644 --- a/test/unit/OperatorStateRetrieverUnit.t.sol +++ b/test/unit/OperatorStateRetrieverUnit.t.sol @@ -93,7 +93,7 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { IStakeRegistry.StrategyParams({strategy: IStrategy(address(1000)), multiplier: 1e16}); cheats.prank(registryCoordinator.owner()); - registryCoordinator.createQuorum(operatorSetParams, minimumStake, strategyParams); + registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, minimumStake, strategyParams); cheats.expectRevert( "IndexRegistry._operatorCountAtBlockNumber: quorum did not exist at given block number" @@ -235,7 +235,7 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { IStakeRegistry.StrategyParams({strategy: IStrategy(address(1000)), multiplier: 1e16}); cheats.prank(registryCoordinator.owner()); - registryCoordinator.createQuorum(operatorSetParams, minimumStake, strategyParams); + registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, minimumStake, strategyParams); cheats.expectRevert( "StakeRegistry.getTotalStakeIndicesAtBlockNumber: quorum has no stake history at blockNumber" diff --git a/test/unit/RegistryCoordinatorMigration.t.sol b/test/unit/RegistryCoordinatorMigration.t.sol index 63e4c837..7b5a6b14 100644 --- a/test/unit/RegistryCoordinatorMigration.t.sol +++ b/test/unit/RegistryCoordinatorMigration.t.sol @@ -199,7 +199,7 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas assertTrue(avsDirectory.isOperatorSet(address(serviceManager), quorumNumber-1), "Operator set doesn't already existed"); vm.prank(registryCoordinator.owner()); - registryCoordinator.createQuorum(operatorSetParams, minimumStake, strategyParams); + registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, minimumStake, strategyParams); assertTrue(avsDirectory.isOperatorSet(address(serviceManager), quorumNumber), "Operator set was not created for the quorum"); @@ -259,8 +259,8 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas vm.prank(operators[0]); avsDirectory.forceDeregisterFromOperatorSets( - operators[0], - address(serviceManager), + operators[0], + address(serviceManager), operatorSetsToUnregister, ISignatureUtils.SignatureWithSaltAndExpiry({ signature: new bytes(0), @@ -466,5 +466,5 @@ contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBas assertTrue(isOperatorRegistered, "Operator wasn't deregistered from operator set"); } - + } diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index 4129b8cb..d6931dc4 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -34,7 +34,7 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { // Emitted when an operator pubkey is removed from a set of quorums event OperatorRemovedFromQuorums( - address operator, + address operator, bytes32 operatorId, bytes quorumNumbers ); @@ -72,7 +72,7 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { for (uint i = 0; i < defaultMaxOperatorCount - 1; i++) { BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); address operator = _incrementAddress(defaultOperator, i); - + _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); } @@ -81,7 +81,7 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); bytes32 operatorToKickId; address operatorToKick; - + // register last operator before kick operatorKickParams = new IRegistryCoordinator.OperatorKickParam[](1); { @@ -115,7 +115,7 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina for (uint i = 0; i < numQuorums; i++) { assertEq( - keccak256(abi.encode(registryCoordinator.getOperatorSetParams(uint8(i)))), + keccak256(abi.encode(registryCoordinator.getOperatorSetParams(uint8(i)))), keccak256(abi.encode(operatorSetParams[i])) ); } @@ -124,13 +124,15 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina cheats.expectRevert(bytes("Initializable: contract is already initialized")); registryCoordinator.initialize( registryCoordinatorOwner, - churnApprover, - ejector, - pauserRegistry, - 0/*initialPausedStatus*/, - operatorSetParams, - new uint96[](0), - new IStakeRegistry.StrategyParams[][](0) + churnApprover, + ejector, + pauserRegistry, + 0/*initialPausedStatus*/, + operatorSetParams, + new uint96[](0), + new IStakeRegistry.StrategyParams[][](0), + new StakeType[](0), + new uint32[](0) ); } @@ -208,7 +210,7 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina cheats.expectRevert("Ownable: caller is not the owner"); cheats.prank(defaultOperator); - registryCoordinator.createQuorum(operatorSetParams, minimumStake, strategyParams); + registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, minimumStake, strategyParams); } function test_createQuorum() public { @@ -216,7 +218,7 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina // this is necessary since the default setup already configures the max number of quorums, preventing adding more _deployMockEigenLayerAndAVS(0); - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ maxOperatorCount: defaultMaxOperatorCount, kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, @@ -235,7 +237,7 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina cheats.expectEmit(true, true, true, true, address(registryCoordinator)); emit OperatorSetParamsUpdated(quorumCountBefore, operatorSetParams); cheats.prank(registryCoordinatorOwner); - registryCoordinator.createQuorum(operatorSetParams, minimumStake, strategyParams); + registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, minimumStake, strategyParams); uint8 quorumCountAfter = registryCoordinator.quorumCount(); assertEq(quorumCountAfter, quorumCountBefore + 1, "quorum count did not increase properly"); @@ -322,7 +324,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), + keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: defaultOperatorId, status: IRegistryCoordinator.OperatorStatus.REGISTERED @@ -330,7 +332,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(quorumBitmap), updateBlockNumber: uint32(block.number), @@ -363,13 +365,13 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni for (uint i = 0; i < quorumNumbers.length; i++) { cheats.expectEmit(true, true, true, true, address(stakeRegistry)); emit OperatorStakeUpdate(defaultOperatorId, uint8(quorumNumbers[i]), actualStake); - } + } for (uint i = 0; i < quorumNumbers.length; i++) { cheats.expectEmit(true, true, true, true, address(indexRegistry)); emit QuorumIndexUpdate(defaultOperatorId, uint8(quorumNumbers[i]), 0); - } - + } + uint256 gasBefore = gasleft(); cheats.prank(defaultOperator); registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); @@ -379,7 +381,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), + keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: defaultOperatorId, status: IRegistryCoordinator.OperatorStatus.REGISTERED @@ -387,7 +389,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(quorumBitmap), updateBlockNumber: uint32(block.number), @@ -430,7 +432,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), + keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: defaultOperatorId, status: IRegistryCoordinator.OperatorStatus.REGISTERED @@ -438,7 +440,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers)), updateBlockNumber: uint32(registrationBlockNumber), @@ -446,7 +448,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni }))) ); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(quorumBitmap), updateBlockNumber: uint32(nextRegistrationBlockNumber), @@ -470,13 +472,13 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni for (uint i = 0; i < numOperators; i++) { BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); address operator = _incrementAddress(defaultOperator, i); - + _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); } address operatorToRegister = _incrementAddress(defaultOperator, numOperators); BN254.G1Point memory operatorToRegisterPubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, numOperators))); - + blsApkRegistry.setBLSPublicKey(operatorToRegister, operatorToRegisterPubKey); _setOperatorWeight(operatorToRegister, defaultQuorumNumber, defaultStake); @@ -560,7 +562,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), + keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: defaultOperatorId, status: IRegistryCoordinator.OperatorStatus.REGISTERED @@ -568,7 +570,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(quorumBitmap), updateBlockNumber: uint32(block.number), @@ -633,9 +635,9 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); cheats.startPrank(defaultOperator); - + cheats.roll(registrationBlockNumber); - + registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); @@ -653,7 +655,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist emit log_named_uint("gasUsed", gasBefore - gasAfter); assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), + keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: defaultOperatorId, status: IRegistryCoordinator.OperatorStatus.DEREGISTERED @@ -661,7 +663,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(quorumBitmap), updateBlockNumber: registrationBlockNumber, @@ -687,9 +689,9 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist } cheats.startPrank(defaultOperator); - + cheats.roll(registrationBlockNumber); - + registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); @@ -708,7 +710,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist emit log_named_uint("numQuorums", quorumNumbers.length); assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), + keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: defaultOperatorId, status: IRegistryCoordinator.OperatorStatus.DEREGISTERED @@ -716,7 +718,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(quorumBitmap), updateBlockNumber: registrationBlockNumber, @@ -747,9 +749,9 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist } cheats.startPrank(defaultOperator); - + cheats.roll(registrationBlockNumber); - + registryCoordinator.registerOperator(registrationquorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); bytes memory deregistrationquorumNumbers = BitmapUtils.bitmapToBytesArray(deregistrationQuorumBitmap); @@ -772,27 +774,27 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // check that the operator is marked as 'degregistered' only if deregistered from *all* quorums if (deregistrationQuorumBitmap == registrationQuorumBitmap) { assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), + keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: defaultOperatorId, status: IRegistryCoordinator.OperatorStatus.DEREGISTERED }))) - ); + ); } else { assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), + keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: defaultOperatorId, status: IRegistryCoordinator.OperatorStatus.REGISTERED }))) - ); + ); } // ensure that the operator's current quorum bitmap matches the expectation uint256 expectedQuorumBitmap = BitmapUtils.minus(registrationQuorumBitmap, deregistrationQuorumBitmap); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), expectedQuorumBitmap); // check that the quorum bitmap history is as expected assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(registrationQuorumBitmap), updateBlockNumber: registrationBlockNumber, @@ -802,7 +804,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // note: there will be no second entry in the operator's bitmap history in the event that the operator has totally deregistered if (deregistrationQuorumBitmap != registrationQuorumBitmap) { assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(expectedQuorumBitmap), updateBlockNumber: deregistrationBlockNumber, @@ -815,7 +817,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // @notice registers the max number of operators with fuzzed bitmaps and then deregisters a pseudorandom operator (from all of their quorums) function testFuzz_deregisterOperator_manyOperators(uint256 pseudoRandomNumber) public { uint32 numOperators = defaultMaxOperatorCount; - + uint32 registrationBlockNumber = 100; uint32 deregistrationBlockNumber = 200; @@ -827,14 +829,14 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist } cheats.roll(registrationBlockNumber); - + bytes32[] memory lastOperatorInQuorum = new bytes32[](numQuorums); for (uint i = 0; i < numOperators; i++) { emit log_named_uint("i", i); BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); bytes32 operatorId = BN254.hashG1Point(pubKey); address operator = _incrementAddress(defaultOperator, i); - + _registerOperatorWithCoordinator(operator, quorumBitmaps[i], pubKey); // for each quorum the operator is in, save the operatorId @@ -858,7 +860,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); emit OperatorRemovedFromQuorums(operatorToDeregister, operatorToDeregisterId, operatorToDeregisterQuorumNumbers); - + for (uint i = 0; i < operatorToDeregisterQuorumNumbers.length; i++) { cheats.expectEmit(true, true, true, true, address(stakeRegistry)); emit OperatorStakeUpdate(operatorToDeregisterId, uint8(operatorToDeregisterQuorumNumbers[i]), 0); @@ -870,7 +872,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist registryCoordinator.deregisterOperator(operatorToDeregisterQuorumNumbers); assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(operatorToDeregister))), + keccak256(abi.encode(registryCoordinator.getOperator(operatorToDeregister))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: operatorToDeregisterId, status: IRegistryCoordinator.OperatorStatus.DEREGISTERED @@ -878,7 +880,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToDeregisterId, 0))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToDeregisterId, 0))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(operatorToDeregisterQuorumBitmap), updateBlockNumber: registrationBlockNumber, @@ -898,9 +900,9 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist quorumNumbers[0] = bytes1(defaultQuorumNumber); cheats.startPrank(defaultOperator); - + cheats.roll(reregistrationBlockNumber); - + // store data before registering, to check against later IRegistryCoordinator.QuorumBitmapUpdate memory previousQuorumBitmapUpdate = registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0); @@ -911,7 +913,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId, "1"); assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), + keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: defaultOperatorId, status: IRegistryCoordinator.OperatorStatus.REGISTERED @@ -921,14 +923,14 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap, "3"); // check that previous entry in bitmap history was not changed assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), keccak256(abi.encode(previousQuorumBitmapUpdate)), "4" ); // check that new entry in bitmap history is as expected uint historyLength = registryCoordinator.getQuorumBitmapHistoryLength(defaultOperatorId); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, historyLength - 1))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, historyLength - 1))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(quorumBitmap), updateBlockNumber: uint32(reregistrationBlockNumber), @@ -1087,27 +1089,27 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // check that the operator is marked as 'degregistered' only if deregistered from *all* quorums if (deregistrationQuorumBitmap == registrationQuorumBitmap) { assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), + keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: defaultOperatorId, status: IRegistryCoordinator.OperatorStatus.DEREGISTERED }))) - ); + ); } else { assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), + keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: defaultOperatorId, status: IRegistryCoordinator.OperatorStatus.REGISTERED }))) - ); + ); } // ensure that the operator's current quorum bitmap matches the expectation uint256 expectedQuorumBitmap = BitmapUtils.minus(registrationQuorumBitmap, deregistrationQuorumBitmap); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), expectedQuorumBitmap); // check that the quorum bitmap history is as expected assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(registrationQuorumBitmap), updateBlockNumber: registrationBlockNumber, @@ -1117,7 +1119,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // note: there will be no second entry in the operator's bitmap history in the event that the operator has totally deregistered if (deregistrationQuorumBitmap != registrationQuorumBitmap) { assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(expectedQuorumBitmap), updateBlockNumber: deregistrationBlockNumber, @@ -1147,10 +1149,10 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // eject cheats.prank(ejector); registryCoordinator.ejectOperator(defaultOperator, quorumNumbers); - + // make sure the operator is deregistered assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), + keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: defaultOperatorId, status: IRegistryCoordinator.OperatorStatus.DEREGISTERED @@ -1158,7 +1160,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist ); // make sure the operator is not in any quorums assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); - } + } function test_ejectOperator_subsetOfQuorums() public { // register operator with default stake with 2 quorums @@ -1186,10 +1188,10 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.prank(ejector); registryCoordinator.ejectOperator(defaultOperator, quorumNumbersToEject); - + // make sure the operator is registered assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), + keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: defaultOperatorId, status: IRegistryCoordinator.OperatorStatus.REGISTERED @@ -1212,7 +1214,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.prank(defaultOperator); registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); - + cheats.expectRevert("RegistryCoordinator.onlyEjector: not ejector"); cheats.prank(defaultOperator); registryCoordinator.ejectOperator(defaultOperator, quorumNumbers); @@ -1234,7 +1236,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist quorumNumbers[0] = bytes1(defaultQuorumNumber); _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); cheats.roll(registrationBlockNumber); - cheats.startPrank(defaultOperator); + cheats.startPrank(defaultOperator); registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); uint32 blockNumber = 0; @@ -1247,7 +1249,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist blockNumber = registrationBlockNumber; returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); - assertEq(returnArray[0], 0, "defaultOperator bitmap index at blockNumber registrationBlockNumber was not 0"); + assertEq(returnArray[0], 0, "defaultOperator bitmap index at blockNumber registrationBlockNumber was not 0"); blockNumber = registrationBlockNumber + 1; returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); @@ -1269,7 +1271,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist blockNumber = registrationBlockNumber; returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); - assertEq(returnArray[0], 0, "defaultOperator bitmap index at blockNumber registrationBlockNumber was not 0"); + assertEq(returnArray[0], 0, "defaultOperator bitmap index at blockNumber registrationBlockNumber was not 0"); blockNumber = registrationBlockNumber + 1; returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); @@ -1277,11 +1279,11 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist blockNumber = deregistrationBlockNumber; returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); - assertEq(returnArray[0], 1, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber was not 1"); + assertEq(returnArray[0], 1, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber was not 1"); blockNumber = deregistrationBlockNumber + 1; returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); - assertEq(returnArray[0], 1, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber + 1 was not 1"); + assertEq(returnArray[0], 1, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber + 1 was not 1"); } // @notice tests for correct reversion and return values in the event that an operator registers and later deregisters @@ -1302,7 +1304,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist blockNumber = registrationBlockNumber; returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); - assertEq(returnVal, defaultQuorumBitmap, "defaultOperator bitmap index at blockNumber registrationBlockNumber was not defaultQuorumBitmap"); + assertEq(returnVal, defaultQuorumBitmap, "defaultOperator bitmap index at blockNumber registrationBlockNumber was not defaultQuorumBitmap"); blockNumber = registrationBlockNumber + 1; returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); @@ -1315,11 +1317,11 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist blockNumber = deregistrationBlockNumber; returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); - assertEq(returnVal, emptyBitmap, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber was not emptyBitmap"); + assertEq(returnVal, emptyBitmap, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber was not emptyBitmap"); blockNumber = deregistrationBlockNumber + 1; returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); - assertEq(returnVal, emptyBitmap, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber + 1 was not emptyBitmap"); + assertEq(returnVal, emptyBitmap, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber + 1 was not emptyBitmap"); // try an incorrect index input and confirm reversion index = 0; @@ -1345,7 +1347,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord for (uint i = 0; i < numOperators - 1; i++) { BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); address operator = _incrementAddress(defaultOperator, i); - + _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); } @@ -1354,7 +1356,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); bytes32 operatorToKickId; address operatorToKick; - + // register last operator before kick IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = new IRegistryCoordinator.OperatorKickParam[](1); { @@ -1409,10 +1411,10 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord cheats.prank(operatorToRegister); uint256 gasBefore = gasleft(); registryCoordinator.registerOperatorWithChurn( - quorumNumbers, + quorumNumbers, defaultSocket, pubkeyRegistrationParams, - operatorKickParams, + operatorKickParams, signatureWithExpiry, emptyAVSRegSig ); @@ -1421,21 +1423,21 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord } assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(operatorToRegister))), + keccak256(abi.encode(registryCoordinator.getOperator(operatorToRegister))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: operatorToRegisterId, status: IRegistryCoordinator.OperatorStatus.REGISTERED }))) ); assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(operatorToKick))), + keccak256(abi.encode(registryCoordinator.getOperator(operatorToKick))), keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ operatorId: operatorToKickId, status: IRegistryCoordinator.OperatorStatus.DEREGISTERED }))) ); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToKickId, 0))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToKickId, 0))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(quorumBitmap), updateBlockNumber: kickRegistrationBlockNumber, @@ -1449,8 +1451,8 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord quorumNumbers[0] = bytes1(defaultQuorumNumber); ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; - ( - address operatorToRegister, + ( + address operatorToRegister, BN254.G1Point memory operatorToRegisterPubKey, IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, defaultStake); @@ -1464,10 +1466,10 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord cheats.prank(operatorToRegister); cheats.expectRevert("RegistryCoordinator._validateChurn: incoming operator has insufficient stake for churn"); registryCoordinator.registerOperatorWithChurn( - quorumNumbers, + quorumNumbers, defaultSocket, pubkeyRegistrationParams, - operatorKickParams, + operatorKickParams, signatureWithExpiry, emptyAVSRegSig ); @@ -1479,8 +1481,8 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; uint96 operatorToKickStake = defaultMaxOperatorCount * defaultStake; - ( - address operatorToRegister, + ( + address operatorToRegister, BN254.G1Point memory operatorToRegisterPubKey, IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, operatorToKickStake); @@ -1496,10 +1498,10 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord cheats.prank(operatorToRegister); cheats.expectRevert("RegistryCoordinator._validateChurn: cannot kick operator with more than kickBIPsOfTotalStake"); registryCoordinator.registerOperatorWithChurn( - quorumNumbers, + quorumNumbers, defaultSocket, pubkeyRegistrationParams, - operatorKickParams, + operatorKickParams, signatureWithExpiry, emptyAVSRegSig ); @@ -1510,8 +1512,8 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord quorumNumbers[0] = bytes1(defaultQuorumNumber); ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; - ( - address operatorToRegister, + ( + address operatorToRegister, , IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, defaultStake); @@ -1528,10 +1530,10 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord cheats.prank(operatorToRegister); cheats.expectRevert(bytes4(keccak256("InvalidSignature()"))); registryCoordinator.registerOperatorWithChurn( - quorumNumbers, + quorumNumbers, defaultSocket, pubkeyRegistrationParams, - operatorKickParams, + operatorKickParams, signatureWithSaltAndExpiry, emptyAVSRegSig ); @@ -1542,8 +1544,8 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord quorumNumbers[0] = bytes1(defaultQuorumNumber); ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; - ( - address operatorToRegister, + ( + address operatorToRegister, BN254.G1Point memory operatorToRegisterPubKey, IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, defaultStake); @@ -1558,10 +1560,10 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord cheats.prank(operatorToRegister); cheats.expectRevert("RegistryCoordinator._verifyChurnApproverSignature: signature expired"); registryCoordinator.registerOperatorWithChurn( - quorumNumbers, + quorumNumbers, defaultSocket, pubkeyRegistrationParams, - operatorKickParams, + operatorKickParams, signatureWithSaltAndExpiry, emptyAVSRegSig ); @@ -1611,7 +1613,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit uint32 registrationBlockNumber = 100; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(registrationBitmap); for (uint256 i = 0; i < quorumNumbers.length; ++i) { - _setOperatorWeight(defaultOperator, uint8(quorumNumbers[i]), defaultStake); + _setOperatorWeight(defaultOperator, uint8(quorumNumbers[i]), defaultStake); } cheats.startPrank(defaultOperator); cheats.roll(registrationBlockNumber); @@ -1627,7 +1629,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit uint192 quorumBitmapToRemove = mockReturnData; bytes memory quorumNumbersToRemove = BitmapUtils.bitmapToBytesArray(quorumBitmapToRemove); for (uint256 i = 0; i < quorumNumbersToRemove.length; ++i) { - _setOperatorWeight(defaultOperator, uint8(quorumNumbersToRemove[i]), 0); + _setOperatorWeight(defaultOperator, uint8(quorumNumbersToRemove[i]), 0); } uint256 expectedQuorumBitmap = BitmapUtils.minus(quorumBitmapBefore, quorumBitmapToRemove); @@ -1726,7 +1728,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit for (uint i = 0; i < numOperators; i++) { BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); address operator = _incrementAddress(defaultOperator, i); - + _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); } @@ -1753,7 +1755,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit for (uint i = 0; i < numOperators; i++) { BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); address operator = _incrementAddress(defaultOperator, i); - + _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); } @@ -1806,7 +1808,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit for (uint i = 0; i < numOperators; i++) { BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); address operator = _incrementAddress(defaultOperator, i); - + _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); } @@ -1832,7 +1834,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit function testFuzz_updateOperatorBitmapInternal_noPreviousEntries(uint192 newBitmap) public { registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(newBitmap), updateBlockNumber: uint32(block.number), @@ -1848,7 +1850,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(newBitmap), updateBlockNumber: uint32(block.number), @@ -1868,7 +1870,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(pastBitmap), updateBlockNumber: uint32(previousBlockNumber), @@ -1876,7 +1878,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit }))) ); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(newBitmap), updateBlockNumber: uint32(block.number), diff --git a/test/unit/StakeRegistryUnit.t.sol b/test/unit/StakeRegistryUnit.t.sol index 71348e1b..4b74194a 100644 --- a/test/unit/StakeRegistryUnit.t.sol +++ b/test/unit/StakeRegistryUnit.t.sol @@ -100,7 +100,10 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { nextQuorum++; cheats.prank(address(registryCoordinator)); - stakeRegistry.initializeQuorum(quorumNumber, minimumStake, strategyParams); + stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); + + StakeType stakeType = stakeRegistry.stakeTypePerQuorum(quorumNumber); + assertEq(uint8(stakeType), uint8(StakeType.TOTAL_DELEGATED), "invalid stake type"); // Mark quorum initialized for other tests initializedQuorumBitmap = uint192(initializedQuorumBitmap.setBit(quorumNumber)); @@ -127,7 +130,7 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { nextQuorum++; cheats.prank(address(registryCoordinator)); - stakeRegistry.initializeQuorum(quorumNumber, minimumStake, strategyParams); + stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); // Mark quorum initialized for other tests initializedQuorumBitmap = uint192(initializedQuorumBitmap.setBit(quorumNumber)); @@ -580,7 +583,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { cheats.expectRevert( "StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator" ); - stakeRegistry.initializeQuorum(quorumNumber, minimumStake, strategyParams); + stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); } function testFuzz_initializeQuorum_Revert_WhenQuorumAlreadyExists( @@ -590,7 +593,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { ) public fuzzOnlyInitializedQuorums(quorumNumber) { cheats.expectRevert("StakeRegistry.initializeQuorum: quorum already exists"); cheats.prank(address(registryCoordinator)); - stakeRegistry.initializeQuorum(quorumNumber, minimumStake, strategyParams); + stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); } function testFuzz_initializeQuorum_Revert_WhenInvalidArrayLengths( @@ -602,7 +605,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { new IStakeRegistry.StrategyParams[](0); cheats.expectRevert("StakeRegistry._addStrategyParams: no strategies provided"); cheats.prank(address(registryCoordinator)); - stakeRegistry.initializeQuorum(quorumNumber, minimumStake, strategyParams); + stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); strategyParams = new IStakeRegistry.StrategyParams[](MAX_WEIGHING_FUNCTION_LENGTH + 1); for (uint256 i = 0; i < strategyParams.length; i++) { @@ -612,7 +615,55 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { } cheats.expectRevert("StakeRegistry._addStrategyParams: exceed MAX_WEIGHING_FUNCTION_LENGTH"); cheats.prank(address(registryCoordinator)); - stakeRegistry.initializeQuorum(quorumNumber, minimumStake, strategyParams); + stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); + } + event StakeTypeSet(StakeType newStakeType); + + function test_initializeDelegatedStakeQuorum() public { + uint8 quorumNumber = nextQuorum; + uint96 minimumStake = 0; + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = IStakeRegistry.StrategyParams( + IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(quorumNumber)))))), + uint96(WEIGHTING_DIVISOR) + ); + + cheats.prank(address(registryCoordinator)); + cheats.expectEmit(true, true, true, true); + emit StakeTypeSet(StakeType.TOTAL_DELEGATED); + stakeRegistry.initializeDelegatedStakeQuorum( + quorumNumber, + minimumStake, + strategyParams + ); + + StakeType stakeType = stakeRegistry.stakeTypePerQuorum(quorumNumber); + assertEq(uint8(stakeType), uint8(StakeType.TOTAL_DELEGATED), "invalid stake type"); + } + + function test_initializeSlashableStakeQuorum() public { + uint8 quorumNumber = nextQuorum; + uint96 minimumStake = 0; + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = IStakeRegistry.StrategyParams( + IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(quorumNumber)))))), + uint96(WEIGHTING_DIVISOR) + ); + + cheats.prank(address(registryCoordinator)); + cheats.expectEmit(true, true, true, true); + emit StakeTypeSet(StakeType.TOTAL_SLASHABLE); + stakeRegistry.initializeSlashableStakeQuorum( + quorumNumber, + minimumStake, + 7 days, + strategyParams + ); + + StakeType stakeType = stakeRegistry.stakeTypePerQuorum(quorumNumber); + assertEq(uint8(stakeType), uint8(StakeType.TOTAL_SLASHABLE), "invalid stake type"); } /** @@ -636,7 +687,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { } quorumNumber = nextQuorum; cheats.prank(address(registryCoordinator)); - stakeRegistry.initializeQuorum(quorumNumber, minimumStake, strategyParams); + stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); IStakeRegistry.StakeUpdate memory initialStakeUpdate = stakeRegistry.getTotalStakeUpdateAtIndex(quorumNumber, 0); @@ -2151,7 +2202,7 @@ contract StakeRegistryUnitTests_weightOfOperatorForQuorum is StakeRegistryUnitTe } cheats.prank(address(registryCoordinator)); uint8 quorumNumber = nextQuorum; - stakeRegistry.initializeQuorum(quorumNumber, 0, /* minimumStake */ strategyParams); + stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, 0, /* minimumStake */ strategyParams); // set the operator shares for (uint256 i = 0; i < strategyParams.length; i++) { @@ -2198,7 +2249,7 @@ contract StakeRegistryUnitTests_weightOfOperatorForQuorum is StakeRegistryUnitTe // create a valid quorum cheats.prank(address(registryCoordinator)); uint8 quorumNumber = nextQuorum; - stakeRegistry.initializeQuorum(quorumNumber, 0, /* minimumStake */ strategyParams); + stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, 0, /* minimumStake */ strategyParams); // set the operator shares for (uint256 i = 0; i < strategyParams.length; i++) { diff --git a/test/utils/MockAVSDeployer.sol b/test/utils/MockAVSDeployer.sol index af8ebe78..19a08295 100644 --- a/test/utils/MockAVSDeployer.sol +++ b/test/utils/MockAVSDeployer.sol @@ -15,7 +15,7 @@ import {RegistryCoordinator} from "../../src/RegistryCoordinator.sol"; import {RegistryCoordinatorHarness} from "../harnesses/RegistryCoordinatorHarness.t.sol"; import {BLSApkRegistry} from "../../src/BLSApkRegistry.sol"; import {ServiceManagerMock} from "../mocks/ServiceManagerMock.sol"; -import {StakeRegistry} from "../../src/StakeRegistry.sol"; +import {StakeRegistry, StakeType} from "../../src/StakeRegistry.sol"; import {IndexRegistry} from "../../src/IndexRegistry.sol"; import {IBLSApkRegistry} from "../../src/interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry} from "../../src/interfaces/IStakeRegistry.sol"; @@ -296,6 +296,16 @@ contract MockAVSDeployer is Test { ); } + // Create arrays for quorum types and lookahead periods + StakeType[] memory quorumStakeTypes = new StakeType[](numQuorumsToAdd); + uint32[] memory slashableStakeQuorumLookAheadPeriods = new uint32[](numQuorumsToAdd); + + // Set all quorums to TOTAL_DELEGATED type with 0 lookahead period + for (uint256 i = 0; i < numQuorumsToAdd; i++) { + quorumStakeTypes[i] = StakeType.TOTAL_DELEGATED; + slashableStakeQuorumLookAheadPeriods[i] = 0; + } + proxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(registryCoordinator))), address(registryCoordinatorImplementation), @@ -308,7 +318,9 @@ contract MockAVSDeployer is Test { 0, /*initialPausedStatus*/ operatorSetParams, minimumStakeForQuorum, - quorumStrategiesConsideredAndMultipliers + quorumStrategiesConsideredAndMultipliers, + quorumStakeTypes, + slashableStakeQuorumLookAheadPeriods ) ); } From 158a890aecf0535ff7461045fb874d57a5610557 Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Wed, 4 Dec 2024 11:58:54 -0500 Subject: [PATCH 24/52] fix: use libraries with only internal vis (#324) * fix: revert making library function vis external * fix: signature checker internal --- src/libraries/BN254.sol | 22 +++++++++++----------- src/libraries/QuorumBitmapHistoryLib.sol | 8 ++++---- src/libraries/SignatureCheckerLib.sol | 4 ++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/libraries/BN254.sol b/src/libraries/BN254.sol index 4d0edf70..37e3d273 100644 --- a/src/libraries/BN254.sol +++ b/src/libraries/BN254.sol @@ -46,7 +46,7 @@ library BN254 { uint256[2] Y; } - function generatorG1() external pure returns (G1Point memory) { + function generatorG1() internal pure returns (G1Point memory) { return G1Point(1, 2); } @@ -62,7 +62,7 @@ library BN254 { /// this is because of the (unknown to us) convention used in the bn254 pairing precompile contract /// "Elements a * i + b of F_p^2 are encoded as two elements of F_p, (a, b)." /// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-197.md#encoding - function generatorG2() external pure returns (G2Point memory) { + function generatorG2() internal pure returns (G2Point memory) { return G2Point([G2x1, G2x0], [G2y1, G2y0]); } @@ -73,7 +73,7 @@ library BN254 { uint256 internal constant nG2y1 = 17805874995975841540914202342111839520379459829704422454583296818431106115052; uint256 internal constant nG2y0 = 13392588948715843804641432497768002650278120570034223513918757245338268106653; - function negGeneratorG2() external pure returns (G2Point memory) { + function negGeneratorG2() internal pure returns (G2Point memory) { return G2Point([nG2x1, nG2x0], [nG2y1, nG2y0]); } @@ -84,7 +84,7 @@ library BN254 { * @param p Some point in G1. * @return The negation of `p`, i.e. p.plus(p.negate()) should be zero. */ - function negate(G1Point memory p) external pure returns (G1Point memory) { + function negate(G1Point memory p) internal pure returns (G1Point memory) { // The prime q in the base field F_q for G1 if (p.X == 0 && p.Y == 0) { return G1Point(0, 0); @@ -122,7 +122,7 @@ library BN254 { * @param p the point to multiply * @param s the scalar to multiply by * @dev this function is only safe to use if the scalar is 9 bits or less - */ + */ function scalar_mul_tiny(BN254.G1Point memory p, uint16 s) internal view returns (BN254.G1Point memory) { require(s < 2**9, "scalar-too-large"); @@ -155,7 +155,7 @@ library BN254 { ++i; } } - + // return the accumulated product return acc; } @@ -194,7 +194,7 @@ library BN254 { G2Point memory a2, G1Point memory b1, G2Point memory b2 - ) external view returns (bool) { + ) internal view returns (bool) { G1Point[2] memory p1 = [a1, b1]; G2Point[2] memory p2 = [a2, b2]; @@ -238,7 +238,7 @@ library BN254 { G1Point memory b1, G2Point memory b2, uint256 pairingGas - ) external view returns (bool, bool) { + ) internal view returns (bool, bool) { G1Point[2] memory p1 = [a1, b1]; G2Point[2] memory p2 = [a2, b2]; @@ -270,7 +270,7 @@ library BN254 { /// @return hashedG1 the keccak256 hash of the G1 Point /// @dev used for BLS signatures - function hashG1Point(BN254.G1Point memory pk) external pure returns (bytes32 hashedG1) { + function hashG1Point(BN254.G1Point memory pk) internal pure returns (bytes32 hashedG1) { assembly { mstore(0, mload(pk)) mstore(0x20, mload(add(0x20, pk))) @@ -282,14 +282,14 @@ library BN254 { /// @dev used for BLS signatures function hashG2Point( BN254.G2Point memory pk - ) external pure returns (bytes32) { + ) internal pure returns (bytes32) { return keccak256(abi.encodePacked(pk.X[0], pk.X[1], pk.Y[0], pk.Y[1])); } /** * @notice adapted from https://github.com/HarryR/solcrypto/blob/master/contracts/altbn128.sol */ - function hashToG1(bytes32 _x) external view returns (G1Point memory) { + function hashToG1(bytes32 _x) internal view returns (G1Point memory) { uint256 beta = 0; uint256 y = 0; diff --git a/src/libraries/QuorumBitmapHistoryLib.sol b/src/libraries/QuorumBitmapHistoryLib.sol index 4a3e72fd..c971d64d 100644 --- a/src/libraries/QuorumBitmapHistoryLib.sol +++ b/src/libraries/QuorumBitmapHistoryLib.sol @@ -41,7 +41,7 @@ library QuorumBitmapHistoryLib { function currentOperatorBitmap( mapping(bytes32 => IRegistryCoordinator.QuorumBitmapUpdate[]) storage self, bytes32 operatorId - ) external view returns (uint192) { + ) internal view returns (uint192) { uint256 historyLength = self[operatorId].length; if (historyLength == 0) { return 0; @@ -59,7 +59,7 @@ library QuorumBitmapHistoryLib { mapping(bytes32 => IRegistryCoordinator.QuorumBitmapUpdate[]) storage self, uint32 blockNumber, bytes32[] memory operatorIds - ) external view returns (uint32[] memory) { + ) internal view returns (uint32[] memory) { uint32[] memory indices = new uint32[](operatorIds.length); for (uint256 i = 0; i < operatorIds.length; i++) { indices[i] = getQuorumBitmapIndexAtBlockNumber(self, blockNumber, operatorIds[i]); @@ -78,7 +78,7 @@ library QuorumBitmapHistoryLib { bytes32 operatorId, uint32 blockNumber, uint256 index - ) external view returns (uint192) { + ) internal view returns (uint192) { IRegistryCoordinator.QuorumBitmapUpdate memory quorumBitmapUpdate = self[operatorId][index]; /** @@ -107,7 +107,7 @@ library QuorumBitmapHistoryLib { mapping(bytes32 => IRegistryCoordinator.QuorumBitmapUpdate[]) storage self, bytes32 operatorId, uint192 newBitmap - ) external { + ) internal { uint256 historyLength = self[operatorId].length; if (historyLength == 0) { diff --git a/src/libraries/SignatureCheckerLib.sol b/src/libraries/SignatureCheckerLib.sol index c01fd3a7..410462cc 100644 --- a/src/libraries/SignatureCheckerLib.sol +++ b/src/libraries/SignatureCheckerLib.sol @@ -11,7 +11,7 @@ import "@openzeppelin-upgrades/contracts/utils/cryptography/SignatureCheckerUpgr */ library SignatureCheckerLib { error InvalidSignature(); - + /** * @notice Validates a signature using EIP-1271 standard. * @param signer The address of the signer. @@ -22,7 +22,7 @@ library SignatureCheckerLib { address signer, bytes32 digestHash, bytes memory signature - ) external view { + ) internal view { if (!SignatureCheckerUpgradeable.isValidSignatureNow(signer, digestHash, signature)) { revert InvalidSignature(); } From 817ad4246672c6cd152ce4880e73f0cb2872882a Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Wed, 4 Dec 2024 19:57:30 -0500 Subject: [PATCH 25/52] feat: avs registrar registration flow changes (#318) * feat: remove both option * feat: total delegated stake and total slashable stake per quorum config * test: resolve some breaking changes to tests * chore: bump core dependency * chore: bump dependency * chore: bump to latest slashing mags * fix: creation of registry coordinator * test: wip * feat: integrate registrar interfaces * test: add function to delegation mock to set operator status * test: additional test case * chore: bumping core dep and adding UAM (#325) * test: use permission controller mock * chore: label fuzz tests * test: various fixes from config changes * chore: remove comment * test: fix permission controlled functions * test: fix config issue in integration tests * test: fix avs directory initialize * feat: wip prevent m2 registration flows after migration --- lib/eigenlayer-contracts | 2 +- script/OperatorSetUpgrade.s.sol | 258 ---------- src/AVSRegistrar.sol | 21 + src/RegistryCoordinator.sol | 207 ++++++-- src/ServiceManagerBase.sol | 21 +- src/StakeRegistry.sol | 43 +- src/interfaces/ISlasher.sol | 1 - src/interfaces/IStakeRegistry.sol | 1 - src/slashers/base/SlasherBase.sol | 2 +- src/unaudited/ECDSAServiceManagerBase.sol | 4 +- test/harnesses/AVSDirectoryHarness.sol | 62 +-- .../RegistryCoordinatorHarness.t.sol | 9 +- test/integration/CoreRegistration.t.sol | 15 +- test/integration/IntegrationDeployer.t.sol | 105 ++-- test/integration/User.t.sol | 31 +- test/mocks/AVSDirectoryMock.sol | 133 ++--- test/mocks/AVSRegistrarMock.sol | 17 + test/mocks/AllocationManagerMock.sol | 165 ++++-- test/mocks/DelegationMock.sol | 465 ++++++++--------- test/mocks/EigenPodManagerMock.sol | 27 +- test/mocks/PermissionControllerMock.sol | 91 ++++ test/mocks/RewardsCoordinatorMock.sol | 187 ++++--- test/unit/AVSRegistrar.t.sol | 100 ++++ test/unit/RegistryCoordinatorMigration.t.sol | 470 ------------------ test/unit/RegistryCoordinatorUnit.t.sol | 1 - test/unit/ServiceManagerBase.t.sol | 13 +- test/unit/ServiceManagerMigration.t.sol | 348 ------------- test/unit/StakeRegistryUnit.t.sol | 7 +- test/unit/UpgradeableProxyLib.sol | 46 ++ test/unit/Utils.sol | 4 +- test/utils/BLSMockAVSDeployer.sol | 4 +- test/utils/CoreDeployLib.sol | 271 ++++++++++ test/utils/MockAVSDeployer.sol | 100 ++-- 33 files changed, 1454 insertions(+), 1777 deletions(-) delete mode 100644 script/OperatorSetUpgrade.s.sol create mode 100644 src/AVSRegistrar.sol create mode 100644 test/mocks/AVSRegistrarMock.sol create mode 100644 test/mocks/PermissionControllerMock.sol create mode 100644 test/unit/AVSRegistrar.t.sol delete mode 100644 test/unit/RegistryCoordinatorMigration.t.sol delete mode 100644 test/unit/ServiceManagerMigration.t.sol create mode 100644 test/unit/UpgradeableProxyLib.sol create mode 100644 test/utils/CoreDeployLib.sol diff --git a/lib/eigenlayer-contracts b/lib/eigenlayer-contracts index d98c5a7d..f8c12749 160000 --- a/lib/eigenlayer-contracts +++ b/lib/eigenlayer-contracts @@ -1 +1 @@ -Subproject commit d98c5a7df7634e25073b9a508be1a6606d7caf0c +Subproject commit f8c127498a3e5f019732a3e35387a2066935cc6b diff --git a/script/OperatorSetUpgrade.s.sol b/script/OperatorSetUpgrade.s.sol deleted file mode 100644 index 32cd80fe..00000000 --- a/script/OperatorSetUpgrade.s.sol +++ /dev/null @@ -1,258 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.0; - -import {Script, console2} from "forge-std/Script.sol"; -import {OperatorSetUpgradeLib} from "./utils/UpgradeLib.sol"; -import {stdJson} from "forge-std/StdJson.sol"; -import {ServiceManagerMock, IServiceManager} from "../test/mocks/ServiceManagerMock.sol"; -import {StakeRegistry, IStakeRegistry} from "../src/StakeRegistry.sol"; -import {RegistryCoordinator, IRegistryCoordinator} from "../src/RegistryCoordinator.sol"; -import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; -import {IBLSApkRegistry} from "../src/interfaces/IBLSApkRegistry.sol"; -import {IIndexRegistry} from "../src/interfaces/IIndexRegistry.sol"; -import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; -import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; -import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; -interface IServiceManagerMigration { - function getOperatorsToMigrate() - external - view - returns ( - uint32[] memory operatorSetIdsToCreate, - uint32[][] memory operatorSetIds, - address[] memory allOperators - ); - function migrateAndCreateOperatorSetIds(uint32[] memory operatorSetsToCreate) external; - function migrateToOperatorSets(uint32[][] memory operatorSetIds, address[] memory operators) external; - function finalizeMigration() external; - function migrationFinalized() external returns (bool); -} - - -import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; - -contract OperatorSetUpgradeScript is Script { - using stdJson for string; - - address private constant DEFAULT_FORGE_SENDER = 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38; - - address public proxyAdminOwner; - address public serviceManagerOwner; - address public serviceManager; - address public stakeRegistry; - address public registryCoordinator; - address public avsDirectory; - address public rewardsCoordinator; - address public delegationManager; - address public blsApkRegistry; - address public indexRegistry; - address public allocationManager; - - function setUp() public { - vm.label(DEFAULT_FORGE_SENDER, "DEFAULT FORGE SENDER"); - - // Note: Ensure that the following environment variables are set before running the script: - // - PROXY_ADMIN_OWNER: The private key of the proxy admin owner. - // - SERVICE_MANAGER_OWNER: The private key of the service manager owner. - // These environment variables are crucial for the proper execution of the upgrade and migration processes. - /// TODO: improve DEVX of gnosis safe. Would like to do an tx service integration for SafeAPI - proxyAdminOwner = vm.rememberKey(vm.envUint("PROXY_ADMIN_OWNER")); - serviceManagerOwner = vm.rememberKey(vm.envUint("PROXY_ADMIN_OWNER")); - - string memory middlewareJson = vm.readFile(vm.envString("MIDDLEWARE_JSON_PATH")); - string memory coreJson = vm.readFile(vm.envString("CORE_JSON_PATH")); - - /* - * Note: Ensure that the structure of the configuration JSON files matches the structure - * of `core_testdata.json`. If you rename any of the files, you will need to update the - * corresponding key values in the code. - */ - loadAddressesSetup(middlewareJson, coreJson); - labelAndLogAddressesSetup(); - } - - function run() public { - vm.startBroadcast(proxyAdminOwner); - - _upgrade(); - - vm.stopBroadcast(); - - vm.startBroadcast(serviceManagerOwner); - - _migrateToOperatorSets(); - - vm.stopBroadcast(); - } - // forge script script/OperatorSetUpgrade.s.sol --sig "simulateUpgrade()" -vvv - function simulateUpgrade() public { - - address proxyAdmin = OperatorSetUpgradeLib.getAdmin(serviceManager); - proxyAdminOwner = Ownable(proxyAdmin).owner(); - vm.startPrank(proxyAdminOwner); - - _upgrade(); - - vm.stopPrank(); - - } - - // forge script script/OperatorSetUpgrade.s.sol --sig "simulateMigrate()" -vvv - function simulateMigrate() public { - _upgradeAvsDirectory(); /// Workaround since this isn't on pre-prod yet - - serviceManagerOwner = Ownable(serviceManager).owner(); - vm.startPrank(serviceManagerOwner); - - _migrateToOperatorSets(); - - vm.stopPrank(); - } - - // forge script script/OperatorSetUpgrade.s.sol --sig "simulateUpgradeAndMigrate()" -vvv - function simulateUpgradeAndMigrate() public { - _upgradeAvsDirectory(); /// Workaround since this isn't on pre-prod yet - - address proxyAdmin = OperatorSetUpgradeLib.getAdmin(serviceManager); - proxyAdminOwner = Ownable(proxyAdmin).owner(); - - console2.log(proxyAdminOwner, "Pranker"); - vm.startPrank(proxyAdminOwner); - - _upgrade(); - - vm.stopPrank(); - - serviceManagerOwner = Ownable(serviceManager).owner(); - vm.startPrank(serviceManagerOwner); - - _migrateToOperatorSets(); - - vm.stopPrank(); - - // Assert that serviceManager is an operatorSetAVS - require( - IAVSDirectory(avsDirectory).isOperatorSetAVS(serviceManager), - "simulateUpgradeAndMigrate: serviceManager is not an operatorSetAVS" - ); - - // Assert that the migration is finalized - require( - IServiceManagerMigration(serviceManager).migrationFinalized(), - "simulateUpgradeAndMigrate: Migration is not finalized" - ); - } - - function _upgradeAvsDirectory() internal { - address proxyAdmin = OperatorSetUpgradeLib.getAdmin(avsDirectory); - address avsDirectoryOwner = Ownable(proxyAdmin).owner(); - AVSDirectory avsDirectoryImpl = new AVSDirectory(IDelegationManager(delegationManager), 0); // TODO: config - - vm.startPrank(avsDirectoryOwner); - OperatorSetUpgradeLib.upgrade(avsDirectory, address(avsDirectoryImpl)); - vm.stopPrank(); - } - - function labelAndLogAddressesSetup() internal virtual { - vm.label(proxyAdminOwner, "Proxy Admin Owner Account"); - vm.label(serviceManagerOwner, "Service Manager Owner Account"); - vm.label(serviceManager, "Service Manager Proxy"); - vm.label(stakeRegistry, "Stake Registry Proxy"); - vm.label(registryCoordinator, "Registry Coordinator Proxy"); - vm.label(indexRegistry, "Index Registry Proxy"); - vm.label(blsApkRegistry, "BLS APK Registry Proxy"); - vm.label(avsDirectory, "AVS Directory Proxy"); - vm.label(delegationManager, "Delegation Manager Proxy"); - vm.label(rewardsCoordinator, "Rewards Coordinator Proxy"); - - console2.log("Proxy Admin Owner Account", proxyAdminOwner); - console2.log("ServiceManager Owner Account", serviceManagerOwner); - console2.log("Service Manager:", serviceManager); - console2.log("Stake Registry:", stakeRegistry); - console2.log("Registry Coordinator:", registryCoordinator); - console2.log("Index Registry:", indexRegistry); - console2.log("BLS APK Registry:", blsApkRegistry); - console2.log("AVS Directory:", avsDirectory); - console2.log("Delegation Manager:", delegationManager); - console2.log("Rewards Coordinator:", rewardsCoordinator); - - address oldServiceManagerImpl = OperatorSetUpgradeLib.getImplementation(serviceManager); - address oldStakeRegistryImpl = OperatorSetUpgradeLib.getImplementation(stakeRegistry); - address oldRegistryCoordinatorImpl = OperatorSetUpgradeLib.getImplementation(registryCoordinator); - address oldAvsDirectoryImpl = OperatorSetUpgradeLib.getImplementation(avsDirectory); - address oldDelegationManagerImpl = OperatorSetUpgradeLib.getImplementation(delegationManager); - - vm.label(oldServiceManagerImpl, "Old Service Manager Implementation"); - vm.label(oldStakeRegistryImpl, "Old Stake Registry Implementation"); - vm.label(oldRegistryCoordinatorImpl, "Old Registry Coordinator Implementation"); - vm.label(oldAvsDirectoryImpl, "Old AVS Directory Implementation"); - vm.label(oldDelegationManagerImpl, "Old Delegation Manager Implementation"); - - console2.log("Old Service Manager Implementation:", oldServiceManagerImpl); - console2.log("Old Stake Registry Implementation:", oldStakeRegistryImpl); - console2.log("Old Registry Coordinator Implementation:", oldRegistryCoordinatorImpl); - console2.log("Old AVS Directory Implementation:", oldAvsDirectoryImpl); - console2.log("Old Delegation Manager Implementation:", oldDelegationManagerImpl); - } - - function loadAddressesSetup(string memory middlewareJson, string memory coreJson) internal virtual { - serviceManager = middlewareJson.readAddress(".addresses.eigenDAServiceManager"); - stakeRegistry = middlewareJson.readAddress(".addresses.stakeRegistry"); - registryCoordinator = middlewareJson.readAddress(".addresses.registryCoordinator"); - blsApkRegistry = middlewareJson.readAddress(".addresses.blsApkRegistry"); - indexRegistry = middlewareJson.readAddress(".addresses.indexRegistry"); - - avsDirectory = coreJson.readAddress(".addresses.avsDirectory"); - delegationManager = coreJson.readAddress(".addresses.delegationManager"); - rewardsCoordinator = coreJson.readAddress(".addresses.rewardsCoordinator"); - } - - function _upgrade() internal virtual { - address newServiceManagerImpl = address(new ServiceManagerMock( - IAVSDirectory(avsDirectory), - IRewardsCoordinator(rewardsCoordinator), - IRegistryCoordinator(registryCoordinator), - IStakeRegistry(stakeRegistry), - IAllocationManager(allocationManager) - )); - address newRegistryCoordinatorImpl = address(new RegistryCoordinator( - IServiceManager(serviceManager), - IStakeRegistry(stakeRegistry), - IBLSApkRegistry(blsApkRegistry), - IIndexRegistry(indexRegistry), - IAVSDirectory(avsDirectory) - )); - address newStakeRegistryImpl = address(new StakeRegistry( - IRegistryCoordinator(registryCoordinator), - IDelegationManager(delegationManager), - IAVSDirectory(avsDirectory), - IServiceManager(serviceManager) - )); - - console2.log("New Service Manager Implementation:", newServiceManagerImpl); - console2.log("New Registry Coordinator Implementation:", newRegistryCoordinatorImpl); - console2.log("New Stake Registry Implementation:", newStakeRegistryImpl); - - vm.label(newServiceManagerImpl, "New Service Manager Implementation"); - vm.label(newRegistryCoordinatorImpl, "New Registry Coordinator Implementation"); - vm.label(newStakeRegistryImpl, "New Stake Registry Implementation"); - - OperatorSetUpgradeLib.upgrade(serviceManager, newServiceManagerImpl); - OperatorSetUpgradeLib.upgrade(registryCoordinator, newRegistryCoordinatorImpl); - OperatorSetUpgradeLib.upgrade(stakeRegistry, newStakeRegistryImpl); - } - - function _migrateToOperatorSets() internal virtual { - IServiceManagerMigration serviceManager = IServiceManagerMigration(serviceManager); - ( - uint32[] memory operatorSetsToCreate, - uint32[][] memory operatorSetIdsToMigrate, - address[] memory operators - ) = serviceManager.getOperatorsToMigrate(); - - serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); - serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); - serviceManager.finalizeMigration(); - } -} \ No newline at end of file diff --git a/src/AVSRegistrar.sol b/src/AVSRegistrar.sol new file mode 100644 index 00000000..9a81e129 --- /dev/null +++ b/src/AVSRegistrar.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; +import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; +import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; +import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; +import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; + +abstract contract AVSRegistrar is IAVSRegistrar { + function registerOperator( + address operator, + uint32[] calldata operatorSetIds, + bytes calldata data + ) external virtual; + + function deregisterOperator( + address operator, + uint32[] calldata operatorSetIds + ) external virtual; +} diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 101cd935..354ae067 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -3,7 +3,8 @@ pragma solidity ^0.8.12; import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; -import {IAVSDirectory, OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IAVSDirectory } from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import { OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {ISocketUpdater} from "./interfaces/ISocketUpdater.sol"; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; @@ -15,6 +16,7 @@ import {BitmapUtils} from "./libraries/BitmapUtils.sol"; import {BN254} from "./libraries/BN254.sol"; import {SignatureCheckerLib} from "./libraries/SignatureCheckerLib.sol"; import {QuorumBitmapHistoryLib} from "./libraries/QuorumBitmapHistoryLib.sol"; +import {AVSRegistrar} from "./AVSRegistrar.sol"; import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; @@ -37,12 +39,15 @@ contract RegistryCoordinator is Pausable, OwnableUpgradeable, RegistryCoordinatorStorage, + AVSRegistrar, ISocketUpdater, ISignatureUtils { using BitmapUtils for *; using BN254 for BN254.G1Point; + bool isOperatorSetAVS; + modifier onlyEjector() { _checkEjector(); _; @@ -60,10 +65,12 @@ contract RegistryCoordinator is IStakeRegistry _stakeRegistry, IBLSApkRegistry _blsApkRegistry, IIndexRegistry _indexRegistry, - IAVSDirectory _avsDirectory + IAVSDirectory _avsDirectory, + IPauserRegistry _pauserRegistry ) RegistryCoordinatorStorage(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry, _avsDirectory) EIP712("AVSRegistryCoordinator", "v0.0.1") + Pausable(_pauserRegistry) { _disableInitializers(); } @@ -72,7 +79,6 @@ contract RegistryCoordinator is * @param _initialOwner will hold the owner role * @param _churnApprover will hold the churnApprover role, which authorizes registering with churn * @param _ejector will hold the ejector role, which can force-eject operators from quorums - * @param _pauserRegistry a registry of addresses that can pause the contract * @param _initialPausedStatus pause status after calling initialize * Config for initial quorums (see `createQuorum`): * @param _operatorSetParams max operator count and operator churn parameters @@ -83,7 +89,6 @@ contract RegistryCoordinator is address _initialOwner, address _churnApprover, address _ejector, - IPauserRegistry _pauserRegistry, uint256 _initialPausedStatus, OperatorSetParam[] memory _operatorSetParams, uint96[] memory _minimumStakes, @@ -101,8 +106,8 @@ contract RegistryCoordinator is // Initialize roles _transferOwnership(_initialOwner); - _initializePauser(_pauserRegistry, _initialPausedStatus); _setChurnApprover(_churnApprover); + _setPausedStatus(_initialPausedStatus); _setEjector(_ejector); // Add registry contracts to the registries array @@ -133,11 +138,12 @@ contract RegistryCoordinator is * @dev `operatorSignature` is ignored if the operator's status is already REGISTERED */ function registerOperator( - bytes calldata quorumNumbers, - string calldata socket, - IBLSApkRegistry.PubkeyRegistrationParams calldata params, + bytes memory quorumNumbers, + string memory socket, + IBLSApkRegistry.PubkeyRegistrationParams memory params, SignatureWithSaltAndExpiry memory operatorSignature ) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { + if (isUsingOperatorSets()) revert(); /** * If the operator has NEVER registered a pubkey before, use `params` to register * their pubkey in blsApkRegistry @@ -183,12 +189,13 @@ contract RegistryCoordinator is */ function registerOperatorWithChurn( bytes calldata quorumNumbers, - string calldata socket, - IBLSApkRegistry.PubkeyRegistrationParams calldata params, - OperatorKickParam[] calldata operatorKickParams, + string memory socket, + IBLSApkRegistry.PubkeyRegistrationParams memory params, + OperatorKickParam[] memory operatorKickParams, SignatureWithSaltAndExpiry memory churnApproverSignature, SignatureWithSaltAndExpiry memory operatorSignature ) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { + if (isUsingOperatorSets()) revert(); require( operatorKickParams.length == quorumNumbers.length, "RegistryCoordinator.registerOperatorWithChurn: input length mismatch" @@ -249,20 +256,84 @@ contract RegistryCoordinator is * @notice Deregisters the caller from one or more quorums * @param quorumNumbers is an ordered byte array containing the quorum numbers being deregistered from */ - function deregisterOperator(bytes calldata quorumNumbers) + function deregisterOperator(bytes memory quorumNumbers) external onlyWhenNotPaused(PAUSED_DEREGISTER_OPERATOR) { _deregisterOperator({operator: msg.sender, quorumNumbers: quorumNumbers}); } + function isUsingOperatorSets() public view returns (bool){ + return isOperatorSetAVS; + } + + function enableOperatorSets() external onlyOwner { + /// TODO: + /// Triggers the updates to use operator sets + /// Opens update the AVS Registrar Hooks on this contract + /// Allows creation of quorums with slashable and total delegated stake for operator sets + isOperatorSetAVS = true; + } + + function registerOperator( + address operator, + uint32[] memory operatorSetIds, + bytes memory data + ) external override { + if (!isUsingOperatorSets()) revert(); + /// TODO: Make a mapping for quorums associated with operator sets / ones associated with m2 registrations + /// TODO: only allow registration of operator sets that have been created in the core and don't conflict with existing quorum numbers + require(msg.sender == address(serviceManager.allocationManager()), "Only allocation manager can register operators"); + + // Decode registration data from bytes + ( + string memory socket, + IBLSApkRegistry.PubkeyRegistrationParams memory params + ) = abi.decode(data, (string, IBLSApkRegistry.PubkeyRegistrationParams)); + + // Get operator ID from BLS registry + bytes32 operatorId = _getOrCreateOperatorId(operator, params); + bytes memory quorumNumbers = new bytes(operatorSetIds.length); + for (uint256 i = 0; i < operatorSetIds.length; i++) { + quorumNumbers[i] = bytes1(uint8(operatorSetIds[i])); + } + + // Register operator with decoded parameters + _registerOperatorNew({ + operator: operator, + operatorId: operatorId, + quorumNumbers: quorumNumbers, + socket: socket + }); + + /// TODO: Correctly handle decoding the registration with churn and the normal registration flow parameters + + } + + function deregisterOperator( + address operator, + uint32[] memory operatorSetIds + ) external override { + if (!isUsingOperatorSets()) revert(); + require(msg.sender == address(serviceManager.allocationManager()), "Only allocation manager can register operators"); + /// TODO: Make a mapping for quorums associated with operator sets / ones associated with m2 registrations + /// TODO: Call _registerOperator to propogate changes to the other contracts + /// TODO: only allow deregistration of operator sets that have been created in the core and don't conflict with existing quorum numbers + bytes memory quorumNumbers = new bytes(operatorSetIds.length); + for (uint256 i = 0; i < operatorSetIds.length; i++) { + quorumNumbers[i] = bytes1(uint8(operatorSetIds[i])); + } + + _deregisterOperator(operator, quorumNumbers); + } + /** * @notice Updates the StakeRegistry's view of one or more operators' stakes. If any operator * is found to be below the minimum stake for the quorum, they are deregistered. * @dev stakes are queried from the Eigenlayer core DelegationManager contract * @param operators a list of operator addresses to update */ - function updateOperators(address[] calldata operators) + function updateOperators(address[] memory operators) external onlyWhenNotPaused(PAUSED_UPDATE_OPERATOR) { @@ -293,7 +364,7 @@ contract RegistryCoordinator is * this method is broadcast (but before it is executed), the method will fail */ function updateOperatorsForQuorum( - address[][] calldata operatorsPerQuorum, + address[][] memory operatorsPerQuorum, bytes calldata quorumNumbers ) external onlyWhenNotPaused(PAUSED_UPDATE_OPERATOR) { // Input validation @@ -312,7 +383,7 @@ contract RegistryCoordinator is uint8 quorumNumber = uint8(quorumNumbers[i]); // Ensure we've passed in the correct number of operators for this quorum - address[] calldata currQuorumOperators = operatorsPerQuorum[i]; + address[] memory currQuorumOperators = operatorsPerQuorum[i]; require( currQuorumOperators.length == indexRegistry.totalOperatorsForQuorum(quorumNumber), "RegistryCoordinator.updateOperatorsForQuorum: number of updated operators does not match quorum total" @@ -378,7 +449,7 @@ contract RegistryCoordinator is * @param quorumNumbers the quorum numbers to eject the operator from * @dev possible race condition if prior to being ejected for a set of quorums the operator self deregisters from a subset */ - function ejectOperator(address operator, bytes calldata quorumNumbers) external onlyEjector { + function ejectOperator(address operator, bytes memory quorumNumbers) external onlyEjector { lastEjectionTimestamp[operator] = block.timestamp; OperatorInfo storage operatorInfo = _operatorInfo[operator]; @@ -413,6 +484,7 @@ contract RegistryCoordinator is uint96 minimumStake, IStakeRegistry.StrategyParams[] memory strategyParams ) external virtual onlyOwner { + if (!isUsingOperatorSets()) revert (); _createQuorum(operatorSetParams, minimumStake, strategyParams, StakeType.TOTAL_DELEGATED, 0); } @@ -422,6 +494,7 @@ contract RegistryCoordinator is IStakeRegistry.StrategyParams[] memory strategyParams, uint32 lookAheadPeriod ) external virtual onlyOwner { + if (!isUsingOperatorSets()) revert (); _createQuorum(operatorSetParams, minimumStake, strategyParams, StakeType.TOTAL_SLASHABLE, lookAheadPeriod); } @@ -486,7 +559,7 @@ contract RegistryCoordinator is function _registerOperator( address operator, bytes32 operatorId, - bytes calldata quorumNumbers, + bytes memory quorumNumbers, string memory socket, SignatureWithSaltAndExpiry memory operatorSignature ) internal virtual returns (RegisterResults memory results) { @@ -529,21 +602,67 @@ contract RegistryCoordinator is _operatorInfo[operator] = OperatorInfo({operatorId: operatorId, status: OperatorStatus.REGISTERED}); - // Register the operator with the EigenLayer core contracts via this AVS's ServiceManager - bool operatorSetAVS = avsDirectory.isOperatorSetAVS(address(serviceManager)); - if (operatorSetAVS){ - bytes memory quorumBytes = BitmapUtils.bitmapToBytesArray(quorumsToAdd); - uint32[] memory operatorSetIds = new uint32[](quorumBytes.length); - for (uint256 i = 0; i < quorumBytes.length; i++) { - operatorSetIds[i] = uint8(quorumBytes[i]); - } - serviceManager.registerOperatorToOperatorSets(operator, operatorSetIds, operatorSignature); + serviceManager.registerOperatorToAVS(operator, operatorSignature); + emit OperatorRegistered(operator, operatorId); - } else { - serviceManager.registerOperatorToAVS(operator, operatorSignature); - emit OperatorRegistered(operator, operatorId); - } + } + + // Register the operator with the BLSApkRegistry, StakeRegistry, and IndexRegistry + blsApkRegistry.registerOperator(operator, quorumNumbers); + (results.operatorStakes, results.totalStakes) = + stakeRegistry.registerOperator(operator, operatorId, quorumNumbers); + results.numOperatorsPerQuorum = indexRegistry.registerOperator(operatorId, quorumNumbers); + + return results; + } + + /** + * @notice Register the operator for one or more quorums. This method updates the + * operator's quorum bitmap, socket, and status, then registers them with each registry. + */ + function _registerOperatorNew( + address operator, + bytes32 operatorId, + bytes memory quorumNumbers, + string memory socket + ) internal virtual returns (RegisterResults memory results) { + /** + * Get bitmap of quorums to register for and operator's current bitmap. Validate that: + * - we're trying to register for at least 1 quorum + * - the quorums we're registering for exist (checked against `quorumCount` in orderedBytesArrayToBitmap) + * - the operator is not currently registered for any quorums we're registering for + * Then, calculate the operator's new bitmap after registration + */ + uint192 quorumsToAdd = + uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); + uint192 currentBitmap = _currentOperatorBitmap(operatorId); + require( + !quorumsToAdd.isEmpty(), "RegistryCoordinator._registerOperator: bitmap empty" + ); + require( + quorumsToAdd.noBitsInCommon(currentBitmap), + "RegistryCoordinator._registerOperator: operator already registered for some quorums being registered for" + ); + uint192 newBitmap = uint192(currentBitmap.plus(quorumsToAdd)); + // Check that the operator can reregister if ejected + require( + lastEjectionTimestamp[operator] + ejectionCooldown < block.timestamp, + "RegistryCoordinator._registerOperator: operator cannot reregister yet" + ); + + /** + * Update operator's bitmap, socket, and status. Only update operatorInfo if needed: + * if we're `REGISTERED`, the operatorId and status are already correct. + */ + _updateOperatorBitmap({operatorId: operatorId, newBitmap: newBitmap}); + + emit OperatorSocketUpdate(operatorId, socket); + + // If the operator wasn't registered for any quorums, update their status + // and register them with this AVS in EigenLayer core (DelegationManager) + if (_operatorInfo[operator].status != OperatorStatus.REGISTERED) { + _operatorInfo[operator] = OperatorInfo(operatorId, OperatorStatus.REGISTERED); } // Register the operator with the BLSApkRegistry, StakeRegistry, and IndexRegistry @@ -584,7 +703,7 @@ contract RegistryCoordinator is */ function _getOrCreateOperatorId( address operator, - IBLSApkRegistry.PubkeyRegistrationParams calldata params + IBLSApkRegistry.PubkeyRegistrationParams memory params ) internal returns (bytes32 operatorId) { operatorId = blsApkRegistry.getOperatorId(operator); if (operatorId == 0) { @@ -681,17 +800,22 @@ contract RegistryCoordinator is _updateOperatorBitmap({operatorId: operatorId, newBitmap: newBitmap}); - bool operatorSetAVS = IAVSDirectory(serviceManager.avsDirectory()).isOperatorSetAVS(address(serviceManager)); + /// TODO: Need to know if an AVS is an operator set avs + bool operatorSetAVS; + // = IAVSDirectory(serviceManager.avsDirectory()).isOperatorSetAVS(address(serviceManager)); if (operatorSetAVS){ bytes memory quorumBytes = BitmapUtils.bitmapToBytesArray(quorumsToRemove); uint32[] memory operatorSetIds = new uint32[](quorumBytes.length); uint256 forceDeregistrationCount; for (uint256 i = 0; i < quorumBytes.length; i++) { - /// We need to track forceDeregistrations so we don't pass an id that was already deregistered on the AVSDirectory + /// Post operator sets feature we need to track forceDeregistrations so we don't pass an id that was already deregistered on the AVSDirectory /// but hasnt yet been recorded in the middleware contracts - if (!avsDirectory.isMember(operator, OperatorSet(address(serviceManager), uint8(quorumBytes[i])))){ - forceDeregistrationCount++; - } + + // TODO: Fix need a way to check member ship in the allocation manager without iterating through every member + + // if (!avsDirectory.isMember(operator, OperatorSet(address(serviceManager), uint8(quorumBytes[i])))){ + // forceDeregistrationCount++; + // } operatorSetIds[i] = uint8(quorumBytes[i]); } @@ -700,7 +824,9 @@ contract RegistryCoordinator is uint32[] memory filteredOperatorSetIds = new uint32[](operatorSetIds.length - forceDeregistrationCount); uint256 offset; for (uint256 i; i < operatorSetIds.length; i++){ - if (avsDirectory.isMember(operator, OperatorSet(address(serviceManager), operatorSetIds[i]))){ + if (true){ + /// TODO: Fix need to check + // avsDirectory.isMember(operator, OperatorSet(address(serviceManager), operatorSetIds[i]))){ filteredOperatorSetIds[i] = operatorSetIds[i+offset]; } else { offset++; @@ -849,13 +975,6 @@ contract RegistryCoordinator is indexRegistry.initializeQuorum(quorumNumber); blsApkRegistry.initializeQuorum(quorumNumber); - // Check if the AVS has migrated to operator sets - if (avsDirectory.isOperatorSetAVS(address(serviceManager))) { - // Create an operator set for the new quorum - uint32[] memory operatorSetIds = new uint32[](1); - operatorSetIds[0] = uint32(quorumNumber); - serviceManager.createOperatorSets(operatorSetIds); - } } /** diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index 74d47510..a482c65d 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -85,7 +85,7 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { } function slashOperator(IAllocationManager.SlashingParams memory params) external onlySlasher { - _allocationManager.slashOperator(params); + _allocationManager.slashOperator(address(this), params); } /** @@ -115,11 +115,12 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { ); } - _rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); + _rewardsCoordinator.createAVSRewardsSubmission(address(this),rewardsSubmissions); } function createOperatorSets(uint32[] memory operatorSetIds) external onlyRegistryCoordinator { - _avsDirectory.createOperatorSets(operatorSetIds); + /// TODO: + // _avsDirectory.createOperatorSets(operatorSetIds); } /** @@ -153,7 +154,7 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { uint32[] calldata operatorSetIds, ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature ) public virtual onlyRegistryCoordinator { - _avsDirectory.registerOperatorToOperatorSets(operator, operatorSetIds, operatorSignature); + // _avsDirectory.registerOperatorToOperatorSets(operator, operatorSetIds, operatorSignature); } /** @@ -165,7 +166,7 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { address operator, uint32[] calldata operatorSetIds ) public virtual onlyRegistryCoordinator { - _avsDirectory.deregisterOperatorFromOperatorSets(operator, operatorSetIds); + // _avsDirectory.deregisterOperatorFromOperatorSets(operator, operatorSetIds); } /** @@ -241,8 +242,8 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { * @param operatorSetIdsToCreate An array of operator set IDs to create. */ function _migrateAndCreateOperatorSetIds(uint32[] memory operatorSetIdsToCreate) internal { - _avsDirectory.becomeOperatorSetAVS(); - IAVSDirectory(address(_avsDirectory)).createOperatorSets(operatorSetIdsToCreate); + // _avsDirectory.becomeOperatorSetAVS(); + // IAVSDirectory(address(_avsDirectory)).createOperatorSets(operatorSetIdsToCreate); } /** @@ -260,9 +261,9 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { for (uint256 i; i < operators.length; i++) { _isOperatorRegisteredForQuorums(operators[i], operatorSetIds[i]); } - IAVSDirectory(address(_avsDirectory)).migrateOperatorsToOperatorSets( - operators, operatorSetIds - ); + // IAVSDirectory(address(_avsDirectory)).migrateOperatorsToOperatorSets( + // operators, operatorSetIds + // ); } /** diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index 4a0ceca8..73bea57b 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -2,7 +2,8 @@ pragma solidity ^0.8.12; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; -import {IAVSDirectory, OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IAVSDirectory } from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; @@ -153,9 +154,9 @@ contract StakeRegistry is StakeRegistryStorage { ) external onlyRegistryCoordinator returns (uint192) { uint192 quorumsToRemove; - bool isOperatorSetAVS = avsDirectory.isOperatorSetAVS( - address(serviceManager) - ); + bool isOperatorSetAVS; + // TODO: logic for determining if it's an operator set quorum number or not + // avsDirectory.isOperatorSetAVS(address(serviceManager)); /** * For each quorum, update the operator's stake and record the delta @@ -181,10 +182,12 @@ contract StakeRegistry is StakeRegistryStorage { // Get the AVSDirectory address from the RegistryCoordinator // Query the AVSDirectory to check if the operator is directly unregistered - operatorRegistered = avsDirectory.isMember( - operator, - OperatorSet(address(serviceManager), operatorSetId) - ); + operatorRegistered; + // TODO: Fix + // = avsDirectory.isMember( + // operator, + // OperatorSet(address(serviceManager), operatorSetId) + // ); if (!hasMinimumStake || (isOperatorSetAVS && !operatorRegistered)) { stakeWeight = 0; @@ -526,8 +529,8 @@ contract StakeRegistry is StakeRegistryStorage { operators[0] = operator; uint32 beforeTimestamp = uint32(block.timestamp + slashableStakeLookAheadPerQuorum[quorumNumber]); - (,uint256[][] memory slashableShares) = IAllocationManager(serviceManager.allocationManager()) - .getMinDelegatedAndSlashableOperatorShares( + uint256[][] memory slashableShares = IAllocationManager(serviceManager.allocationManager()) + .getMinimumSlashableStake( OperatorSet(address(serviceManager), quorumNumber), operators, strategiesPerQuorum[quorumNumber], @@ -551,17 +554,23 @@ contract StakeRegistry is StakeRegistryStorage { if (stakeTypePerQuorum[quorumNumber]== StakeType.TOTAL_SLASHABLE) { strategyShares = _getSlashableStakePerStrategy(quorumNumber, operator); + for (uint256 i = 0; i < stratsLength; i++) { + strategyAndMultiplier = strategyParams[quorumNumber][i]; + if (strategyShares[i] > 0) { + weight += uint96(strategyShares[i] * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR); + } + } } else { /// M2 Concept of delegated stake strategyShares = delegation.getOperatorShares(operator, strategiesPerQuorum[quorumNumber]); - } - for (uint256 i = 0; i < stratsLength; i++) { - // accessing i^th StrategyParams struct for the quorumNumber - strategyAndMultiplier = strategyParams[quorumNumber][i]; + for (uint256 i = 0; i < stratsLength; i++) { + // accessing i^th StrategyParams struct for the quorumNumber + strategyAndMultiplier = strategyParams[quorumNumber][i]; - // add the weight from the shares for this strategy to the total weight - if (strategyShares[i] > 0) { - weight += uint96(strategyShares[i] * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR); + // add the weight from the shares for this strategy to the total weight + if (strategyShares[i] > 0) { + weight += uint96(strategyShares[i] * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR); + } } } diff --git a/src/interfaces/ISlasher.sol b/src/interfaces/ISlasher.sol index e2d128f1..018cf16c 100644 --- a/src/interfaces/ISlasher.sol +++ b/src/interfaces/ISlasher.sol @@ -20,7 +20,6 @@ interface ISlasherEvents { uint256 indexed slashingRequestId, address indexed operator, uint32 indexed operatorSetId, - IStrategy[] strategies, uint256 wadToSlash, string description ); diff --git a/src/interfaces/IStakeRegistry.sol b/src/interfaces/IStakeRegistry.sol index 17770b3a..ded09290 100644 --- a/src/interfaces/IStakeRegistry.sol +++ b/src/interfaces/IStakeRegistry.sol @@ -16,7 +16,6 @@ enum StakeType { * @author Layr Labs, Inc. */ interface IStakeRegistry is IRegistry { - // DATA STRUCTURES /// @notice struct used to store the stakes of an individual operator or the sum of all operators' stakes, for storage diff --git a/src/slashers/base/SlasherBase.sol b/src/slashers/base/SlasherBase.sol index c62513d3..8357c6f4 100644 --- a/src/slashers/base/SlasherBase.sol +++ b/src/slashers/base/SlasherBase.sol @@ -24,7 +24,7 @@ abstract contract SlasherBase is Initializable, SlasherStorage { IAllocationManager.SlashingParams memory _params ) internal virtual { IServiceManager(serviceManager).slashOperator(_params); - emit OperatorSlashed(_requestId, _params.operator, _params.operatorSetId, _params.strategies, _params.wadToSlash, _params.description); + emit OperatorSlashed(_requestId, _params.operator, _params.operatorSetId, _params.wadToSlash, _params.description); } function _checkSlasher(address account) internal view virtual { diff --git a/src/unaudited/ECDSAServiceManagerBase.sol b/src/unaudited/ECDSAServiceManagerBase.sol index facb6813..c358796d 100644 --- a/src/unaudited/ECDSAServiceManagerBase.sol +++ b/src/unaudited/ECDSAServiceManagerBase.sol @@ -23,7 +23,7 @@ abstract contract ECDSAServiceManagerBase is /// @notice Address of the AVS directory contract, which manages AVS-related data for registered operators. address public immutable avsDirectory; - /// @notice Address of the AllocationManager contract + /// @notice Address of the AllocationManager contract address public immutable allocationManager; /// @notice Address of the rewards coordinator contract, which handles rewards distributions. @@ -203,7 +203,7 @@ abstract contract ECDSAServiceManagerBase is ); } - IRewardsCoordinator(rewardsCoordinator).createAVSRewardsSubmission( + IRewardsCoordinator(rewardsCoordinator).createAVSRewardsSubmission(address(this), rewardsSubmissions ); } diff --git a/test/harnesses/AVSDirectoryHarness.sol b/test/harnesses/AVSDirectoryHarness.sol index 94598058..262e8903 100644 --- a/test/harnesses/AVSDirectoryHarness.sol +++ b/test/harnesses/AVSDirectoryHarness.sol @@ -4,65 +4,9 @@ pragma solidity ^0.8.12; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; +import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; // wrapper around the AVSDirectory contract that exposes internal functionality, for unit testing contract AVSDirectoryHarness is AVSDirectory { - constructor(IDelegationManager _delegation) AVSDirectory(_delegation, 0) {} // TODO: config update - - function setOperatorSaltIsSpent(address operator, bytes32 salt, bool isSpent) external { - operatorSaltIsSpent[operator][salt] = isSpent; - } - - function setAvsOperatorStatus( - address avs, - address operator, - OperatorAVSRegistrationStatus status - ) external { - avsOperatorStatus[avs][operator] = status; - } - - function setIsOperatorSetAVS(address avs, bool isOperatorSet) external { - isOperatorSetAVS[avs] = isOperatorSet; - } - - function setIsOperatorSet(address avs, uint32 operatorSetId, bool isSet) external { - isOperatorSet[avs][operatorSetId] = isSet; - } - - function setIsMember( - address avs, - address operator, - uint32[] calldata operatorSetIds, - bool membershipStatus - ) external { - if (membershipStatus) { - _registerToOperatorSets(avs, operator, operatorSetIds); - } else { - _deregisterFromOperatorSets(avs, operator, operatorSetIds); - } - } - - function _registerToOperatorSetsExternal( - address avs, - address operator, - uint32[] calldata operatorSetIds - ) external { - _registerToOperatorSets(avs, operator, operatorSetIds); - } - - function _deregisterFromOperatorSetsExternal( - address avs, - address operator, - uint32[] calldata operatorSetIds - ) external { - _deregisterFromOperatorSets(avs, operator, operatorSetIds); - } - - function _calculateDigestHashExternal(bytes32 structHash) external view returns (bytes32) { - // return calculateOperatorSetRegistrationDigestHash(structHash); // TODO: Fix - } - - function _calculateDomainSeparatorExternal() external view returns (bytes32) { - return _calculateDomainSeparator(); - } -} + constructor(IDelegationManager _dm, IPauserRegistry _pauser)AVSDirectory(_dm, _pauser){} +} \ No newline at end of file diff --git a/test/harnesses/RegistryCoordinatorHarness.t.sol b/test/harnesses/RegistryCoordinatorHarness.t.sol index 4644c276..9dede138 100644 --- a/test/harnesses/RegistryCoordinatorHarness.t.sol +++ b/test/harnesses/RegistryCoordinatorHarness.t.sol @@ -12,8 +12,9 @@ contract RegistryCoordinatorHarness is RegistryCoordinator, Test { IStakeRegistry _stakeRegistry, IBLSApkRegistry _blsApkRegistry, IIndexRegistry _indexRegistry, - IAVSDirectory _avsDirectory - ) RegistryCoordinator(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry, _avsDirectory) { + IAVSDirectory _avsDirectory, + IPauserRegistry _pauserRegistry + ) RegistryCoordinator(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry, _avsDirectory, _pauserRegistry) { _transferOwnership(msg.sender); } @@ -27,7 +28,7 @@ contract RegistryCoordinatorHarness is RegistryCoordinator, Test { // @notice exposes the internal `_registerOperator` function, overriding all access controls function _registerOperatorExternal( - address operator, + address operator, bytes32 operatorId, bytes calldata quorumNumbers, string memory socket, @@ -38,7 +39,7 @@ contract RegistryCoordinatorHarness is RegistryCoordinator, Test { // @notice exposes the internal `_deregisterOperator` function, overriding all access controls function _deregisterOperatorExternal( - address operator, + address operator, bytes calldata quorumNumbers ) external { _deregisterOperator(operator, quorumNumbers); diff --git a/test/integration/CoreRegistration.t.sol b/test/integration/CoreRegistration.t.sol index b9784dc6..f385c7e2 100644 --- a/test/integration/CoreRegistration.t.sol +++ b/test/integration/CoreRegistration.t.sol @@ -9,6 +9,7 @@ import { DelegationManager } from "eigenlayer-contracts/src/contracts/core/Deleg import { IDelegationManager, IDelegationManagerTypes } from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import { RewardsCoordinator } from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; import { IRewardsCoordinator } from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import { PermissionController } from "eigenlayer-contracts/src/contracts/permissions/PermissionController.sol"; contract Test_CoreRegistration is MockAVSDeployer { // Contracts @@ -27,7 +28,8 @@ contract Test_CoreRegistration is MockAVSDeployer { _deployMockEigenLayerAndAVS(); // Deploy New DelegationManager - DelegationManager delegationManagerImplementation = new DelegationManager(avsDirectoryMock, IStrategyManager(address(strategyManagerMock)), eigenPodManagerMock, allocationManagerMock, 0); + PermissionController permissionController; // TODO: Fix + DelegationManager delegationManagerImplementation = new DelegationManager(avsDirectoryMock, IStrategyManager(address(strategyManagerMock)), eigenPodManagerMock, allocationManagerMock, pauserRegistry, permissionController, 0); IStrategy[] memory initializeStrategiesToSetDelayBlocks = new IStrategy[](0); uint256[] memory initializeWithdrawalDelayBlocks = new uint256[](0); delegationManager = DelegationManager( @@ -49,7 +51,7 @@ contract Test_CoreRegistration is MockAVSDeployer { ); // Deploy New AVS Directory - AVSDirectory avsDirectoryImplementation = new AVSDirectory(delegationManager, 0); // TODO: Fix Config + AVSDirectory avsDirectoryImplementation = new AVSDirectory(delegationManager, pauserRegistry); // TODO: Fix Config avsDirectory = AVSDirectory( address( new TransparentUpgradeableProxy( @@ -82,7 +84,8 @@ contract Test_CoreRegistration is MockAVSDeployer { stakeRegistry, blsApkRegistry, indexRegistry, - avsDirectory + avsDirectory, + pauserRegistry ); // Upgrade Registry Coordinator & ServiceManager @@ -104,11 +107,7 @@ contract Test_CoreRegistration is MockAVSDeployer { // Register operator to EigenLayer cheats.prank(operator); delegationManager.registerAsOperator( - IDelegationManagerTypes.OperatorDetails({ - __deprecated_earningsReceiver: operator, - delegationApprover: address(0), - __deprecated_stakerOptOutWindowBlocks: 0 - }), + operator, // TODO: fix or parameterize 0, emptyStringForMetadataURI diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index 2c33bfa5..a162746c 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -21,6 +21,7 @@ import "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; import "eigenlayer-contracts/src/contracts/pods/EigenPodManager.sol"; import "eigenlayer-contracts/src/contracts/pods/EigenPod.sol"; import "eigenlayer-contracts/src/contracts/permissions/PauserRegistry.sol"; +import "eigenlayer-contracts/src/contracts/permissions/PermissionController.sol"; import "eigenlayer-contracts/src/test/mocks/ETHDepositMock.sol"; // Middleware contracts @@ -55,6 +56,7 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { EigenPod pod; ETHPOSDepositMock ethPOSDeposit; AllocationManager allocationManager; + PermissionController permissionController; // Base strategy implementation in case we want to create more strategies later StrategyBase baseStrategyImplementation; @@ -93,10 +95,23 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { uint256 constant MAX_STRATEGY_COUNT = 32; // From StakeRegistry.MAX_WEIGHING_FUNCTION_LENGTH uint96 constant DEFAULT_STRATEGY_MULTIPLIER = 1e18; // RewardsCoordinator + // Config Variables + /// @notice intervals(epochs) are 1 weeks + uint32 CALCULATION_INTERVAL_SECONDS = 7 days; + + /// @notice Max duration is 5 epochs (2 weeks * 5 = 10 weeks in seconds) uint32 MAX_REWARDS_DURATION = 70 days; + + /// @notice Lower bound start range is ~3 months into the past, multiple of CALCULATION_INTERVAL_SECONDS uint32 MAX_RETROACTIVE_LENGTH = 84 days; + /// @notice Upper bound start range is ~1 month into the future, multiple of CALCULATION_INTERVAL_SECONDS uint32 MAX_FUTURE_LENGTH = 28 days; - uint32 GENESIS_REWARDS_TIMESTAMP = 1_712_092_632; + /// @notice absolute min timestamp that a rewards can start at + uint32 GENESIS_REWARDS_TIMESTAMP = 1712188800; + /// @notice Equivalent to 100%, but in basis points. + uint16 internal constant ONE_HUNDRED_IN_BIPS = 10_000; + + uint32 defaultOperatorSplitBips = 1000; /// @notice Delay in timestamp before a posted root can be claimed against uint32 activationDelay = 7 days; /// @notice intervals(epochs) are 2 weeks @@ -147,9 +162,12 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") ) ); - // RewardsCoordinator = RewardsCoordinator( - // address(new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "")) - // ); + + permissionController = PermissionController(address(new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), ""))); + + rewardsCoordinator = RewardsCoordinator( + address(new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "")) + ); // Deploy EigenPod Contracts pod = new EigenPod( @@ -160,23 +178,31 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { eigenPodBeacon = new UpgradeableBeacon(address(pod)); + PermissionController permissionControllerImplementation = new PermissionController(); + // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs DelegationManager delegationImplementation = - new DelegationManager(avsDirectory, strategyManager, eigenPodManager, allocationManager, 0); + new DelegationManager(avsDirectory, strategyManager, eigenPodManager, allocationManager, pauserRegistry, permissionController, 0); StrategyManager strategyManagerImplementation = - new StrategyManager(delegationManager); + new StrategyManager(delegationManager, pauserRegistry); EigenPodManager eigenPodManagerImplementation = new EigenPodManager( - ethPOSDeposit, eigenPodBeacon, strategyManager, delegationManager + ethPOSDeposit, eigenPodBeacon, strategyManager, delegationManager, pauserRegistry + ); + console.log("HERE Impl"); + AVSDirectory avsDirectoryImplementation = new AVSDirectory(delegationManager, pauserRegistry); + + RewardsCoordinator rewardsCoordinatorImplementation = new RewardsCoordinator( + delegationManager, + IStrategyManager(address(strategyManager)), + allocationManager, + pauserRegistry, + permissionController, + CALCULATION_INTERVAL_SECONDS, + MAX_REWARDS_DURATION, + MAX_RETROACTIVE_LENGTH, + MAX_FUTURE_LENGTH, + GENESIS_REWARDS_TIMESTAMP ); - AVSDirectory avsDirectoryImplemntation = new AVSDirectory(delegationManager, 0); // TODO: fix config - // RewardsCoordinator rewardsCoordinatorImplementation = new RewardsCoordinator( - // delegationManager, - // IStrategyManager(address(strategyManager)), - // MAX_REWARDS_DURATION, - // MAX_RETROACTIVE_LENGTH, - // MAX_FUTURE_LENGTH, - // GENESIS_REWARDS_TIMESTAMP - // ); // Third, upgrade the proxy contracts to point to the implementations uint256 minWithdrawalDelayBlocks = 7 days / 12 seconds; @@ -219,35 +245,43 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { 0 // initialPausedStatus ) ); + console.log("HERE"); // AVSDirectory proxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(avsDirectory))), - address(avsDirectoryImplemntation), + address(avsDirectoryImplementation), abi.encodeWithSelector( AVSDirectory.initialize.selector, eigenLayerReputedMultisig, // initialOwner - pauserRegistry, + // pauserRegistry, 0 // initialPausedStatus ) ); - // // RewardsCoordinator - // proxyAdmin.upgradeAndCall( - // TransparentUpgradeableProxy(payable(address(rewardsCoordinator))), - // address(rewardsCoordinatorImplementation), - // abi.encodeWithSelector( - // RewardsCoordinator.initialize.selector, - // eigenLayerReputedMultisig, // initialOwner - // pauserRegistry, - // 0, // initialPausedStatus - // rewardsUpdater, - // activationDelay, - // calculationIntervalSeconds, - // globalCommissionBips - // ) - // ); + + console.log("HERE 2"); + proxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(permissionController))), + address(permissionControllerImplementation), + abi.encodeWithSelector( + PermissionController.initialize.selector + ) + ); + + proxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(rewardsCoordinator))), + address(rewardsCoordinatorImplementation), + abi.encodeWithSelector( + RewardsCoordinator.initialize.selector, + eigenLayerReputedMultisig, // initialOwner + 0, // initialPausedStatus + rewardsUpdater, + activationDelay, + defaultOperatorSplitBips // defaultSplitBips + ) + ); // Deploy and whitelist strategies - baseStrategyImplementation = new StrategyBase(strategyManager); + baseStrategyImplementation = new StrategyBase(strategyManager, pauserRegistry); for (uint256 i = 0; i < MAX_STRATEGY_COUNT; i++) { string memory number = uint256(i).toString(); string memory stratName = string.concat("StrategyToken", number); @@ -335,7 +369,7 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { uint32[] memory slashableStakeQuorumLookAheadPeriods = new uint32[](0); RegistryCoordinator registryCoordinatorImplementation = - new RegistryCoordinator(serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, avsDirectory); + new RegistryCoordinator(serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, avsDirectory, pauserRegistry); proxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(registryCoordinator))), address(registryCoordinatorImplementation), @@ -344,7 +378,6 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { registryCoordinatorOwner, churnApprover, ejector, - pauserRegistry, 0, /*initialPausedStatus*/ new IRegistryCoordinator.OperatorSetParam[](0), new uint96[](0), diff --git a/test/integration/User.t.sol b/test/integration/User.t.sol index ff31a7ed..b31914bd 100644 --- a/test/integration/User.t.sol +++ b/test/integration/User.t.sol @@ -57,7 +57,7 @@ contract User is Test { BLSApkRegistry blsApkRegistry; StakeRegistry stakeRegistry; IndexRegistry indexRegistry; - + TimeMachine timeMachine; uint churnApproverPrivateKey; @@ -147,12 +147,12 @@ contract User is Test { assertEq(churnQuorums.length, churnTargets.length, "User.registerOperatorWithChurn: input length mismatch"); assertTrue(churnBitmap.noBitsInCommon(standardBitmap), "User.registerOperatorWithChurn: input quorums have common bits"); - bytes memory allQuorums = + bytes memory allQuorums = churnBitmap .plus(standardBitmap) .bitmapToBytesArray(); - IRegistryCoordinator.OperatorKickParam[] memory kickParams + IRegistryCoordinator.OperatorKickParam[] memory kickParams = new IRegistryCoordinator.OperatorKickParam[](allQuorums.length); // this constructs OperatorKickParam[] in ascending quorum order @@ -244,13 +244,8 @@ contract User is Test { function registerAsOperator() public createSnapshot virtual { _log("registerAsOperator (core)"); - IDelegationManagerTypes.OperatorDetails memory details = IDelegationManagerTypes.OperatorDetails({ - __deprecated_earningsReceiver: address(this), - delegationApprover: address(0), - __deprecated_stakerOptOutWindowBlocks: 0 - }); - - delegationManager.registerAsOperator(details,0, NAME); + /// TODO: check + delegationManager.registerAsOperator(msg.sender,0, NAME); } // Deposit LSTs into the StrategyManager. This setup does not use the EPMgr or native ETH. @@ -270,14 +265,14 @@ contract User is Test { function exitEigenlayer() public createSnapshot virtual returns (IStrategy[] memory, uint256[] memory) { _log("exitEigenlayer (core)"); - IStrategy[] memory strategies; + IStrategy[] memory strategies; uint256[] memory shares; // = delegationManager.getDelegatableShares(address(this)); // TODO: Fix IDelegationManagerTypes.QueuedWithdrawalParams[] memory params = new IDelegationManager.QueuedWithdrawalParams[](1); params[0] = IDelegationManagerTypes.QueuedWithdrawalParams({ strategies: strategies, - shares: shares, + depositShares: shares, withdrawer: address(this) }); @@ -332,14 +327,14 @@ contract User is Test { emit log_named_string(string.concat(NAME, ".", s), quorums.toString()); } - // Operator0.registerOperatorWithChurn + // Operator0.registerOperatorWithChurn // - standardQuorums: 0x00010203... // - churnQuorums: 0x0405... // - churnTargets: Operator1, Operator2, ... function _logChurn( - string memory s, - bytes memory churnQuorums, - User[] memory churnTargets, + string memory s, + bytes memory churnQuorums, + User[] memory churnTargets, bytes memory standardQuorums ) internal virtual { emit log(string.concat(NAME, ".", s)); @@ -371,7 +366,7 @@ contract User_AltMethods is User { _; } - constructor(string memory name, uint _privKey, IBLSApkRegistry.PubkeyRegistrationParams memory _pubkeyParams) + constructor(string memory name, uint _privKey, IBLSApkRegistry.PubkeyRegistrationParams memory _pubkeyParams) User(name, _privKey, _pubkeyParams) {} /// @dev Rather than calling deregisterOperator, this pranks the ejector and calls @@ -405,6 +400,6 @@ contract User_AltMethods is User { operatorsPerQuorum[i] = Sort.sortAddresses(operatorsPerQuorum[i]); } - registryCoordinator.updateOperatorsForQuorum(operatorsPerQuorum, allQuorums); + registryCoordinator.updateOperatorsForQuorum(operatorsPerQuorum, allQuorums); } } diff --git a/test/mocks/AVSDirectoryMock.sol b/test/mocks/AVSDirectoryMock.sol index 597a09a1..5e4c6f77 100644 --- a/test/mocks/AVSDirectoryMock.sol +++ b/test/mocks/AVSDirectoryMock.sol @@ -1,17 +1,23 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.12; -import {IAVSDirectory, OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IAVSDirectory } from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; contract AVSDirectoryMock is IAVSDirectory { + function initialize( + address initialOwner, + uint256 initialPausedStatus + ) external {} + function createOperatorSets( uint32[] calldata operatorSetIds ) external {} - function becomeOperatorSetAVS() external {} + function becomeOperatorSetAVS() external {} function migrateOperatorsToOperatorSets( address[] calldata operators, @@ -24,11 +30,6 @@ contract AVSDirectoryMock is IAVSDirectory { ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature ) external {} - function deregisterOperatorFromOperatorSets( - address operator, - uint32[] calldata operatorSetIds - ) external {} - function forceDeregisterFromOperatorSets( address operator, address avs, @@ -36,32 +37,37 @@ contract AVSDirectoryMock is IAVSDirectory { ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature ) external {} - function registerOperatorToAVS( + function deregisterOperatorFromOperatorSets( address operator, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + uint32[] calldata operatorSetIds ) external {} - function deregisterOperatorFromAVS(address operator) external {} + function addStrategiesToOperatorSet( + uint32 operatorSetId, + IStrategy[] calldata strategies + ) external {} + + function removeStrategiesFromOperatorSet( + uint32 operatorSetId, + IStrategy[] calldata strategies + ) external {} function updateAVSMetadataURI( string calldata metadataURI ) external {} - function cancelSalt(bytes32 salt) external {} + function cancelSalt(bytes32 salt) external {} - function operatorSaltIsSpent( + function registerOperatorToAVS( address operator, - bytes32 salt - ) external view returns (bool) {} + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external {} - function isMember( - address operator, - OperatorSet memory operatorSet - ) external view returns (bool) {} + function deregisterOperatorFromAVS(address operator) external {} - function isOperatorSlashable( + function operatorSaltIsSpent( address operator, - OperatorSet memory operatorSet + bytes32 salt ) external view returns (bool) {} function isOperatorSetAVS( @@ -73,35 +79,9 @@ contract AVSDirectoryMock is IAVSDirectory { uint32 operatorSetId ) external view returns (bool) {} - function isOperatorSetBatch( - OperatorSet[] calldata operatorSets - ) external view returns (bool) {} - - function operatorSetsMemberOfAtIndex( - address operator, - uint256 index - ) external view returns (OperatorSet memory) {} - - function operatorSetMemberAtIndex( - OperatorSet memory operatorSet, - uint256 index - ) external view returns (address) {} - - function getOperatorSetsOfOperator( - address operator, - uint256 start, - uint256 length - ) external view returns (OperatorSet[] memory operatorSets) {} - - function getOperatorsInOperatorSet( - OperatorSet memory operatorSet, - uint256 start, - uint256 length - ) external view returns (address[] memory operators) {} - - function getNumOperatorsInOperatorSet( - OperatorSet memory operatorSet - ) external view returns (uint256) {} + function getNumOperatorSetsOfOperator( + address operator + ) external view returns (uint256) {} function inTotalOperatorSets( address operator @@ -131,13 +111,15 @@ contract AVSDirectoryMock is IAVSDirectory { function OPERATOR_AVS_REGISTRATION_TYPEHASH() external view - returns (bytes32) + + returns (bytes32) {} function OPERATOR_SET_REGISTRATION_TYPEHASH() external view - returns (bytes32) + + returns (bytes32) {} function operatorSetStatus( @@ -147,16 +129,9 @@ contract AVSDirectoryMock is IAVSDirectory { ) external view - returns (bool registered, uint32 lastDeregisteredTimestamp) - {} - function getNumOperatorSetsOfOperator( - address operator - ) external view returns (uint256) {} - - function getStrategiesInOperatorSet( - OperatorSet memory operatorSet - ) external view returns (IStrategy[] memory) {} + returns (bool registered, uint32 lastDeregisteredTimestamp) + {} function initialize( address initialOwner, @@ -164,10 +139,36 @@ contract AVSDirectoryMock is IAVSDirectory { uint256 initialPausedStatus ) external {} - function removeStrategiesFromOperatorSet( - uint32 operatorSetId, - IStrategy[] calldata strategies - ) external {} + function operatorSetMemberAtIndex( + OperatorSet memory operatorSet, + uint256 index + ) external view returns (address) {} + + function getOperatorsInOperatorSet( + OperatorSet memory operatorSet, + uint256 start, + uint256 length + ) external view returns (address[] memory operators) {} + + function getStrategiesInOperatorSet( + OperatorSet memory operatorSet + ) external view returns (IStrategy[] memory strategies) {} + + function getNumOperatorsInOperatorSet( + OperatorSet memory operatorSet + ) external view returns (uint256) {} - function addStrategiesToOperatorSet(uint32 operatorSetId, IStrategy[] calldata strategies) external {} -} + function isMember( + address operator, + OperatorSet memory operatorSet + ) external view returns (bool) {} + + function isOperatorSlashable( + address operator, + OperatorSet memory operatorSet + ) external view returns (bool) {} + + function isOperatorSetBatch( + OperatorSet[] calldata operatorSets + ) external view returns (bool) {} +} \ No newline at end of file diff --git a/test/mocks/AVSRegistrarMock.sol b/test/mocks/AVSRegistrarMock.sol new file mode 100644 index 00000000..ce4ce2bc --- /dev/null +++ b/test/mocks/AVSRegistrarMock.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import {AVSRegistrar} from "../../src/AVSRegistrar.sol"; + +contract AVSRegistrarMock is AVSRegistrar { + function registerOperator( + address operator, + uint32[] calldata operatorSetIds, + bytes calldata data + ) external override {} + + function deregisterOperator( + address operator, + uint32[] calldata operatorSetIds + ) external override {} +} diff --git a/test/mocks/AllocationManagerMock.sol b/test/mocks/AllocationManagerMock.sol index 1436882e..adf06c62 100644 --- a/test/mocks/AllocationManagerMock.sol +++ b/test/mocks/AllocationManagerMock.sol @@ -1,83 +1,170 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.12; -import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManager, OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAVSRegistrar } from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; -import {OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; - -contract AllocationManagerMock is IAllocationManager { +contract AllocationManagerIntermediate is IAllocationManager { function initialize( address initialOwner, - IPauserRegistry _pauserRegistry, uint256 initialPausedStatus - ) external override {} + ) external virtual {} - function slashOperator(SlashingParams calldata params) external override {} + function slashOperator( + address avs, + SlashingParams calldata params + ) external virtual {} function modifyAllocations( - MagnitudeAllocation[] calldata allocations - ) external override {} + address operator, + AllocateParams[] calldata params + ) external virtual {} function clearDeallocationQueue( address operator, IStrategy[] calldata strategies, - uint16[] calldata numToComplete - ) external override {} + uint16[] calldata numToClear + ) external virtual {} + + function registerForOperatorSets( + address operator, + RegisterParams calldata params + ) external virtual {} + + function deregisterFromOperatorSets( + DeregisterParams calldata params + ) external virtual {} function setAllocationDelay( address operator, uint32 delay - ) external override {} + ) external virtual {} + + function setAVSRegistrar( + address avs, + IAVSRegistrar registrar + ) external virtual {} - function setAllocationDelay(uint32 delay) external override {} + function updateAVSMetadataURI( + address avs, + string calldata metadataURI + ) external virtual {} + + function createOperatorSets( + address avs, + CreateSetParams[] calldata params + ) external virtual {} + + function addStrategiesToOperatorSet( + address avs, + uint32 operatorSetId, + IStrategy[] calldata strategies + ) external virtual {} + + function removeStrategiesFromOperatorSet( + address avs, + uint32 operatorSetId, + IStrategy[] calldata strategies + ) external virtual {} + + function getOperatorSetCount( + address avs + ) external view virtual returns (uint256) {} + + function getAllocatedSets( + address operator + ) external view virtual returns (OperatorSet[] memory) {} + + function getAllocatedStrategies( + address operator, + OperatorSet memory operatorSet + ) external view virtual returns (IStrategy[] memory) {} + + function getAllocation( + address operator, + OperatorSet memory operatorSet, + IStrategy strategy + ) external view virtual returns (Allocation memory) {} + + function getAllocations( + address[] memory operators, + OperatorSet memory operatorSet, + IStrategy strategy + ) external view virtual returns (Allocation[] memory) {} - function getAllocationInfo( + function getStrategyAllocations( address operator, IStrategy strategy ) external view - override - returns (OperatorSet[] memory, MagnitudeInfo[] memory) + virtual + returns (OperatorSet[] memory, Allocation[] memory) {} - function getAllocationInfo( + function getAllocatableMagnitude( address operator, - IStrategy strategy, - OperatorSet[] calldata operatorSets - ) external view override returns (MagnitudeInfo[] memory) {} - - function getAllocationInfo( - OperatorSet calldata operatorSet, - IStrategy[] calldata strategies, - address[] calldata operators - ) external view override returns (MagnitudeInfo[][] memory) {} + IStrategy strategy + ) external view virtual returns (uint64) {} - function getAllocatableMagnitude( + function getMaxMagnitude( address operator, IStrategy strategy - ) external view override returns (uint64) {} + ) external view virtual returns (uint64) {} function getMaxMagnitudes( address operator, IStrategy[] calldata strategies - ) external view override returns (uint64[] memory) {} + ) external view virtual returns (uint64[] memory) {} - function getMaxMagnitudesAtTimestamp( + function getMaxMagnitudes( + address[] calldata operators, + IStrategy strategy + ) external view virtual returns (uint64[] memory) {} + + function getMaxMagnitudesAtBlock( address operator, IStrategy[] calldata strategies, - uint32 timestamp - ) external view override returns (uint64[] memory) {} + uint32 blockNumber + ) external view virtual returns (uint64[] memory) {} function getAllocationDelay( address operator - ) external view override returns (bool isSet, uint32 delay) {} + ) external view virtual returns (bool isSet, uint32 delay) {} + + function getRegisteredSets( + address operator + ) external view virtual returns (OperatorSet[] memory operatorSets) {} + + function isOperatorSet( + OperatorSet memory operatorSet + ) external view virtual returns (bool) {} + + function getMembers( + OperatorSet memory operatorSet + ) external view virtual returns (address[] memory operators) {} + + function getMemberCount( + OperatorSet memory operatorSet + ) external view virtual returns (uint256) {} + + function getAVSRegistrar( + address avs + ) external view virtual returns (IAVSRegistrar) {} + + function getStrategiesInOperatorSet( + OperatorSet memory operatorSet + ) external view virtual returns (IStrategy[] memory strategies) {} + + function getMinimumSlashableStake( + OperatorSet memory operatorSet, + address[] memory operators, + IStrategy[] memory strategies, + uint32 futureBlock + ) external view virtual returns (uint256[][] memory slashableStake) {} +} + +contract AllocationManagerMock is AllocationManagerIntermediate { - function getMinDelegatedAndSlashableOperatorShares( - OperatorSet calldata operatorSet, - address[] calldata operators, - IStrategy[] calldata strategies, - uint32 beforeTimestamp - ) external view override returns (uint256[][] memory, uint256[][] memory) {} } \ No newline at end of file diff --git a/test/mocks/DelegationMock.sol b/test/mocks/DelegationMock.sol index 9743fb14..3f057669 100644 --- a/test/mocks/DelegationMock.sol +++ b/test/mocks/DelegationMock.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.12; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {console2 as console} from "forge-std/Test.sol"; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; @@ -11,319 +12,261 @@ import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPa import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {SlashingLib} from "eigenlayer-contracts/src/contracts/libraries/SlashingLib.sol"; -contract DelegationMock is IDelegationManager { - using SlashingLib for uint256; - - mapping(address => bool) public isOperator; - mapping(address => mapping(IStrategy => uint256)) public operatorShares; - - function setIsOperator( - address operator, - bool _isOperatorReturnValue - ) external { - isOperator[operator] = _isOperatorReturnValue; - } - - /// @notice returns the total number of shares in `strategy` that are delegated to `operator`. - function setOperatorShares( - address operator, - IStrategy strategy, - uint256 shares - ) external { - operatorShares[operator][strategy] = shares; - } - - mapping(address => address) public delegatedTo; +contract DelegationIntermediate is IDelegationManager { + function initialize( + address initialOwner, + uint256 initialPausedStatus + ) external virtual {} function registerAsOperator( - OperatorDetails calldata /*registeringOperatorDetails*/, - string calldata /*metadataURI*/ - ) external pure {} + OperatorDetails calldata registeringOperatorDetails, + uint32 allocationDelay, + string calldata metadataURI + ) external virtual {} - function updateOperatorMetadataURI( - string calldata /*metadataURI*/ - ) external pure {} + function modifyOperatorDetails( + OperatorDetails calldata newOperatorDetails + ) external virtual {} - function updateAVSMetadataURI( - string calldata /*metadataURI*/ - ) external pure {} + function updateOperatorMetadataURI( + string calldata metadataURI + ) external virtual {} function delegateTo( address operator, - SignatureWithExpiry memory /*approverSignatureAndExpiry*/, - bytes32 /*approverSalt*/ - ) external { - delegatedTo[msg.sender] = operator; - } - - function modifyOperatorDetails( - OperatorDetails calldata /*newOperatorDetails*/ - ) external pure {} - - function delegateToBySignature( - address /*staker*/, - address /*operator*/, - SignatureWithExpiry memory /*stakerSignatureAndExpiry*/, - SignatureWithExpiry memory /*approverSignatureAndExpiry*/, - bytes32 /*approverSalt*/ - ) external pure {} + SignatureWithExpiry memory approverSignatureAndExpiry, + bytes32 approverSalt + ) external virtual {} function undelegate( address staker - ) external returns (bytes32[] memory withdrawalRoot) { - delegatedTo[staker] = address(0); - return withdrawalRoot; - } - - function increaseDelegatedShares( - address /*staker*/, - IStrategy /*strategy*/, - uint256 /*shares*/ - ) external pure {} - - function operatorDetails( - address operator - ) external pure returns (OperatorDetails memory) { - OperatorDetails memory returnValue = OperatorDetails({ - __deprecated_earningsReceiver: operator, - delegationApprover: operator, - __deprecated_stakerOptOutWindowBlocks: 0 - }); - return returnValue; - } - - function beaconChainETHStrategy() external pure returns (IStrategy) {} - - function earningsReceiver(address operator) external pure returns (address) { - return operator; - } - - function delegationApprover( - address operator - ) external pure returns (address) { - return operator; - } - - function stakerOptOutWindowBlocks( - address /*operator*/ - ) external pure returns (uint256) { - return 0; - } - - function minWithdrawalDelayBlocks() external view returns (uint256) { - return 50400; - } - - /** - * @notice Minimum delay enforced by this contract per Strategy for completing queued withdrawals. Measured in blocks, and adjustable by this contract's owner, - * up to a maximum of `MAX_WITHDRAWAL_DELAY_BLOCKS`. Minimum value is 0 (i.e. no delay enforced). - */ - function strategyWithdrawalDelayBlocks( - IStrategy /*strategy*/ - ) external view returns (uint256) { - return 0; - } - - function getOperatorShares( - address operator, - IStrategy[] memory strategies - ) external view returns (uint256[] memory) { - uint256[] memory shares = new uint256[](strategies.length); - for (uint256 i = 0; i < strategies.length; ++i) { - shares[i] = operatorShares[operator][strategies[i]]; - } - return shares; - } - - function getWithdrawalDelay( - IStrategy[] calldata /*strategies*/ - ) public view returns (uint256) { - return 0; - } - - function isDelegated(address staker) external view returns (bool) { - return (delegatedTo[staker] != address(0)); - } - - function isNotDelegated(address /*staker*/) external pure returns (bool) {} - - // function isOperator(address /*operator*/) external pure returns (bool) {} - - function stakerNonce(address /*staker*/) external pure returns (uint256) {} - - function delegationApproverSaltIsSpent( - address /*delegationApprover*/, - bytes32 /*salt*/ - ) external pure returns (bool) {} - - function calculateCurrentStakerDelegationDigestHash( - address /*staker*/, - address /*operator*/, - uint256 /*expiry*/ - ) external view returns (bytes32) {} - - function calculateStakerDelegationDigestHash( - address /*staker*/, - uint256 /*stakerNonce*/, - address /*operator*/, - uint256 /*expiry*/ - ) external view returns (bytes32) {} - - function calculateDelegationApprovalDigestHash( - address /*staker*/, - address /*operator*/, - address /*_delegationApprover*/, - bytes32 /*approverSalt*/, - uint256 /*expiry*/ - ) external view returns (bytes32) {} - - function calculateStakerDigestHash( - address /*staker*/, - address /*operator*/, - uint256 /*expiry*/ - ) external pure returns (bytes32 stakerDigestHash) {} - - function calculateApproverDigestHash( - address /*staker*/, - address /*operator*/, - uint256 /*expiry*/ - ) external pure returns (bytes32 approverDigestHash) {} - - function calculateOperatorAVSRegistrationDigestHash( - address /*operator*/, - address /*avs*/, - bytes32 /*salt*/, - uint256 /*expiry*/ - ) external pure returns (bytes32 digestHash) {} - - function DOMAIN_TYPEHASH() external view returns (bytes32) {} - - function STAKER_DELEGATION_TYPEHASH() external view returns (bytes32) {} - - function DELEGATION_APPROVAL_TYPEHASH() external view returns (bytes32) {} - - function domainSeparator() external view returns (bytes32) {} - - function cumulativeWithdrawalsQueued( - address staker - ) external view returns (uint256) {} - - function calculateWithdrawalRoot( - Withdrawal memory withdrawal - ) external pure returns (bytes32) {} - - function operatorSaltIsSpent( - address avs, - bytes32 salt - ) external view returns (bool) {} + ) external virtual returns (bytes32[] memory withdrawalRoots) {} function queueWithdrawals( - QueuedWithdrawalParams[] calldata queuedWithdrawalParams - ) external returns (bytes32[] memory) {} + QueuedWithdrawalParams[] calldata params + ) external virtual returns (bytes32[] memory) {} + + function completeQueuedWithdrawals( + IERC20[][] calldata tokens, + bool[] calldata receiveAsTokens, + uint256 numToComplete + ) external virtual {} function completeQueuedWithdrawal( Withdrawal calldata withdrawal, IERC20[] calldata tokens, - uint256 middlewareTimesIndex, bool receiveAsTokens - ) external {} + ) external virtual {} function completeQueuedWithdrawals( Withdrawal[] calldata withdrawals, IERC20[][] calldata tokens, - uint256[] calldata middlewareTimesIndexes, bool[] calldata receiveAsTokens - ) external {} + ) external virtual {} - // onlyDelegationManager functions in StrategyManager - function addShares( - IStrategyManager strategyManager, + function increaseDelegatedShares( address staker, - IERC20 token, IStrategy strategy, - uint256 shares - ) external { - strategyManager.addShares(staker, strategy, token, shares); - } + uint256 existingDepositShares, + uint256 addedShares + ) external virtual {} - function removeShares( - IStrategyManager strategyManager, + function decreaseBeaconChainScalingFactor( address staker, - IStrategy strategy, - uint256 shares - ) external { - strategyManager.removeDepositShares(staker, strategy, shares); - } - - function withdrawSharesAsTokens( - IStrategyManager strategyManager, - address recipient, - IStrategy strategy, - uint256 shares, - IERC20 token - ) external { - strategyManager.withdrawSharesAsTokens(recipient, strategy, token, shares); - } + uint256 existingShares, + uint64 proportionOfOldBalance + ) external virtual {} - function registerAsOperator( - OperatorDetails calldata registeringOperatorDetails, - uint32 allocationDelay, - string calldata metadataURI - ) external override {} + function burnOperatorShares( + address operator, + IStrategy strategy, + uint64 prevMaxMagnitude, + uint64 newMaxMagnitude + ) external virtual {} function completeQueuedWithdrawal( Withdrawal calldata withdrawal, IERC20[] calldata tokens, + uint256 middlewareTimesIndex, bool receiveAsTokens - ) external override {} + ) external virtual {} function completeQueuedWithdrawals( Withdrawal[] calldata withdrawals, IERC20[][] calldata tokens, + uint256[] calldata middlewareTimesIndexes, bool[] calldata receiveAsTokens - ) external override {} + ) external virtual {} - function decreaseBeaconChainScalingFactor( - address staker, - uint256 existingDepositShares, - uint64 proportionOfOldBalance - ) external override {} + function delegatedTo( + address staker + ) external view virtual returns (address) {} - function decreaseOperatorShares( - address operator, - IStrategy strategy, - uint64 previousTotalMagnitude, - uint64 newTotalMagnitude - ) external override {} + function delegationApproverSaltIsSpent( + address _delegationApprover, + bytes32 salt + ) external view virtual returns (bool) {} - function increaseDelegatedShares( - address staker, - IStrategy strategy, - uint256 existingDepositShares, - uint256 addedShares - ) external override {} + function cumulativeWithdrawalsQueued( + address staker + ) external view virtual returns (uint256) {} - function initialize( - address initialOwner, - IPauserRegistry _pauserRegistry, - uint256 initialPausedStatus - ) external override {} + function isDelegated(address staker) external view virtual returns (bool) {} + + function isOperator(address operator) external view virtual returns (bool) {} + + function operatorDetails( + address operator + ) external view virtual returns (OperatorDetails memory) {} + + function delegationApprover( + address operator + ) external view virtual returns (address) {} + + function getOperatorShares( + address operator, + IStrategy[] memory strategies + ) external view virtual returns (uint256[] memory) {} function getOperatorsShares( address[] memory operators, IStrategy[] memory strategies - ) external view override returns (uint256[][] memory) {} + ) external view virtual returns (uint256[][] memory) {} + + function getSlashableSharesInQueue( + address operator, + IStrategy strategy + ) external view virtual returns (uint256) {} function getWithdrawableShares( address staker, IStrategy[] memory strategies - ) external view override returns (uint256[] memory withdrawableShares) {} + ) + external + view + virtual + override + returns ( + uint256[] memory withdrawableShares, + uint256[] memory depositShares + ) + {} function getDepositedShares( address staker - ) external view override returns (IStrategy[] memory, uint256[] memory) {} + ) external view virtual returns (IStrategy[] memory, uint256[] memory) {} - function getCompletableTimestamp( - uint32 startTimestamp - ) external view override returns (uint32 completableTimestamp) {} + function depositScalingFactor( + address staker, + IStrategy strategy + ) external view virtual returns (uint256) {} + + function getBeaconChainSlashingFactor( + address staker + ) external view virtual returns (uint64) {} + + function MIN_WITHDRAWAL_DELAY_BLOCKS() + external + view + virtual + override + returns (uint32) + {} + + function getQueuedWithdrawals( + address staker + ) + external + view + virtual + override + returns (Withdrawal[] memory withdrawals, uint256[][] memory shares) + {} + + function calculateWithdrawalRoot( + Withdrawal memory withdrawal + ) external pure virtual returns (bytes32) {} + + function calculateDelegationApprovalDigestHash( + address staker, + address operator, + address _delegationApprover, + bytes32 approverSalt, + uint256 expiry + ) external view virtual returns (bytes32) {} + + function beaconChainETHStrategy() + external + view + virtual + override + returns (IStrategy) + {} + + function DELEGATION_APPROVAL_TYPEHASH() + external + view + virtual + override + returns (bytes32) + {} + + function registerAsOperator( + address initDelegationApprover, + uint32 allocationDelay, + string calldata metadataURI + ) external virtual {} + + function modifyOperatorDetails( + address operator, + address newDelegationApprover + ) external virtual {} + + function updateOperatorMetadataURI( + address operator, + string calldata metadataURI + ) external virtual {} + + function redelegate( + address newOperator, + SignatureWithExpiry memory newOperatorApproverSig, + bytes32 approverSalt + ) external virtual returns (bytes32[] memory withdrawalRoots) {} + + function decreaseDelegatedShares( + address staker, + uint256 curDepositShares, + uint64 prevBeaconChainSlashingFactor, + uint256 wadSlashed + ) external virtual {} } + +contract DelegationMock is DelegationIntermediate { + mapping(address => bool) internal _isOperator; + mapping(address => mapping(IStrategy => uint256)) internal _weightOf; + function setOperatorShares(address operator, IStrategy strategy, uint256 actualWeight) external { + _weightOf[operator][strategy] = actualWeight; + } + + function setIsOperator(address operator, bool isOperator) external { + _isOperator[operator] = isOperator; + } + + function isOperator(address operator) external view override returns (bool) { + return _isOperator[operator]; + } + + function getOperatorShares( + address operator, + IStrategy[] calldata strategies + ) external view override returns (uint256[] memory) { + uint256[] memory shares = new uint256[](strategies.length); + for (uint256 i = 0; i < strategies.length; i++) { + shares[i] = _weightOf[operator][strategies[i]]; + } + return shares; + } + function minWithdrawalDelayBlocks() external view returns (uint32){ + return 100; + } +} \ No newline at end of file diff --git a/test/mocks/EigenPodManagerMock.sol b/test/mocks/EigenPodManagerMock.sol index afdd6189..cefd5b7a 100644 --- a/test/mocks/EigenPodManagerMock.sol +++ b/test/mocks/EigenPodManagerMock.sol @@ -11,8 +11,8 @@ contract EigenPodManagerMock is Test, Pausable, IEigenPodManager { mapping(address => int256) public podShares; - constructor(IPauserRegistry _pauserRegistry) { - _initializePauser(_pauserRegistry, 0); + constructor(IPauserRegistry _pauserRegistry) Pausable(_pauserRegistry){ + _setPausedStatus(0); } function podOwnerShares(address podOwner) external view returns (int256) { @@ -67,9 +67,6 @@ contract EigenPodManagerMock is Test, Pausable, IEigenPodManager { function beaconChainETHStrategy() external view returns (IStrategy) { } - function addShares(address staker, IStrategy strategy, IERC20 token, uint256 shares) external { - } - function removeDepositShares(address staker, IStrategy strategy, uint256 depositSharesToRemove) external { } @@ -77,4 +74,24 @@ contract EigenPodManagerMock is Test, Pausable, IEigenPodManager { } function withdrawSharesAsTokens(address staker, IStrategy strategy, IERC20 token, uint256 shares) external{} + + function addShares( + address staker, + IStrategy strategy, + IERC20 token, + uint256 shares + ) external returns (uint256, uint256) { + } + + function beaconChainSlashingFactor( + address staker + ) external view returns (uint64) { + } + + function recordBeaconChainETHBalanceUpdate( + address podOwner, + uint256 prevRestakedBalanceWei, + int256 balanceDeltaWei + ) external { + } } \ No newline at end of file diff --git a/test/mocks/PermissionControllerMock.sol b/test/mocks/PermissionControllerMock.sol new file mode 100644 index 00000000..7501a9fa --- /dev/null +++ b/test/mocks/PermissionControllerMock.sol @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +import {IPermissionController} from "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; + +contract PermissionControllerIntermediate is IPermissionController { + function addPendingAdmin(address account, address admin) external virtual {} + + function removePendingAdmin( + address account, + address admin + ) external virtual {} + + function acceptAdmin(address account) external virtual {} + + function removeAdmin(address account, address admin) external virtual {} + + function setAppointee( + address account, + address appointee, + address target, + bytes4 selector + ) external virtual {} + + function removeAppointee( + address account, + address appointee, + address target, + bytes4 selector + ) external virtual {} + + function isAdmin( + address account, + address caller + ) external view virtual returns (bool) {} + + function isPendingAdmin( + address account, + address pendingAdmin + ) external view virtual returns (bool) {} + + function getAdmins( + address account + ) external view virtual returns (address[] memory) {} + + function getPendingAdmins( + address account + ) external view virtual returns (address[] memory) {} + + function canCall( + address account, + address caller, + address target, + bytes4 selector + ) external virtual returns (bool) {} + + function getAppointeePermissions( + address account, + address appointee + ) external virtual returns (address[] memory, bytes4[] memory) {} + + function getAppointees( + address account, + address target, + bytes4 selector + ) external virtual returns (address[] memory) {} +} + +contract PermissionControllerMock is PermissionControllerIntermediate { + mapping(address => mapping(address => mapping(address => mapping(bytes4 => bool)))) internal _canCall; + + function setCanCall( + address account, + address caller, + address target, + bytes4 selector + ) external { + _canCall[account][caller][target][selector] = true; + } + + function canCall( + address account, + address caller, + address target, + bytes4 selector + ) external override returns (bool) { + if (account == caller) return true; + return _canCall[account][caller][target][selector]; + } + +} diff --git a/test/mocks/RewardsCoordinatorMock.sol b/test/mocks/RewardsCoordinatorMock.sol index db403ac6..3a8e9622 100644 --- a/test/mocks/RewardsCoordinatorMock.sol +++ b/test/mocks/RewardsCoordinatorMock.sol @@ -8,126 +8,165 @@ import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces import "./AVSDirectoryMock.sol"; contract RewardsCoordinatorMock is IRewardsCoordinator { - /// @notice The address of the entity that can update the contract with new merkle roots - function rewardsUpdater() external view returns (address) {} + function initialize( + address initialOwner, + uint256 initialPausedStatus, + address _rewardsUpdater, + uint32 _activationDelay, + uint16 _defaultSplitBips + ) external override {} - function CALCULATION_INTERVAL_SECONDS() external view returns (uint32) {} + function createAVSRewardsSubmission( + address avs, + RewardsSubmission[] calldata rewardsSubmissions + ) external override {} - function MAX_REWARDS_DURATION() external view returns (uint32) {} + function createRewardsForAllSubmission( + RewardsSubmission[] calldata rewardsSubmissions + ) external override {} - function MAX_RETROACTIVE_LENGTH() external view returns (uint32) {} + function createRewardsForAllEarners( + RewardsSubmission[] calldata rewardsSubmissions + ) external override {} + + function createOperatorDirectedAVSRewardsSubmission( + address avs, + OperatorDirectedRewardsSubmission[] + calldata operatorDirectedRewardsSubmissions + ) external override {} - function MAX_FUTURE_LENGTH() external view returns (uint32) {} + function processClaim( + RewardsMerkleClaim calldata claim, + address recipient + ) external override {} - function GENESIS_REWARDS_TIMESTAMP() external view returns (uint32) {} + function processClaims( + RewardsMerkleClaim[] calldata claims, + address recipient + ) external override {} - function activationDelay() external view returns (uint32) {} + function submitRoot( + bytes32 root, + uint32 rewardsCalculationEndTimestamp + ) external override {} + + function disableRoot(uint32 rootIndex) external override {} + + function setClaimerFor(address claimer) external override {} + + function setClaimerFor(address earner, address claimer) external override {} + + function setActivationDelay(uint32 _activationDelay) external override {} + + function setDefaultOperatorSplit(uint16 split) external override {} + + function setOperatorAVSSplit( + address operator, + address avs, + uint16 split + ) external override {} + + function setOperatorPISplit( + address operator, + uint16 split + ) external override {} + + function setRewardsUpdater(address _rewardsUpdater) external override {} + + function setRewardsForAllSubmitter( + address _submitter, + bool _newValue + ) external override {} + + function activationDelay() external view override returns (uint32) {} + + function currRewardsCalculationEndTimestamp() + external + view + override + returns (uint32) + {} - function claimerFor(address earner) external view returns (address) {} + function claimerFor( + address earner + ) external view override returns (address) {} function cumulativeClaimed( address claimer, IERC20 token - ) external view returns (uint256) {} + ) external view override returns (uint256) {} - function globalOperatorCommissionBips() external view returns (uint16) {} + function defaultOperatorSplitBips() external view override returns (uint16) {} - function operatorCommissionBips( + function getOperatorAVSSplit( address operator, address avs - ) external view returns (uint16) {} + ) external view override returns (uint16) {} + + function getOperatorPISplit( + address operator + ) external view override returns (uint16) {} function calculateEarnerLeafHash( EarnerTreeMerkleLeaf calldata leaf - ) external pure returns (bytes32) {} + ) external pure override returns (bytes32) {} function calculateTokenLeafHash( TokenTreeMerkleLeaf calldata leaf - ) external pure returns (bytes32) {} + ) external pure override returns (bytes32) {} function checkClaim( RewardsMerkleClaim calldata claim - ) external view returns (bool) {} + ) external view override returns (bool) {} - function currRewardsCalculationEndTimestamp() + function getDistributionRootsLength() external view - returns (uint32) + override + returns (uint256) {} - function getRootIndexFromHash( - bytes32 rootHash - ) external view returns (uint32) {} - - function getDistributionRootsLength() external view returns (uint256) {} - function getDistributionRootAtIndex( uint256 index - ) external view returns (DistributionRoot memory) {} + ) external view override returns (DistributionRoot memory) {} - function getCurrentClaimableDistributionRoot() + function getCurrentDistributionRoot() external view + override returns (DistributionRoot memory) {} - function getCurrentDistributionRoot() + function getCurrentClaimableDistributionRoot() external view + override returns (DistributionRoot memory) {} - /// EXTERNAL FUNCTIONS /// - - function disableRoot(uint32 rootIndex) external {} - - function createAVSRewardsSubmission( - RewardsSubmission[] calldata rewardsSubmissions - ) external {} - - function createRewardsForAllSubmission( - RewardsSubmission[] calldata rewardsSubmission - ) external {} - - function processClaim( - RewardsMerkleClaim calldata claim, - address recipient - ) external {} - - function submitRoot( - bytes32 root, - uint32 rewardsCalculationEndTimestamp - ) external {} - - function setRewardsUpdater(address _rewardsUpdater) external {} + function getRootIndexFromHash( + bytes32 rootHash + ) external view override returns (uint32) {} - function setActivationDelay(uint32 _activationDelay) external {} + function rewardsUpdater() external view override returns (address) {} - function setGlobalOperatorCommission(uint16 _globalCommissionBips) external {} + function CALCULATION_INTERVAL_SECONDS() + external + view + override + returns (uint32) + {} - function setClaimerFor(address claimer) external {} + function MAX_REWARDS_DURATION() external view override returns (uint32) {} - /** - * @notice Sets the permissioned `payAllForRangeSubmitter` address which can submit payAllForRange - * @dev Only callable by the contract owner - * @param _submitter The address of the payAllForRangeSubmitter - * @param _newValue The new value for isPayAllForRangeSubmitter - */ - function setRewardsForAllSubmitter( - address _submitter, - bool _newValue - ) external {} + function MAX_RETROACTIVE_LENGTH() external view override returns (uint32) {} - function createRewardsForAllEarners( - RewardsSubmission[] calldata rewardsSubmissions - ) external override {} + function MAX_FUTURE_LENGTH() external view override returns (uint32) {} - function initialize( - address initialOwner, - IPauserRegistry _pauserRegistry, - uint256 initialPausedStatus, - address _rewardsUpdater, - uint32 _activationDelay, - uint16 _globalCommissionBips - ) external {} + function GENESIS_REWARDS_TIMESTAMP() + external + view + override + returns (uint32) + {} } \ No newline at end of file diff --git a/test/unit/AVSRegistrar.t.sol b/test/unit/AVSRegistrar.t.sol new file mode 100644 index 00000000..deea28a2 --- /dev/null +++ b/test/unit/AVSRegistrar.t.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import {MockAVSDeployer} from "../utils/MockAVSDeployer.sol"; +import {BN254} from "../../src/libraries/BN254.sol"; +import {IRegistryCoordinator} from "../../src/interfaces/IRegistryCoordinator.sol"; +import {IStakeRegistry} from "../../src/interfaces/IStakeRegistry.sol"; +import {BitmapUtils} from "../../src/libraries/BitmapUtils.sol"; +import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; +import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; +import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {AVSRegistrarMock} from "../mocks/AVSRegistrarMock.sol"; +import {console2 as console} from "forge-std/Test.sol"; + +contract AVSRegistrarTest is MockAVSDeployer { + using BN254 for BN254.G1Point; + + AVSRegistrarMock public avsRegistrarMock; + address internal operator = address(420); + + function setUp() public virtual { + _deployMockEigenLayerAndAVS(); + avsRegistrarMock = new AVSRegistrarMock(); + } + + function testSetAVSRegistrar() public { + vm.prank(address(serviceManager)); + allocationManager.setAVSRegistrar(address(serviceManager), IAVSRegistrar(address(avsRegistrarMock))); + assertEq(address(allocationManager.getAVSRegistrar(address(serviceManager))), address(avsRegistrarMock)); + } + + function testRegisterOperator() public { + // Set up AVS registrar + vm.prank(address(serviceManager)); + allocationManager.setAVSRegistrar(address(serviceManager), IAVSRegistrar(address(avsRegistrarMock))); + + // Create operator set + uint32 operatorSetId = 1; + IAllocationManagerTypes.CreateSetParams[] memory createSetParams = new IAllocationManagerTypes.CreateSetParams[](1); + createSetParams[0] = IAllocationManagerTypes.CreateSetParams({ + operatorSetId: operatorSetId, + strategies: new IStrategy[](0) + }); + + // Create operator set + vm.prank(address(serviceManager)); + allocationManager.createOperatorSets(address(serviceManager), createSetParams); + + // Set up registration params + uint32[] memory operatorSetIds = new uint32[](1); + operatorSetIds[0] = operatorSetId; + bytes memory emptyBytes; + + delegationMock.setIsOperator(operator, true); + + // Register operator + vm.prank(operator); + allocationManager.registerForOperatorSets( + address(operator), + IAllocationManagerTypes.RegisterParams(address(serviceManager), operatorSetIds, emptyBytes) + ); + } + + function testRegisterOperator_RevertsIfNotOperator() public { + vm.prank(address(serviceManager)); + allocationManager.setAVSRegistrar(address(serviceManager), IAVSRegistrar(address(avsRegistrarMock))); + + // Create operator set + uint32 operatorSetId = 1; + IAllocationManagerTypes.CreateSetParams[] memory createSetParams = new IAllocationManagerTypes.CreateSetParams[](1); + createSetParams[0] = IAllocationManagerTypes.CreateSetParams({ + operatorSetId: operatorSetId, + strategies: new IStrategy[](0) + }); + + // Create operator set + vm.prank(address(serviceManager)); + allocationManager.createOperatorSets(address(serviceManager), createSetParams); + + // Set up registration params + uint32[] memory operatorSetIds = new uint32[](1); + operatorSetIds[0] = operatorSetId; + bytes memory emptyBytes; + + delegationMock.setIsOperator(operator, false); + + // Register operator + vm.prank(operator); + + vm.expectRevert(); + allocationManager.registerForOperatorSets( + address(operator), + IAllocationManagerTypes.RegisterParams(address(serviceManager), operatorSetIds, emptyBytes) + ); + } + function testAllocationManagerDeployed() public { + assertTrue(address(allocationManager) != address(0), "AllocationManager not deployed"); + assertTrue(address(allocationManagerImplementation) != address(0), "AllocationManager implementation not deployed"); + } +} diff --git a/test/unit/RegistryCoordinatorMigration.t.sol b/test/unit/RegistryCoordinatorMigration.t.sol deleted file mode 100644 index 7b5a6b14..00000000 --- a/test/unit/RegistryCoordinatorMigration.t.sol +++ /dev/null @@ -1,470 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; -import { - RewardsCoordinator, - IRewardsCoordinator, - IRewardsCoordinatorTypes, - IERC20 -} from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; -import {StrategyBase} from "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; -import {IServiceManagerBaseEvents} from "../events/IServiceManagerBaseEvents.sol"; -import {IAVSDirectoryTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; -import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; -import {AVSDirectoryHarness} from "../harnesses/AVSDirectoryHarness.sol"; -import {OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; - -import "../utils/MockAVSDeployer.sol"; - -contract RegistryCoordinatorMigrationUnit is MockAVSDeployer, IServiceManagerBaseEvents { - // RewardsCoordinator config - address rewardsUpdater = address(uint160(uint256(keccak256("rewardsUpdater")))); - uint32 CALCULATION_INTERVAL_SECONDS = 7 days; - uint32 MAX_REWARDS_DURATION = 70 days; - uint32 MAX_RETROACTIVE_LENGTH = 84 days; - uint32 MAX_FUTURE_LENGTH = 28 days; - uint32 GENESIS_REWARDS_TIMESTAMP = 1_712_188_800; - uint256 MAX_REWARDS_AMOUNT = 1e38 - 1; - /// @notice Delay in timestamp before a posted root can be claimed against - uint32 activationDelay = 7 days; - /// @notice the commission for all operators across all avss - uint16 globalCommissionBips = 1000; - - // Testing Config and Mocks - address serviceManagerOwner; - IERC20[] rewardTokens; - uint256 mockTokenInitialSupply = 10e50; - IStrategy strategyMock1; - IStrategy strategyMock2; - IStrategy strategyMock3; - StrategyBase strategyImplementation; - IRewardsCoordinator.StrategyAndMultiplier[] defaultStrategyAndMultipliers; - AVSDirectoryHarness avsDirectoryHarness; - - // mapping to setting fuzzed inputs - mapping(address => bool) public addressIsExcludedFromFuzzedInputs; - - modifier filterFuzzedAddressInputs(address fuzzedAddress) { - cheats.assume(!addressIsExcludedFromFuzzedInputs[fuzzedAddress]); - _; - } - - function setUp() public virtual { - numQuorums = maxQuorumsToRegisterFor; - _deployMockEigenLayerAndAVS(); - - serviceManagerImplementation = new ServiceManagerMock( - avsDirectory, - IRewardsCoordinator(address(rewardsCoordinatorMock)), - registryCoordinator, - stakeRegistry, - allocationManager - ); - avsDirectoryHarness = new AVSDirectoryHarness(delegationMock); - - serviceManagerImplementation = new ServiceManagerMock( - avsDirectory, - rewardsCoordinatorMock, - registryCoordinator, - stakeRegistry, - allocationManager - ); - /// Needed to upgrade to a service manager that points to an AVS Directory that can track state - vm.prank(proxyAdmin.owner()); - proxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(serviceManager))), - address(serviceManagerImplementation) - ); - - serviceManagerOwner = serviceManager.owner(); - - _setUpDefaultStrategiesAndMultipliers(); - - addressIsExcludedFromFuzzedInputs[address(pauserRegistry)] = true; - addressIsExcludedFromFuzzedInputs[address(proxyAdmin)] = true; - } - - function _setUpDefaultStrategiesAndMultipliers() internal virtual { - // Deploy Mock Strategies - IERC20 token1 = new ERC20PresetFixedSupply( - "dog wif hat", "MOCK1", mockTokenInitialSupply, address(this) - ); - IERC20 token2 = - new ERC20PresetFixedSupply("jeo boden", "MOCK2", mockTokenInitialSupply, address(this)); - IERC20 token3 = new ERC20PresetFixedSupply( - "pepe wif avs", "MOCK3", mockTokenInitialSupply, address(this) - ); - strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock))); - strategyMock1 = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(strategyImplementation), - address(proxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, token1, pauserRegistry) - ) - ) - ); - strategyMock2 = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(strategyImplementation), - address(proxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, token2, pauserRegistry) - ) - ) - ); - strategyMock3 = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(strategyImplementation), - address(proxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, token3, pauserRegistry) - ) - ) - ); - IStrategy[] memory strategies = new IStrategy[](3); - strategies[0] = strategyMock1; - strategies[1] = strategyMock2; - strategies[2] = strategyMock3; - strategies = _sortArrayAsc(strategies); - - strategyManagerMock.setStrategyWhitelist(strategies[0], true); - strategyManagerMock.setStrategyWhitelist(strategies[1], true); - strategyManagerMock.setStrategyWhitelist(strategies[2], true); - - defaultStrategyAndMultipliers.push( - IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[0])), 1e18) - ); - defaultStrategyAndMultipliers.push( - IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[1])), 2e18) - ); - defaultStrategyAndMultipliers.push( - IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[2])), 3e18) - ); - } - - /// @dev Sort to ensure that the array is in ascending order for strategies - function _sortArrayAsc(IStrategy[] memory arr) internal pure returns (IStrategy[] memory) { - uint256 l = arr.length; - for (uint256 i = 0; i < l; i++) { - for (uint256 j = i + 1; j < l; j++) { - if (address(arr[i]) > address(arr[j])) { - IStrategy temp = arr[i]; - arr[i] = arr[j]; - arr[j] = temp; - } - } - } - return arr; - } - - function test_migrateToOperatorSets() public { - (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); - cheats.startPrank(serviceManagerOwner); - serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); - serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); - cheats.stopPrank(); - - assertTrue(avsDirectory.isOperatorSetAVS(address(serviceManager)), "AVS is not an operator set AVS"); - } - - - - function test_createQuorum() public { - (uint32[] memory operatorSetsToCreate, uint32[][] memory operatorSetIdsToMigrate, address[] memory operators) = serviceManager.getOperatorsToMigrate(); - cheats.startPrank(serviceManagerOwner); - serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); - serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); - cheats.stopPrank(); - - assertTrue(avsDirectory.isOperatorSetAVS(address(serviceManager)), "AVS is not an operator set AVS"); - - uint8 quorumNumber = registryCoordinator.quorumCount(); - uint96 minimumStake = 1000; - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ - maxOperatorCount: 10, - kickBIPsOfOperatorStake: 50, - kickBIPsOfTotalStake: 2 - }); - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = - IStakeRegistry.StrategyParams({ - strategy: IStrategy(address(1000)), - multiplier: 1e16 - }); - - assertFalse(avsDirectory.isOperatorSet(address(serviceManager), quorumNumber), "Operator set already existed"); - assertTrue(avsDirectory.isOperatorSet(address(serviceManager), quorumNumber-1), "Operator set doesn't already existed"); - - vm.prank(registryCoordinator.owner()); - registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, minimumStake, strategyParams); - - assertTrue(avsDirectory.isOperatorSet(address(serviceManager), quorumNumber), "Operator set was not created for the quorum"); - - } - - function test_updateOperatorsForQuorumsAfterDirectUnregister() public { - vm.prank(proxyAdmin.owner()); - proxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(avsDirectory))), - address(avsDirectoryMock) - ); - uint256 pseudoRandomNumber = uint256(keccak256("pseudoRandomNumber")); - _registerRandomOperators(pseudoRandomNumber); - - vm.prank(proxyAdmin.owner()); - proxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(avsDirectory))), - address(avsDirectoryHarness) - ); - - uint256 quorumCount = registryCoordinator.quorumCount(); - for (uint256 i = 0; i < quorumCount; i++) { - uint256 operatorCount = indexRegistry.totalOperatorsForQuorum(uint8(i)); - bytes32[] memory operatorIds = - indexRegistry.getOperatorListAtBlockNumber(uint8(i), uint32(block.number)); - assertEq(operatorCount, operatorIds.length, "Operator Id length mismatch"); // sanity check - for (uint256 j = 0; j < operatorCount; j++) { - address operatorAddress = - registryCoordinator.blsApkRegistry().getOperatorFromPubkeyHash(operatorIds[j]); - AVSDirectoryHarness(address(avsDirectory)).setAvsOperatorStatus( - address(serviceManager), - operatorAddress, - IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED - ); - } - } - - ( - uint32[] memory operatorSetsToCreate, - uint32[][] memory operatorSetIdsToMigrate, - address[] memory operators - ) = serviceManager.getOperatorsToMigrate(); - cheats.startPrank(serviceManagerOwner); - serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); - serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); - cheats.stopPrank(); - - bytes32[] memory registeredOperators = indexRegistry.getOperatorListAtBlockNumber(defaultQuorumNumber, uint32(block.number)); - uint256 preNumOperators = registeredOperators.length; - address[] memory registeredOperatorAddresses = new address[](registeredOperators.length); - for (uint256 i = 0; i < registeredOperators.length; i++) { - registeredOperatorAddresses[i] = registryCoordinator.blsApkRegistry().pubkeyHashToOperator(registeredOperators[i]); - } - - uint32[] memory operatorSetsToUnregister = new uint32[](1); - operatorSetsToUnregister[0] = defaultQuorumNumber; - - vm.prank(operators[0]); - avsDirectory.forceDeregisterFromOperatorSets( - operators[0], - address(serviceManager), - operatorSetsToUnregister, - ISignatureUtils.SignatureWithSaltAndExpiry({ - signature: new bytes(0), - salt: bytes32(0), - expiry: 0 - }) - ); - // sanity check if the operator was unregistered from the intended operator set - bool operatorIsUnRegistered = !avsDirectory.isMember(operators[0], OperatorSet({ - avs: address(serviceManager), - operatorSetId: defaultQuorumNumber - })); - bool isOperatorSetAVS = avsDirectory.isOperatorSetAVS(address(serviceManager)); - assertTrue(isOperatorSetAVS, "ServiceManager is not an operator set AVS"); - assertTrue(operatorIsUnRegistered, "Operator wasnt unregistered from op set"); - - address[][] memory registeredOperatorAddresses2D = new address[][](1); - registeredOperatorAddresses2D[0] = registeredOperatorAddresses; - bytes memory quorumNumbers = new bytes(1); - quorumNumbers[0] = bytes1(defaultQuorumNumber); - registryCoordinator.updateOperatorsForQuorum(registeredOperatorAddresses2D, quorumNumbers); - - registeredOperators = indexRegistry.getOperatorListAtBlockNumber(defaultQuorumNumber, uint32(block.number)); - uint256 postRegisteredOperators = registeredOperators.length; - - assertEq(preNumOperators-1, postRegisteredOperators, ""); - - } - - function test_deregister_afterMigration() public { - vm.prank(proxyAdmin.owner()); - proxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(avsDirectory))), - address(avsDirectoryMock) - ); - uint256 pseudoRandomNumber = uint256(keccak256("pseudoRandomNumber")); - _registerRandomOperators(pseudoRandomNumber); - - vm.prank(proxyAdmin.owner()); - proxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(avsDirectory))), - address(avsDirectoryHarness) - ); - - uint256 quorumCount = registryCoordinator.quorumCount(); - for (uint256 i = 0; i < quorumCount; i++) { - uint256 operatorCount = indexRegistry.totalOperatorsForQuorum(uint8(i)); - bytes32[] memory operatorIds = - indexRegistry.getOperatorListAtBlockNumber(uint8(i), uint32(block.number)); - assertEq(operatorCount, operatorIds.length, "Operator Id length mismatch"); // sanity check - for (uint256 j = 0; j < operatorCount; j++) { - address operatorAddress = - registryCoordinator.blsApkRegistry().getOperatorFromPubkeyHash(operatorIds[j]); - AVSDirectoryHarness(address(avsDirectory)).setAvsOperatorStatus( - address(serviceManager), - operatorAddress, - IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED - ); - } - } - - ( - uint32[] memory operatorSetsToCreate, - uint32[][] memory operatorSetIdsToMigrate, - address[] memory operators - ) = serviceManager.getOperatorsToMigrate(); - cheats.startPrank(serviceManagerOwner); - serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); - serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); - cheats.stopPrank(); - - bytes32[] memory registeredOperators = indexRegistry.getOperatorListAtBlockNumber(defaultQuorumNumber, uint32(block.number)); - address[] memory registeredOperatorAddresses = new address[](registeredOperators.length); - for (uint256 i = 0; i < registeredOperators.length; i++) { - registeredOperatorAddresses[i] = registryCoordinator.blsApkRegistry().pubkeyHashToOperator(registeredOperators[i]); - } - - uint32[] memory operatorSetsToUnregister = new uint32[](1); - operatorSetsToUnregister[0] = defaultQuorumNumber; - - address operatorToDeregister = operators[0]; - - bool isOperatorRegistered = avsDirectory.isMember(operatorToDeregister, OperatorSet({ - avs: address(serviceManager), - operatorSetId: defaultQuorumNumber - })); - bool isOperatorSetAVS = avsDirectory.isOperatorSetAVS(address(serviceManager)); - // sanity check if the operator was registered from the intended operator set - assertTrue(isOperatorSetAVS, "ServiceManager is not an operator set AVS"); - assertTrue(isOperatorRegistered, "Operator wasnt unregistered from op set"); - - bytes memory quorumNumbers = new bytes(1); - quorumNumbers[0] = bytes1(defaultQuorumNumber); - cheats.startPrank(operatorToDeregister); - registryCoordinator.deregisterOperator(quorumNumbers); - cheats.stopPrank(); - - isOperatorRegistered = avsDirectory.isMember(operatorToDeregister, OperatorSet({ - avs: address(serviceManager), - operatorSetId: defaultQuorumNumber - })); - assertFalse(isOperatorRegistered, "Operator wasn't deregistered from operator set"); - } - - function test_register_afterMigration() public { - vm.prank(proxyAdmin.owner()); - proxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(avsDirectory))), - address(avsDirectoryMock) - ); - uint256 pseudoRandomNumber = uint256(keccak256("pseudoRandomNumber")); - _registerRandomOperators(pseudoRandomNumber); - - vm.prank(proxyAdmin.owner()); - proxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(avsDirectory))), - address(avsDirectoryHarness) - ); - - uint256 quorumCount = registryCoordinator.quorumCount(); - for (uint256 i = 0; i < quorumCount; i++) { - uint256 operatorCount = indexRegistry.totalOperatorsForQuorum(uint8(i)); - bytes32[] memory operatorIds = - indexRegistry.getOperatorListAtBlockNumber(uint8(i), uint32(block.number)); - assertEq(operatorCount, operatorIds.length, "Operator Id length mismatch"); // sanity check - for (uint256 j = 0; j < operatorCount; j++) { - address operatorAddress = - registryCoordinator.blsApkRegistry().getOperatorFromPubkeyHash(operatorIds[j]); - AVSDirectoryHarness(address(avsDirectory)).setAvsOperatorStatus( - address(serviceManager), - operatorAddress, - IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED - ); - } - } - - ( - uint32[] memory operatorSetsToCreate, - uint32[][] memory operatorSetIdsToMigrate, - address[] memory operators - ) = serviceManager.getOperatorsToMigrate(); - cheats.startPrank(serviceManagerOwner); - serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); - serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); - cheats.stopPrank(); - - bytes32[] memory registeredOperators = indexRegistry.getOperatorListAtBlockNumber(defaultQuorumNumber, uint32(block.number)); - address[] memory registeredOperatorAddresses = new address[](registeredOperators.length); - for (uint256 i = 0; i < registeredOperators.length; i++) { - registeredOperatorAddresses[i] = registryCoordinator.blsApkRegistry().pubkeyHashToOperator(registeredOperators[i]); - } - - uint32[] memory operatorSetsToRegisterFor = new uint32[](1); - operatorSetsToRegisterFor[0] = defaultQuorumNumber; - - uint256 operatorPk = uint256(keccak256("operator to register")); - address operatorToRegister = vm.addr(operatorPk) ; - - bool isOperatorRegistered = avsDirectory.isMember(operatorToRegister, OperatorSet({ - avs: address(serviceManager), - operatorSetId: defaultQuorumNumber - })); - bool isOperatorSetAVS = avsDirectory.isOperatorSetAVS(address(serviceManager)); - // sanity check if the operator was registered from the intended operator set - assertTrue(isOperatorSetAVS, "ServiceManager is not an operator set AVS"); - assertTrue(!isOperatorRegistered, "Operator wasnt unregistered from op set"); - - IDelegationManager.OperatorDetails memory details; - - cheats.startPrank(operatorToRegister); - delegationMock.registerAsOperator(details, "your_metadata_URI_here"); - cheats.stopPrank(); - - delegationMock.setIsOperator(operatorToRegister, true); - - bytes memory quorumNumbers = new bytes(1); - IBLSApkRegistry.PubkeyRegistrationParams memory params; - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; - quorumNumbers[0] = bytes1(defaultQuorumNumber); - bytes32 typeHash = avsDirectory.calculateOperatorSetRegistrationDigestHash( - address(serviceManager), - operatorSetsToRegisterFor, - keccak256(abi.encodePacked("operator registration salt")), - block.timestamp + 1 days - ); - (uint8 v, bytes32 r, bytes32 s) = vm.sign(operatorPk, typeHash); - operatorSignature = ISignatureUtils.SignatureWithSaltAndExpiry({ - signature: abi.encodePacked(r, s, v), - salt: keccak256(abi.encodePacked("operator registration salt")), - expiry: block.timestamp + 1 days - }); - - blsApkRegistry.setBLSPublicKey(operatorToRegister, defaultPubKey); - delegationMock.setOperatorShares(operatorToRegister, IStrategy(address(0)), 100 ether); - cheats.startPrank(operatorToRegister); - registryCoordinator.registerOperator(quorumNumbers, "", params, operatorSignature); - cheats.stopPrank(); - - isOperatorRegistered = avsDirectory.isMember(operatorToRegister, OperatorSet({ - avs: address(serviceManager), - operatorSetId: defaultQuorumNumber - })); - assertTrue(isOperatorRegistered, "Operator wasn't deregistered from operator set"); - } - - -} diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index d6931dc4..47eb1724 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -126,7 +126,6 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina registryCoordinatorOwner, churnApprover, ejector, - pauserRegistry, 0/*initialPausedStatus*/, operatorSetParams, new uint96[](0), diff --git a/test/unit/ServiceManagerBase.t.sol b/test/unit/ServiceManagerBase.t.sol index 609e8d2b..c7ac91e9 100644 --- a/test/unit/ServiceManagerBase.t.sol +++ b/test/unit/ServiceManagerBase.t.sol @@ -8,6 +8,7 @@ import { IRewardsCoordinatorTypes, IERC20 } from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; +import {PermissionController} from "eigenlayer-contracts/src/contracts/permissions/PermissionController.sol"; import {StrategyBase} from "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; import {IServiceManagerBaseEvents} from "../events/IServiceManagerBaseEvents.sol"; @@ -56,6 +57,9 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve rewardsCoordinatorImplementation = new RewardsCoordinator( delegationMock, IStrategyManager(address(strategyManagerMock)), + allocationManagerMock, + pauserRegistry, + permissionControllerMock, CALCULATION_INTERVAL_SECONDS, MAX_REWARDS_DURATION, MAX_RETROACTIVE_LENGTH, @@ -71,7 +75,6 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve abi.encodeWithSelector( RewardsCoordinator.initialize.selector, msg.sender, - pauserRegistry, 0, /*initialPausedStatus*/ rewardsUpdater, activationDelay, @@ -146,7 +149,7 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve IERC20 token3 = new ERC20PresetFixedSupply( "pepe wif avs", "MOCK3", mockTokenInitialSupply, address(this) ); - strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock))); + strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry); strategyMock1 = StrategyBase( address( new TransparentUpgradeableProxy( @@ -248,7 +251,7 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve serviceManager.createAVSRewardsSubmission(rewardsSubmissions); } - function test_createAVSRewardsSubmission_SingleSubmission( + function testFuzz_createAVSRewardsSubmission_SingleSubmission( uint256 startTimestamp, uint256 duration, uint256 amount @@ -325,7 +328,7 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve ); } - function test_createAVSRewardsSubmission_MultipleSubmissions( + function testFuzz_createAVSRewardsSubmission_MultipleSubmissions( uint256 startTimestamp, uint256 duration, uint256 amount, @@ -418,7 +421,7 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve } } - function test_createAVSRewardsSubmission_MultipleSubmissionsSingleToken( + function testFuzz_createAVSRewardsSubmission_MultipleSubmissionsSingleToken( uint256 startTimestamp, uint256 duration, uint256 amount, diff --git a/test/unit/ServiceManagerMigration.t.sol b/test/unit/ServiceManagerMigration.t.sol deleted file mode 100644 index 5fd86846..00000000 --- a/test/unit/ServiceManagerMigration.t.sol +++ /dev/null @@ -1,348 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; - -import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; -import { - RewardsCoordinator, - IRewardsCoordinator, - IRewardsCoordinatorTypes, - IERC20 -} from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; -import {StrategyBase} from "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; -import {IServiceManagerBaseEvents} from "../events/IServiceManagerBaseEvents.sol"; -import {IAVSDirectoryTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; -import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; -import {AVSDirectoryHarness} from "../harnesses/AVSDirectoryHarness.sol"; -import {OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; - -import "../utils/MockAVSDeployer.sol"; - -contract ServiceManagerMigration_UnitTests is MockAVSDeployer, IServiceManagerBaseEvents { - // RewardsCoordinator config - address rewardsUpdater = address(uint160(uint256(keccak256("rewardsUpdater")))); - uint32 CALCULATION_INTERVAL_SECONDS = 7 days; - uint32 MAX_REWARDS_DURATION = 70 days; - uint32 MAX_RETROACTIVE_LENGTH = 84 days; - uint32 MAX_FUTURE_LENGTH = 28 days; - uint32 GENESIS_REWARDS_TIMESTAMP = 1_712_188_800; - uint256 MAX_REWARDS_AMOUNT = 1e38 - 1; - uint32 OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP = 0; - /// TODO: what values should these have - uint32 OPERATOR_SET_MAX_RETROACTIVE_LENGTH = 0; - /// TODO: What values these should have - /// @notice Delay in timestamp before a posted root can be claimed against - uint32 activationDelay = 7 days; - /// @notice the commission for all operators across all avss - uint16 globalCommissionBips = 1000; - - // Testing Config and Mocks - address serviceManagerOwner; - address rewardsInitiator = address(uint160(uint256(keccak256("rewardsInitiator")))); - IERC20[] rewardTokens; - uint256 mockTokenInitialSupply = 10e50; - IStrategy strategyMock1; - IStrategy strategyMock2; - IStrategy strategyMock3; - StrategyBase strategyImplementation; - IRewardsCoordinator.StrategyAndMultiplier[] defaultStrategyAndMultipliers; - AVSDirectoryHarness avsDirectoryHarness; - - // mapping to setting fuzzed inputs - mapping(address => bool) public addressIsExcludedFromFuzzedInputs; - - modifier filterFuzzedAddressInputs(address fuzzedAddress) { - cheats.assume(!addressIsExcludedFromFuzzedInputs[fuzzedAddress]); - _; - } - - function setUp() public virtual { - numQuorums = maxQuorumsToRegisterFor; - _deployMockEigenLayerAndAVS(); - - avsDirectoryHarness = new AVSDirectoryHarness(delegationMock); - // Deploy rewards coordinator - rewardsCoordinatorImplementation = new RewardsCoordinator( - delegationMock, - IStrategyManager(address(strategyManagerMock)), - CALCULATION_INTERVAL_SECONDS, - MAX_REWARDS_DURATION, - MAX_RETROACTIVE_LENGTH, - MAX_FUTURE_LENGTH, - GENESIS_REWARDS_TIMESTAMP - ); - - rewardsCoordinator = RewardsCoordinator( - address( - new TransparentUpgradeableProxy( - address(rewardsCoordinatorImplementation), - address(proxyAdmin), - abi.encodeWithSelector( - RewardsCoordinator.initialize.selector, - msg.sender, - pauserRegistry, - 0, /*initialPausedStatus*/ - rewardsUpdater, - activationDelay, - globalCommissionBips - ) - ) - ) - ); - // Deploy ServiceManager - serviceManagerImplementation = new ServiceManagerMock( - avsDirectory, rewardsCoordinator, registryCoordinator, stakeRegistry, allocationManager - ); - - serviceManager = ServiceManagerMock( - address( - new TransparentUpgradeableProxy( - address(serviceManagerImplementation), - address(proxyAdmin), - abi.encodeWithSelector( - ServiceManagerMock.initialize.selector, serviceManager.owner(), msg.sender, msg.sender - ) - ) - ) - ); - - serviceManagerOwner = serviceManager.owner(); - cheats.prank(serviceManagerOwner); - serviceManager.setRewardsInitiator(rewardsInitiator); - - _setUpDefaultStrategiesAndMultipliers(); - - cheats.warp(GENESIS_REWARDS_TIMESTAMP + 2 weeks); - - addressIsExcludedFromFuzzedInputs[address(pauserRegistry)] = true; - addressIsExcludedFromFuzzedInputs[address(proxyAdmin)] = true; - } - - function _setUpDefaultStrategiesAndMultipliers() internal virtual { - // Deploy Mock Strategies - IERC20 token1 = new ERC20PresetFixedSupply( - "dog wif hat", "MOCK1", mockTokenInitialSupply, address(this) - ); - IERC20 token2 = - new ERC20PresetFixedSupply("jeo boden", "MOCK2", mockTokenInitialSupply, address(this)); - IERC20 token3 = new ERC20PresetFixedSupply( - "pepe wif avs", "MOCK3", mockTokenInitialSupply, address(this) - ); - strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock))); - strategyMock1 = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(strategyImplementation), - address(proxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, token1, pauserRegistry) - ) - ) - ); - strategyMock2 = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(strategyImplementation), - address(proxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, token2, pauserRegistry) - ) - ) - ); - strategyMock3 = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(strategyImplementation), - address(proxyAdmin), - abi.encodeWithSelector(StrategyBase.initialize.selector, token3, pauserRegistry) - ) - ) - ); - IStrategy[] memory strategies = new IStrategy[](3); - strategies[0] = strategyMock1; - strategies[1] = strategyMock2; - strategies[2] = strategyMock3; - strategies = _sortArrayAsc(strategies); - - strategyManagerMock.setStrategyWhitelist(strategies[0], true); - strategyManagerMock.setStrategyWhitelist(strategies[1], true); - strategyManagerMock.setStrategyWhitelist(strategies[2], true); - - defaultStrategyAndMultipliers.push( - IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[0])), 1e18) - ); - defaultStrategyAndMultipliers.push( - IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[1])), 2e18) - ); - defaultStrategyAndMultipliers.push( - IRewardsCoordinatorTypes.StrategyAndMultiplier(IStrategy(address(strategies[2])), 3e18) - ); - } - - /// @dev Sort to ensure that the array is in ascending order for strategies - function _sortArrayAsc(IStrategy[] memory arr) internal pure returns (IStrategy[] memory) { - uint256 l = arr.length; - for (uint256 i = 0; i < l; i++) { - for (uint256 j = i + 1; j < l; j++) { - if (address(arr[i]) > address(arr[j])) { - IStrategy temp = arr[i]; - arr[i] = arr[j]; - arr[j] = temp; - } - } - } - return arr; - } - - function test_viewFunction(uint256 randomValue) public { - _registerRandomOperators(randomValue); - ( - uint32[] memory operatorSetsToCreate, - uint32[][] memory operatorSetIdsToMigrate, - address[] memory operators - ) = serviceManager.getOperatorsToMigrate(); - - // Assert that all operators are in quorum 0 invariant of _registerRandomOperators - for (uint256 i = 0; i < operators.length; i++) { - bytes32 operatorId = registryCoordinator.getOperatorId(operators[i]); - uint192 operatorBitmap = registryCoordinator.getCurrentQuorumBitmap(operatorId); - assertTrue(operatorId != bytes32(0), "Operator was registered"); - assertTrue(operatorBitmap & 1 == 1, "Operator is not registered in quorum 0"); - } - - // Assert we are migrating all the quorums that existed - uint256 quorumCount = registryCoordinator.quorumCount(); - assertEq(quorumCount, operatorSetsToCreate.length, "Operator sets to create incorrect"); - } - - function test_migrateToOperatorSets() public { - ( - uint32[] memory operatorSetsToCreate, - uint32[][] memory operatorSetIdsToMigrate, - address[] memory operators - ) = serviceManager.getOperatorsToMigrate(); - cheats.startPrank(serviceManagerOwner); - serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); - serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); - cheats.stopPrank(); - - assertTrue( - avsDirectory.isOperatorSetAVS(address(serviceManager)), "AVS is not an operator set AVS" - ); - } - - function test_migrateTwoTransactions() public { - ( - uint32[] memory operatorSetsToCreate, - uint32[][] memory operatorSetIdsToMigrate, - address[] memory operators - ) = serviceManager.getOperatorsToMigrate(); - // Split the operatorSetIdsToMigrate and operators into two separate sets - uint256 halfLength = operatorSetIdsToMigrate.length / 2; - - uint32[][] memory firstHalfOperatorSetIds = new uint32[][](halfLength); - uint32[][] memory secondHalfOperatorSetIds = - new uint32[][](operatorSetIdsToMigrate.length - halfLength); - address[] memory firstHalfOperators = new address[](halfLength); - address[] memory secondHalfOperators = new address[](operators.length - halfLength); - - for (uint256 i = 0; i < halfLength; i++) { - firstHalfOperatorSetIds[i] = operatorSetIdsToMigrate[i]; - firstHalfOperators[i] = operators[i]; - } - - for (uint256 i = halfLength; i < operatorSetIdsToMigrate.length; i++) { - secondHalfOperatorSetIds[i - halfLength] = operatorSetIdsToMigrate[i]; - secondHalfOperators[i - halfLength] = operators[i]; - } - - // Migrate the first half - cheats.startPrank(serviceManagerOwner); - serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); - serviceManager.migrateToOperatorSets(firstHalfOperatorSetIds, firstHalfOperators); - serviceManager.migrateToOperatorSets(secondHalfOperatorSetIds, secondHalfOperators); - cheats.stopPrank(); - - assertTrue( - avsDirectory.isOperatorSetAVS(address(serviceManager)), "AVS is not an operator set AVS" - ); - } - - function test_migrateToOperatorSets_revert_alreadyMigrated() public { - ( - uint32[] memory operatorSetsToCreate, - uint32[][] memory operatorSetIdsToMigrate, - address[] memory operators - ) = serviceManager.getOperatorsToMigrate(); - cheats.startPrank(serviceManagerOwner); - serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); - serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); - serviceManager.finalizeMigration(); - - vm.expectRevert(); - - /// TODO: Now that it's not 1 step, we should have a way to signal completion - serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); - - cheats.stopPrank(); - } - - function test_migrateToOperatorSets_revert_notOwner() public { - ( - uint32[] memory operatorSetsToCreate, - uint32[][] memory operatorSetIdsToMigrate, - address[] memory operators - ) = serviceManager.getOperatorsToMigrate(); - cheats.startPrank(serviceManagerOwner); - serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); - cheats.stopPrank(); - address caller = address(uint160(uint256(keccak256("caller")))); - cheats.expectRevert("Ownable: caller is not the owner"); - cheats.prank(caller); - serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); - } - - function test_migrateToOperatorSets_verify() public { - uint256 pseudoRandomNumber = uint256(keccak256("pseudoRandomNumber")); - _registerRandomOperators(pseudoRandomNumber); - - vm.prank(proxyAdmin.owner()); - proxyAdmin.upgrade( - TransparentUpgradeableProxy(payable(address(avsDirectory))), - address(avsDirectoryHarness) - ); - - uint256 quorumCount = registryCoordinator.quorumCount(); - for (uint256 i = 0; i < quorumCount; i++) { - uint256 operatorCount = indexRegistry.totalOperatorsForQuorum(uint8(i)); - bytes32[] memory operatorIds = - indexRegistry.getOperatorListAtBlockNumber(uint8(i), uint32(block.number)); - assertEq(operatorCount, operatorIds.length, "Operator Id length mismatch"); // sanity check - for (uint256 j = 0; j < operatorCount; j++) { - address operatorAddress = - registryCoordinator.blsApkRegistry().getOperatorFromPubkeyHash(operatorIds[j]); - AVSDirectoryHarness(address(avsDirectory)).setAvsOperatorStatus( - address(serviceManager), - operatorAddress, - IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED - ); - } - } - - ( - uint32[] memory operatorSetsToCreate, - uint32[][] memory operatorSetIdsToMigrate, - address[] memory operators - ) = serviceManager.getOperatorsToMigrate(); - cheats.startPrank(serviceManagerOwner); - serviceManager.migrateAndCreateOperatorSetIds(operatorSetsToCreate); - serviceManager.migrateToOperatorSets(operatorSetIdsToMigrate, operators); - cheats.stopPrank(); - - /// quick check, this operator is in operator set 3 - assertTrue( - avsDirectory.isMember( - 0x73e2Ce949f15Be901f76b54F5a4554A6C8DCf539, - OperatorSet(address(serviceManager), uint32(3)) - ), - "Operator not migrated to operator set" - ); - } -} diff --git a/test/unit/StakeRegistryUnit.t.sol b/test/unit/StakeRegistryUnit.t.sol index 4b74194a..6fbe8609 100644 --- a/test/unit/StakeRegistryUnit.t.sol +++ b/test/unit/StakeRegistryUnit.t.sol @@ -49,7 +49,8 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { stakeRegistry, IBLSApkRegistry(blsApkRegistry), IIndexRegistry(indexRegistry), - IAVSDirectory(avsDirectory) + IAVSDirectory(avsDirectory), + pauserRegistry ); stakeRegistryImplementation = new StakeRegistryHarness( @@ -2171,7 +2172,7 @@ contract StakeRegistryUnitTests_weightOfOperatorForQuorum is StakeRegistryUnitTe * successfully and return a value for weightOfOperatorForQuorum. Fuzz test sets the operator shares * and asserts that the summed weight of the operator is correct. */ - function test_weightOfOperatorForQuorum( + function testFuzz_weightOfOperatorForQuorum( address operator, uint96[] memory multipliers, uint96[] memory shares @@ -2226,7 +2227,7 @@ contract StakeRegistryUnitTests_weightOfOperatorForQuorum is StakeRegistryUnitTe } /// @dev consider multipliers for 3 strategies - function test_weightOfOperatorForQuorum_3Strategies( + function testFuzz_weightOfOperatorForQuorum_3Strategies( address operator, uint96[3] memory shares ) public { diff --git a/test/unit/UpgradeableProxyLib.sol b/test/unit/UpgradeableProxyLib.sol new file mode 100644 index 00000000..15fd49d8 --- /dev/null +++ b/test/unit/UpgradeableProxyLib.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity ^0.8.0; +import {Vm} from "forge-std/Vm.sol"; +import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +import {TransparentUpgradeableProxy} from + "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; + +contract EmptyContract { +} + +library UpgradeableProxyLib { + bytes32 internal constant IMPLEMENTATION_SLOT = + 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + bytes32 internal constant ADMIN_SLOT = + 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; + Vm internal constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + function deployProxyAdmin() internal returns (address) { + return address(new ProxyAdmin()); + } + function setUpEmptyProxy( + address admin + ) internal returns (address) { + address emptyContract = address(new EmptyContract()); + return address(new TransparentUpgradeableProxy(emptyContract, admin, "")); + } + function upgrade(address proxy, address impl) internal { + ProxyAdmin admin = getProxyAdmin(proxy); + admin.upgrade(TransparentUpgradeableProxy(payable(proxy)), impl); + } + function upgradeAndCall(address proxy, address impl, bytes memory initData) internal { + ProxyAdmin admin = getProxyAdmin(proxy); + admin.upgradeAndCall(TransparentUpgradeableProxy(payable(proxy)), impl, initData); + } + function getImplementation( + address proxy + ) internal view returns (address) { + bytes32 value = vm.load(proxy, IMPLEMENTATION_SLOT); + return address(uint160(uint256(value))); + } + function getProxyAdmin( + address proxy + ) internal view returns (ProxyAdmin) { + bytes32 value = vm.load(proxy, ADMIN_SLOT); + return ProxyAdmin(address(uint160(uint256(value)))); + } +} \ No newline at end of file diff --git a/test/unit/Utils.sol b/test/unit/Utils.sol index 0947b1d4..c143633d 100644 --- a/test/unit/Utils.sol +++ b/test/unit/Utils.sol @@ -7,7 +7,7 @@ contract Utils { address constant dummyAdmin = address(uint160(uint256(keccak256("DummyAdmin")))); function deployNewStrategy(IERC20 token, IStrategyManager strategyManager, IPauserRegistry pauserRegistry, address admin) public returns (StrategyBase) { - StrategyBase newStrategy = new StrategyBase(strategyManager); + StrategyBase newStrategy = new StrategyBase(strategyManager, pauserRegistry); newStrategy = StrategyBase( address( new TransparentUpgradeableProxy( @@ -17,7 +17,7 @@ contract Utils { ) ) ); - newStrategy.initialize(token, pauserRegistry); + newStrategy.initialize(token); return newStrategy; } } diff --git a/test/utils/BLSMockAVSDeployer.sol b/test/utils/BLSMockAVSDeployer.sol index 3f5286a3..14339d55 100644 --- a/test/utils/BLSMockAVSDeployer.sol +++ b/test/utils/BLSMockAVSDeployer.sol @@ -130,8 +130,8 @@ contract BLSMockAVSDeployer is MockAVSDeployer { OperatorStateRetriever.CheckSignaturesIndices memory checkSignaturesIndices = operatorStateRetriever.getCheckSignaturesIndices( registryCoordinator, - referenceBlockNumber, - quorumNumbers, + referenceBlockNumber, + quorumNumbers, nonSignerOperatorIds ); diff --git a/test/utils/CoreDeployLib.sol b/test/utils/CoreDeployLib.sol new file mode 100644 index 00000000..d88f6ff6 --- /dev/null +++ b/test/utils/CoreDeployLib.sol @@ -0,0 +1,271 @@ +// // SPDX-License-Identifier: UNLICENSED +// pragma solidity ^0.8.0; + +// import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; +// import {TransparentUpgradeableProxy} from +// "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +// import {UpgradeableBeacon} from "@openzeppelin/contracts/proxy/beacon/UpgradeableBeacon.sol"; +// import {DelegationManager} from "eigenlayer-contracts/src/contracts/core/DelegationManager.sol"; +// import {StrategyManager} from "eigenlayer-contracts/src/contracts/core/StrategyManager.sol"; +// import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; +// import {EigenPodManager} from "eigenlayer-contracts/src/contracts/pods/EigenPodManager.sol"; +// import {RewardsCoordinator} from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; +// import {StrategyBase} from "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; +// import {EigenPod} from "eigenlayer-contracts/src/contracts/pods/EigenPod.sol"; +// import {IETHPOSDeposit} from "eigenlayer-contracts/src/contracts/interfaces/IETHPOSDeposit.sol"; +// import {StrategyBaseTVLLimits} from "eigenlayer-contracts/src/contracts/strategies/StrategyBaseTVLLimits.sol"; +// import {PauserRegistry} from "eigenlayer-contracts/src/contracts/permissions/PauserRegistry.sol"; +// import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; +// import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +// import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; +// import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +// import {IBeacon} from "@openzeppelin/contracts/proxy/beacon/IBeacon.sol"; +// import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; +// import {IEigenPodManager} from "eigenlayer-contracts/src/contracts/interfaces/IEigenPodManager.sol"; +// import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +// import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; +// import {StrategyFactory} from "eigenlayer-contracts/src/contracts/strategies/StrategyFactory.sol"; + +// import {UpgradeableProxyLib} from "../unit/UpgradeableProxyLib.sol"; + +// library CoreDeploymentLib { +// using UpgradeableProxyLib for address; + +// struct StrategyManagerConfig { +// uint256 initPausedStatus; +// uint256 initWithdrawalDelayBlocks; +// } + +// struct DelegationManagerConfig { +// uint256 initPausedStatus; +// IStrategy[] strategies; +// uint256 minWithdrawalDelayBlocks; +// uint256[] withdrawalDelayBlocks; + +// } + +// struct EigenPodManagerConfig { +// uint256 initPausedStatus; +// } + +// struct RewardsCoordinatorConfig { +// uint256 initPausedStatus; +// uint256 maxRewardsDuration; +// uint256 maxRetroactiveLength; +// uint256 maxFutureLength; +// uint256 genesisRewardsTimestamp; +// address updater; +// uint256 activationDelay; +// uint256 calculationIntervalSeconds; +// uint256 globalOperatorCommissionBips; +// } + +// struct StrategyFactoryConfig { +// uint256 initPausedStatus; +// } + +// struct DeploymentConfigData { +// StrategyManagerConfig strategyManager; +// DelegationManagerConfig delegationManager; +// EigenPodManagerConfig eigenPodManager; +// RewardsCoordinatorConfig rewardsCoordinator; +// StrategyFactoryConfig strategyFactory; +// } + +// struct DeploymentData { +// address delegationManager; +// address avsDirectory; +// address strategyManager; +// address eigenPodManager; +// address rewardsCoordinator; +// address eigenPodBeacon; +// address pauserRegistry; +// address strategyFactory; +// address strategyBeacon; +// } + +// function deployContracts( +// address proxyAdmin, +// DeploymentConfigData memory configData +// ) internal returns (DeploymentData memory) { +// DeploymentData memory result; + +// result.delegationManager = UpgradeableProxyLib.setUpEmptyProxy(proxyAdmin); +// result.avsDirectory = UpgradeableProxyLib.setUpEmptyProxy(proxyAdmin); +// result.strategyManager = UpgradeableProxyLib.setUpEmptyProxy(proxyAdmin); +// result.eigenPodManager = UpgradeableProxyLib.setUpEmptyProxy(proxyAdmin); +// result.rewardsCoordinator = UpgradeableProxyLib.setUpEmptyProxy(proxyAdmin); +// result.eigenPodBeacon = UpgradeableProxyLib.setUpEmptyProxy(proxyAdmin); +// result.pauserRegistry = UpgradeableProxyLib.setUpEmptyProxy(proxyAdmin); +// result.strategyFactory = UpgradeableProxyLib.setUpEmptyProxy(proxyAdmin); + +// // Deploy the implementation contracts, using the proxy contracts as inputs +// address delegationManagerImpl = address( +// new DelegationManager( +// IStrategyManager(result.strategyManager), +// IEigenPodManager(result.eigenPodManager) +// ) +// ); +// address avsDirectoryImpl = +// address(new AVSDirectory(IDelegationManager(result.delegationManager))); + +// address strategyManagerImpl = address( +// new StrategyManager( +// IDelegationManager(result.delegationManager), +// IEigenPodManager(result.eigenPodManager) +// ) +// ); + +// address strategyFactoryImpl = +// address(new StrategyFactory(IStrategyManager(result.strategyManager))); + +// address ethPOSDeposit; +// if (block.chainid == 1) { +// ethPOSDeposit = 0x00000000219ab540356cBB839Cbe05303d7705Fa; +// } else { +// // For non-mainnet chains, you might want to deploy a mock or read from a config +// // This assumes you have a similar config setup as in M2_Deploy_From_Scratch.s.sol +// /// TODO: Handle Eth pos +// } + +// address eigenPodManagerImpl = address( +// new EigenPodManager( +// IETHPOSDeposit(ethPOSDeposit), +// IBeacon(result.eigenPodBeacon), +// IStrategyManager(result.strategyManager), +// IDelegationManager(result.delegationManager) +// ) +// ); + +// /// TODO: Get actual values +// uint32 CALCULATION_INTERVAL_SECONDS = 1 days; +// uint32 MAX_REWARDS_DURATION = 1 days; +// uint32 MAX_RETROACTIVE_LENGTH = 1; +// uint32 MAX_FUTURE_LENGTH = 1; +// uint32 GENESIS_REWARDS_TIMESTAMP = 10 days; +// address rewardsCoordinatorImpl = address( +// new RewardsCoordinator( +// IDelegationManager(result.delegationManager), +// IStrategyManager(result.strategyManager), +// CALCULATION_INTERVAL_SECONDS, +// MAX_REWARDS_DURATION, +// MAX_RETROACTIVE_LENGTH, +// MAX_FUTURE_LENGTH, +// GENESIS_REWARDS_TIMESTAMP +// ) +// ); + +// /// TODO: Get actual genesis time +// uint64 GENESIS_TIME = 1_564_000; + +// address eigenPodImpl = address( +// new EigenPod( +// IETHPOSDeposit(ethPOSDeposit), +// IEigenPodManager(result.eigenPodManager), +// GENESIS_TIME +// ) +// ); +// address eigenPodBeaconImpl = address(new UpgradeableBeacon(eigenPodImpl)); +// address baseStrategyImpl = +// address(new StrategyBase(IStrategyManager(result.strategyManager))); +// /// TODO: PauserRegistry isn't upgradeable +// address pauserRegistryImpl = address( +// new PauserRegistry( +// new address[](0), // Empty array for pausers +// proxyAdmin // ProxyAdmin as the unpauser +// ) +// ); + +// // Deploy and configure the strategy beacon +// result.strategyBeacon = address(new UpgradeableBeacon(baseStrategyImpl)); + +// // Upgrade contracts +// /// TODO: Get from config +// bytes memory upgradeCall = abi.encodeWithSelector( /// TODO: Fix abi.encodeCall was failing Cannot implicitly convert component at position 4 from "IStrategy[]" to "IStrategy[]" +// DelegationManager.initialize.selector, +// proxyAdmin, // initialOwner +// IPauserRegistry(result.pauserRegistry), // _pauserRegistry +// configData.delegationManager.initPausedStatus, // initialPausedStatus +// configData.delegationManager.minWithdrawalDelayBlocks, // _minWithdrawalDelayBlocks +// configData.delegationManager.strategies, // _strategies +// configData.delegationManager.withdrawalDelayBlocks // _withdrawalDelayBlocks +// ); +// UpgradeableProxyLib.upgradeAndCall( +// result.delegationManager, delegationManagerImpl, upgradeCall +// ); + +// // Upgrade StrategyManager contract +// upgradeCall = abi.encodeCall( +// StrategyManager.initialize, +// ( +// proxyAdmin, // initialOwner +// result.strategyFactory, // initialStrategyWhitelister +// IPauserRegistry(result.pauserRegistry), // _pauserRegistry +// configData.strategyManager.initPausedStatus // initialPausedStatus +// ) +// ); +// UpgradeableProxyLib.upgradeAndCall(result.strategyManager, strategyManagerImpl, upgradeCall); + +// // Upgrade StrategyFactory contract +// upgradeCall = abi.encodeCall( +// StrategyFactory.initialize, +// ( +// proxyAdmin, // initialOwner +// IPauserRegistry(result.pauserRegistry), // _pauserRegistry +// configData.strategyFactory.initPausedStatus, // initialPausedStatus +// IBeacon(result.strategyBeacon) +// ) +// ); +// UpgradeableProxyLib.upgradeAndCall(result.strategyFactory, strategyFactoryImpl, upgradeCall); + +// // Upgrade EigenPodManager contract +// upgradeCall = abi.encodeCall( +// EigenPodManager.initialize, +// ( +// proxyAdmin, // initialOwner +// IPauserRegistry(result.pauserRegistry), // _pauserRegistry +// configData.eigenPodManager.initPausedStatus // initialPausedStatus +// ) +// ); +// UpgradeableProxyLib.upgradeAndCall(result.eigenPodManager, eigenPodManagerImpl, upgradeCall); + +// // Upgrade AVSDirectory contract +// upgradeCall = abi.encodeCall( +// AVSDirectory.initialize, +// ( +// proxyAdmin, // initialOwner +// IPauserRegistry(result.pauserRegistry), // _pauserRegistry +// 0 // TODO: AVS Missing configinitialPausedStatus +// ) +// ); +// UpgradeableProxyLib.upgradeAndCall(result.avsDirectory, avsDirectoryImpl, upgradeCall); + +// // Upgrade RewardsCoordinator contract +// upgradeCall = abi.encodeCall( +// RewardsCoordinator.initialize, +// ( +// proxyAdmin, // initialOwner +// IPauserRegistry(result.pauserRegistry), // _pauserRegistry +// configData.rewardsCoordinator.initPausedStatus, // initialPausedStatus +// /// TODO: is there a setter and is this expected? +// address(0), // rewards updater +// uint32(configData.rewardsCoordinator.activationDelay), // _activationDelay +// uint16(configData.rewardsCoordinator.globalOperatorCommissionBips) // _globalCommissionBips +// ) +// ); +// UpgradeableProxyLib.upgradeAndCall( +// result.rewardsCoordinator, rewardsCoordinatorImpl, upgradeCall +// ); + +// // Upgrade EigenPod contract +// upgradeCall = abi.encodeCall( +// EigenPod.initialize, +// // TODO: Double check this +// (address(result.eigenPodManager)) // _podOwner +// ); +// UpgradeableProxyLib.upgradeAndCall(result.eigenPodBeacon, eigenPodImpl, upgradeCall); + +// return result; +// } + +// } \ No newline at end of file diff --git a/test/utils/MockAVSDeployer.sol b/test/utils/MockAVSDeployer.sol index 19a08295..226502ed 100644 --- a/test/utils/MockAVSDeployer.sol +++ b/test/utils/MockAVSDeployer.sol @@ -32,8 +32,11 @@ import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {RewardsCoordinatorMock} from "../mocks/RewardsCoordinatorMock.sol"; +import {PermissionControllerMock} from "../mocks/PermissionControllerMock.sol"; import {RewardsCoordinator} from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; +import {PermissionController} from "eigenlayer-contracts/src/contracts/permissions/PermissionController.sol"; +import {AllocationManager} from "eigenlayer-contracts/src/contracts/core/AllocationManager.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; @@ -59,7 +62,6 @@ contract MockAVSDeployer is Test { IBLSApkRegistry public blsApkRegistryImplementation; IIndexRegistry public indexRegistryImplementation; ServiceManagerMock public serviceManagerImplementation; - AllocationManagerMock public allocationManagerImplementation; OperatorStateRetriever public operatorStateRetriever; RegistryCoordinatorHarness public registryCoordinator; @@ -67,7 +69,6 @@ contract MockAVSDeployer is Test { BLSApkRegistryHarness public blsApkRegistry; IIndexRegistry public indexRegistry; ServiceManagerMock public serviceManager; - AllocationManagerMock public allocationManager; StrategyManagerMock public strategyManagerMock; DelegationMock public delegationMock; @@ -76,9 +77,12 @@ contract MockAVSDeployer is Test { AVSDirectory public avsDirectoryImplementation; AVSDirectoryMock public avsDirectoryMock; AllocationManagerMock public allocationManagerMock; + AllocationManager public allocationManager; + AllocationManager public allocationManagerImplementation; RewardsCoordinator public rewardsCoordinator; RewardsCoordinator public rewardsCoordinatorImplementation; RewardsCoordinatorMock public rewardsCoordinatorMock; + PermissionControllerMock public permissionControllerMock; /// @notice StakeRegistry, Constant used as a divisor in calculating weights. uint256 public constant WEIGHTING_DIVISOR = 1e18; @@ -135,24 +139,20 @@ contract MockAVSDeployer is Test { function _deployMockEigenLayerAndAVS(uint8 numQuorumsToAdd) internal { emptyContract = new EmptyContract(); - defaultOperatorId = defaultPubKey.hashG1Point(); cheats.startPrank(proxyAdminOwner); proxyAdmin = new ProxyAdmin(); - address[] memory pausers = new address[](1); pausers[0] = pauser; pauserRegistry = new PauserRegistry(pausers, unpauser); - delegationMock = new DelegationMock(); avsDirectoryMock = new AVSDirectoryMock(); eigenPodManagerMock = new EigenPodManagerMock(pauserRegistry); - strategyManagerMock = new StrategyManagerMock(); + strategyManagerMock = new StrategyManagerMock(delegationMock); allocationManagerMock = new AllocationManagerMock(); - avsDirectoryMock = new AVSDirectoryMock(); - allocationManagerMock = new AllocationManagerMock(); - avsDirectoryImplementation = new AVSDirectory(delegationMock, 0); // TODO: config value + permissionControllerMock = new PermissionControllerMock(); + avsDirectoryImplementation = new AVSDirectory(delegationMock, pauserRegistry); // TODO: config value avsDirectory = AVSDirectory( address( new TransparentUpgradeableProxy( @@ -160,15 +160,13 @@ contract MockAVSDeployer is Test { address(proxyAdmin), abi.encodeWithSelector( AVSDirectory.initialize.selector, - msg.sender, - pauserRegistry, - 0 /*initialPausedStatus*/ + msg.sender, // initialOwner + 0 // initialPausedStatus ) ) ) ); rewardsCoordinatorMock = new RewardsCoordinatorMock(); - strategyManagerMock.setDelegationManager(delegationMock); cheats.stopPrank(); @@ -178,58 +176,49 @@ contract MockAVSDeployer is Test { new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") ) ); - stakeRegistry = StakeRegistryHarness( address( new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") ) ); - indexRegistry = IndexRegistry( address( new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") ) ); - blsApkRegistry = BLSApkRegistryHarness( address( new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") ) ); - serviceManager = ServiceManagerMock( address( new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") ) ); - - allocationManager = AllocationManagerMock( + allocationManager = AllocationManager( address( new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") ) ); - cheats.stopPrank(); cheats.startPrank(proxyAdminOwner); stakeRegistryImplementation = new StakeRegistryHarness(IRegistryCoordinator(registryCoordinator), delegationMock, avsDirectory, serviceManager); - proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(stakeRegistry))), address(stakeRegistryImplementation) ); blsApkRegistryImplementation = new BLSApkRegistryHarness(registryCoordinator); - proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(blsApkRegistry))), address(blsApkRegistryImplementation) ); indexRegistryImplementation = new IndexRegistry(registryCoordinator); - proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(indexRegistry))), address(indexRegistryImplementation) @@ -242,14 +231,18 @@ contract MockAVSDeployer is Test { stakeRegistry, allocationManager ); - proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(serviceManager))), address(serviceManagerImplementation) ); - allocationManagerImplementation = new AllocationManagerMock(); - + allocationManagerImplementation = new AllocationManager( + delegationMock, + pauserRegistry, + permissionControllerMock, + uint32(7 days), // DEALLOCATION_DELAY + uint32(1 days) // ALLOCATION_CONFIGURATION_DELAY + ); proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(allocationManager))), address(allocationManagerImplementation) @@ -281,7 +274,7 @@ contract MockAVSDeployer is Test { } registryCoordinatorImplementation = new RegistryCoordinatorHarness( - serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, avsDirectory + serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, avsDirectory, pauserRegistry ); { delete operatorSetParams; @@ -309,20 +302,20 @@ contract MockAVSDeployer is Test { proxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(registryCoordinator))), address(registryCoordinatorImplementation), - abi.encodeWithSelector( - RegistryCoordinator.initialize.selector, - registryCoordinatorOwner, - churnApprover, - ejector, - pauserRegistry, - 0, /*initialPausedStatus*/ - operatorSetParams, - minimumStakeForQuorum, - quorumStrategiesConsideredAndMultipliers, - quorumStakeTypes, - slashableStakeQuorumLookAheadPeriods - ) - ); + abi.encodeCall( + RegistryCoordinator.initialize, + ( + registryCoordinatorOwner, // _initialOwner + churnApprover, // _churnApprover + ejector, // _ejector + 0, // _initialPausedStatus + operatorSetParams, // _operatorSetParams + minimumStakeForQuorum, // _minimumStakes + quorumStrategiesConsideredAndMultipliers, // _strategyParams + quorumStakeTypes, // _stakeTypes + slashableStakeQuorumLookAheadPeriods // _lookAheadPeriods + ) + )); } operatorStateRetriever = new OperatorStateRetriever(); @@ -330,6 +323,31 @@ contract MockAVSDeployer is Test { cheats.stopPrank(); } + function _labelContracts() internal { + vm.label(address(emptyContract), "EmptyContract"); + vm.label(address(proxyAdmin), "ProxyAdmin"); + vm.label(address(pauserRegistry), "PauserRegistry"); + vm.label(address(delegationMock), "DelegationMock"); + vm.label(address(avsDirectoryMock), "AVSDirectoryMock"); + vm.label(address(eigenPodManagerMock), "EigenPodManagerMock"); + vm.label(address(strategyManagerMock), "StrategyManagerMock"); + vm.label(address(allocationManagerMock), "AllocationManagerMock"); + vm.label(address(avsDirectoryImplementation), "AVSDirectoryImplementation"); + vm.label(address(avsDirectory), "AVSDirectory"); + vm.label(address(rewardsCoordinatorMock), "RewardsCoordinatorMock"); + vm.label(address(registryCoordinator), "RegistryCoordinator"); + vm.label(address(stakeRegistry), "StakeRegistry"); + vm.label(address(indexRegistry), "IndexRegistry"); + vm.label(address(blsApkRegistry), "BLSApkRegistry"); + vm.label(address(serviceManager), "ServiceManager"); + vm.label(address(allocationManager), "AllocationManager"); + vm.label(address(stakeRegistryImplementation), "StakeRegistryImplementation"); + vm.label(address(blsApkRegistryImplementation), "BLSApkRegistryImplementation"); + vm.label(address(indexRegistryImplementation), "IndexRegistryImplementation"); + vm.label(address(serviceManagerImplementation), "ServiceManagerImplementation"); + vm.label(address(allocationManagerImplementation), "AllocationManagerImplementation"); + } + /** * @notice registers operator with coordinator */ From dbd59ddb1ed8920fdae77c0bb6bc948970073827 Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Mon, 9 Dec 2024 13:05:46 -0500 Subject: [PATCH 26/52] feat: registration changes part 2 * chore: add note * fix: remove handling of forceDeregistration * fix: fix total delegated stake usage * fix: integration tests * test: fix remaining integration tests * test: add back log check * test: add additional tests for transition to operator sets * test: add more test cases * feat: record m2 quorums on migration * chore: add note about churn support * fix: prevent operator set registration changes for m2 quorums * feat: require strings * chore: add dev note and add require string --- src/RegistryCoordinator.sol | 105 ++-- src/RegistryCoordinatorStorage.sol | 11 +- src/ServiceManagerBase.sol | 11 + src/StakeRegistry.sol | 16 +- src/interfaces/IRegistryCoordinator.sol | 12 +- src/interfaces/IServiceManager.sol | 9 + src/interfaces/IStakeRegistry.sol | 1 - src/unaudited/ECDSAServiceManagerBase.sol | 13 + test/integration/IntegrationDeployer.t.sol | 28 +- test/integration/User.t.sol | 5 +- test/unit/ECDSAServiceManager.t.sol | 20 +- test/unit/RegistryCoordinatorUnit.t.sol | 537 +++++++++++++++++++++ 12 files changed, 666 insertions(+), 102 deletions(-) diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 354ae067..102e462f 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -24,6 +24,8 @@ import {EIP712} from "@openzeppelin/contracts/utils/cryptography/draft-EIP712.so import {Pausable} from "eigenlayer-contracts/src/contracts/permissions/Pausable.sol"; import {RegistryCoordinatorStorage} from "./RegistryCoordinatorStorage.sol"; +import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; + /** * @title A `RegistryCoordinator` that has three registries: @@ -46,8 +48,6 @@ contract RegistryCoordinator is using BitmapUtils for *; using BN254 for BN254.G1Point; - bool isOperatorSetAVS; - modifier onlyEjector() { _checkEjector(); _; @@ -143,7 +143,7 @@ contract RegistryCoordinator is IBLSApkRegistry.PubkeyRegistrationParams memory params, SignatureWithSaltAndExpiry memory operatorSignature ) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { - if (isUsingOperatorSets()) revert(); + require(!isUsingOperatorSets(), "RegistryCoordinator.registerOperator: operator sets enabled"); /** * If the operator has NEVER registered a pubkey before, use `params` to register * their pubkey in blsApkRegistry @@ -195,7 +195,7 @@ contract RegistryCoordinator is SignatureWithSaltAndExpiry memory churnApproverSignature, SignatureWithSaltAndExpiry memory operatorSignature ) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { - if (isUsingOperatorSets()) revert(); + require(!isUsingOperatorSets(), "RegistryCoordinator.registerOperatorWithChurn: operator sets not supported"); require( operatorKickParams.length == quorumNumbers.length, "RegistryCoordinator.registerOperatorWithChurn: input length mismatch" @@ -260,6 +260,16 @@ contract RegistryCoordinator is external onlyWhenNotPaused(PAUSED_DEREGISTER_OPERATOR) { + // Check that either: + // 1. The AVS hasn't migrated to operator sets yet (!isOperatorSetAVS), or + // 2. The AVS has migrated but this is an M2 quorum + for (uint256 i = 0; i < quorumNumbers.length; i++) { + uint8 quorumNumber = uint8(quorumNumbers[i]); + require( + !isOperatorSetAVS || isM2Quorum[quorumNumber], + "RegistryCoordinator.deregisterOperator: cannot deregister from non-M2 quorum after operator sets enabled" + ); + } _deregisterOperator({operator: msg.sender, quorumNumbers: quorumNumbers}); } @@ -268,10 +278,20 @@ contract RegistryCoordinator is } function enableOperatorSets() external onlyOwner { - /// TODO: - /// Triggers the updates to use operator sets - /// Opens update the AVS Registrar Hooks on this contract + /// Triggers the updates to use operator sets ie setsAVSRegistrar + /// Opens up the AVS Registrar Hooks on this contract to be callable by the ALM /// Allows creation of quorums with slashable and total delegated stake for operator sets + /// Sets all quorums created before this call as m2 quorums in a mapping so that we can gate function calls to deregister + /// M2 Registrations turn off once migrated. M2 deregistration remain open for only m2 quorums + // Set this contract as the AVS registrar in the service manager + serviceManager.setAVSRegistrar(IAVSRegistrar(address(this))); + + // Set all existing quorums as m2 quorums + for (uint8 i = 0; i < quorumCount; i++) { + isM2Quorum[i] = true; + } + + // Enable operator sets mode isOperatorSetAVS = true; } @@ -279,10 +299,11 @@ contract RegistryCoordinator is address operator, uint32[] memory operatorSetIds, bytes memory data - ) external override { - if (!isUsingOperatorSets()) revert(); - /// TODO: Make a mapping for quorums associated with operator sets / ones associated with m2 registrations - /// TODO: only allow registration of operator sets that have been created in the core and don't conflict with existing quorum numbers + ) external override onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { + require(isUsingOperatorSets(), "RegistryCoordinator.registerOperator: operator sets not enabled"); + for (uint256 i = 0; i < operatorSetIds.length; i++) { + require(!isM2Quorum[uint8(operatorSetIds[i])], "RegistryCoordinator.registerOperator: cannot register for M2 quorum"); + } require(msg.sender == address(serviceManager.allocationManager()), "Only allocation manager can register operators"); // Decode registration data from bytes @@ -299,26 +320,28 @@ contract RegistryCoordinator is } // Register operator with decoded parameters - _registerOperatorNew({ + _registerOperatorToOperatorSet({ operator: operator, operatorId: operatorId, quorumNumbers: quorumNumbers, socket: socket }); - /// TODO: Correctly handle decoding the registration with churn and the normal registration flow parameters + /// TODO: Register with Churn doesn't seem to be used in practice. I would advocate for not even handling the + /// the case and just killing off the function. This would free up code size as well + /// TODO: alternatively, Correctly handle decoding the registration with churn and the normal registration flow parameters } function deregisterOperator( address operator, uint32[] memory operatorSetIds - ) external override { - if (!isUsingOperatorSets()) revert(); + ) external override onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { + require(isUsingOperatorSets(), "RegistryCoordinator.deregisterOperator: operator sets not enabled"); + for (uint256 i = 0; i < operatorSetIds.length; i++) { + require(!isM2Quorum[uint8(operatorSetIds[i])], "RegistryCoordinator.deregisterOperator: cannot deregister from M2 quorum"); + } require(msg.sender == address(serviceManager.allocationManager()), "Only allocation manager can register operators"); - /// TODO: Make a mapping for quorums associated with operator sets / ones associated with m2 registrations - /// TODO: Call _registerOperator to propogate changes to the other contracts - /// TODO: only allow deregistration of operator sets that have been created in the core and don't conflict with existing quorum numbers bytes memory quorumNumbers = new bytes(operatorSetIds.length); for (uint256 i = 0; i < operatorSetIds.length; i++) { quorumNumbers[i] = bytes1(uint8(operatorSetIds[i])); @@ -478,13 +501,15 @@ contract RegistryCoordinator is * registered * @param strategyParams a list of strategies and multipliers used by the StakeRegistry to * calculate an operator's stake weight for the quorum + * @dev For m2 AVS this function has the same behavior as createQuorum before + * For migrated AVS that enable operator sets this will create a quorum that measures total delegated stake for operator set + * */ function createTotalDelegatedStakeQuorum( OperatorSetParam memory operatorSetParams, uint96 minimumStake, IStakeRegistry.StrategyParams[] memory strategyParams ) external virtual onlyOwner { - if (!isUsingOperatorSets()) revert (); _createQuorum(operatorSetParams, minimumStake, strategyParams, StakeType.TOTAL_DELEGATED, 0); } @@ -494,7 +519,7 @@ contract RegistryCoordinator is IStakeRegistry.StrategyParams[] memory strategyParams, uint32 lookAheadPeriod ) external virtual onlyOwner { - if (!isUsingOperatorSets()) revert (); + require(isUsingOperatorSets(), "RegistryCoordinator.createSlashableStakeQuorum: operator sets not enabled"); _createQuorum(operatorSetParams, minimumStake, strategyParams, StakeType.TOTAL_SLASHABLE, lookAheadPeriod); } @@ -620,7 +645,7 @@ contract RegistryCoordinator is * @notice Register the operator for one or more quorums. This method updates the * operator's quorum bitmap, socket, and status, then registers them with each registry. */ - function _registerOperatorNew( + function _registerOperatorToOperatorSet( address operator, bytes32 operatorId, bytes memory quorumNumbers, @@ -682,6 +707,10 @@ contract RegistryCoordinator is require(msg.sender == ejector, "RegistryCoordinator.onlyEjector: not ejector"); } + function _checkAllocationManager() internal view { + address allocationManager = address(serviceManager.allocationManager()); + require(msg.sender == allocationManager, "RegistryCoordinator.onlyAllocationManager: not allocation manager"); + } /** * @notice Checks if a quorum exists * @param quorumNumber The quorum number to check @@ -799,46 +828,16 @@ contract RegistryCoordinator is // Update operator's bitmap and status _updateOperatorBitmap({operatorId: operatorId, newBitmap: newBitmap}); - - /// TODO: Need to know if an AVS is an operator set avs - bool operatorSetAVS; + bool operatorSetAVS = isUsingOperatorSets(); // = IAVSDirectory(serviceManager.avsDirectory()).isOperatorSetAVS(address(serviceManager)); if (operatorSetAVS){ bytes memory quorumBytes = BitmapUtils.bitmapToBytesArray(quorumsToRemove); uint32[] memory operatorSetIds = new uint32[](quorumBytes.length); - uint256 forceDeregistrationCount; for (uint256 i = 0; i < quorumBytes.length; i++) { - /// Post operator sets feature we need to track forceDeregistrations so we don't pass an id that was already deregistered on the AVSDirectory - /// but hasnt yet been recorded in the middleware contracts - - // TODO: Fix need a way to check member ship in the allocation manager without iterating through every member - - // if (!avsDirectory.isMember(operator, OperatorSet(address(serviceManager), uint8(quorumBytes[i])))){ - // forceDeregistrationCount++; - // } operatorSetIds[i] = uint8(quorumBytes[i]); } - /// Filter out forceDeregistration operator set Ids - if (forceDeregistrationCount > 0 ){ - uint32[] memory filteredOperatorSetIds = new uint32[](operatorSetIds.length - forceDeregistrationCount); - uint256 offset; - for (uint256 i; i < operatorSetIds.length; i++){ - if (true){ - /// TODO: Fix need to check - // avsDirectory.isMember(operator, OperatorSet(address(serviceManager), operatorSetIds[i]))){ - filteredOperatorSetIds[i] = operatorSetIds[i+offset]; - } else { - offset++; - } - } - serviceManager.deregisterOperatorFromOperatorSets(operator, filteredOperatorSetIds); - } else { - serviceManager.deregisterOperatorFromOperatorSets(operator, operatorSetIds); - - } - - + serviceManager.deregisterOperatorFromOperatorSets(operator, operatorSetIds); } else { // If the operator is no longer registered for any quorums, update their status and deregister // them from the AVS via the EigenLayer core contracts diff --git a/src/RegistryCoordinatorStorage.sol b/src/RegistryCoordinatorStorage.sol index 64486e93..145bc840 100644 --- a/src/RegistryCoordinatorStorage.sol +++ b/src/RegistryCoordinatorStorage.sol @@ -11,7 +11,7 @@ import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { /******************************************************************************* - CONSTANTS AND IMMUTABLES + CONSTANTS AND IMMUTABLES *******************************************************************************/ /// @notice The EIP-712 typehash for the `DelegationApproval` struct used by the contract @@ -40,11 +40,11 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { IStakeRegistry public immutable stakeRegistry; /// @notice the Index Registry contract that will keep track of operators' indexes IIndexRegistry public immutable indexRegistry; - /// @notice the AVS Directory that tracks operator registrations to AVS and operator sets + /// @notice the AVS Directory that tracks operator registrations to AVS and operator sets IAVSDirectory public immutable avsDirectory; /******************************************************************************* - STATE + STATE *******************************************************************************/ /// @notice the current number of quorums supported by the registry coordinator @@ -72,6 +72,9 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { /// @notice the delay in seconds before an operator can reregister after being ejected uint256 public ejectionCooldown; + bool public isOperatorSetAVS; + mapping(uint8 => bool) public isM2Quorum; + constructor( IServiceManager _serviceManager, IStakeRegistry _stakeRegistry, @@ -88,5 +91,5 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { // storage gap for upgradeability // slither-disable-next-line shadowing-state - uint256[39] private __GAP; + uint256[37] private __GAP; } diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index a482c65d..ed0f743e 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -12,6 +12,8 @@ import {ServiceManagerBaseStorage} from "./ServiceManagerBaseStorage.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; +import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; + import {BitmapUtils} from "./libraries/BitmapUtils.sol"; import {LibMergeSort} from "./libraries/LibMergeSort.sol"; @@ -178,6 +180,15 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _setRewardsInitiator(newRewardsInitiator); } + /** + * @notice Sets the AVS registrar address in the AllocationManager + * @param registrar The new AVS registrar address + * @dev Only callable by the registry coordinator + */ + function setAVSRegistrar(IAVSRegistrar registrar) external onlyRegistryCoordinator { + _allocationManager.setAVSRegistrar(address(this), registrar); + } + /** * @notice Proposes a new slasher address * @param newSlasher The new slasher address diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index 73bea57b..0a5d8d97 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -175,21 +175,7 @@ contract StakeRegistry is StakeRegistryStorage { (uint96 stakeWeight, bool hasMinimumStake) = _weightOfOperatorForQuorum(quorumNumber, operator); // If the operator no longer meets the minimum stake, set their stake to zero and mark them for removal /// also handle setting the operator's stake to 0 and remove them from the quorum - /// if they directly unregistered from the AVSDirectory bubbles up info via registry coordinator to deregister them - bool operatorRegistered; - // Convert quorumNumber to operatorSetId - uint32 operatorSetId = uint32(quorumNumber); - - // Get the AVSDirectory address from the RegistryCoordinator - // Query the AVSDirectory to check if the operator is directly unregistered - operatorRegistered; - // TODO: Fix - // = avsDirectory.isMember( - // operator, - // OperatorSet(address(serviceManager), operatorSetId) - // ); - - if (!hasMinimumStake || (isOperatorSetAVS && !operatorRegistered)) { + if (!hasMinimumStake) { stakeWeight = 0; quorumsToRemove = uint192(quorumsToRemove.setBit(quorumNumber)); } diff --git a/src/interfaces/IRegistryCoordinator.sol b/src/interfaces/IRegistryCoordinator.sol index 3a56baa2..da20a3bc 100644 --- a/src/interfaces/IRegistryCoordinator.sol +++ b/src/interfaces/IRegistryCoordinator.sol @@ -51,7 +51,7 @@ interface IRegistryCoordinator { } /** - * @notice Data structure for storing info on quorum bitmap updates where the `quorumBitmap` is the bitmap of the + * @notice Data structure for storing info on quorum bitmap updates where the `quorumBitmap` is the bitmap of the * quorums the operator is registered for starting at (inclusive)`updateBlockNumber` and ending at (exclusive) `nextUpdateBlockNumber` * @dev nextUpdateBlockNumber is initialized to 0 for the latest update */ @@ -62,11 +62,11 @@ interface IRegistryCoordinator { } /** - * @notice Data structure for storing operator set params for a given quorum. Specifically the + * @notice Data structure for storing operator set params for a given quorum. Specifically the * `maxOperatorCount` is the maximum number of operators that can be registered for the quorum, * `kickBIPsOfOperatorStake` is the basis points of a new operator needs to have of an operator they are trying to kick from the quorum, * and `kickBIPsOfTotalStake` is the basis points of the total stake of the quorum that an operator needs to be below to be kicked. - */ + */ struct OperatorSetParam { uint32 maxOperatorCount; uint16 kickBIPsOfOperatorStake; @@ -97,7 +97,7 @@ interface IRegistryCoordinator { * @param quorumNumbers are the quorum numbers to eject the operator from */ function ejectOperator( - address operator, + address operator, bytes calldata quorumNumbers ) external; @@ -121,8 +121,8 @@ interface IRegistryCoordinator { /** * @notice Returns the quorum bitmap for the given `operatorId` at the given `blockNumber` via the `index` - * @dev reverts if `index` is incorrect - */ + * @dev reverts if `index` is incorrect + */ function getQuorumBitmapAtBlockNumberByIndex(bytes32 operatorId, uint32 blockNumber, uint256 index) external view returns (uint192); /// @notice Returns the `index`th entry in the operator with `operatorId`'s bitmap history diff --git a/src/interfaces/IServiceManager.sol b/src/interfaces/IServiceManager.sol index 6c2bcf94..cdab4383 100644 --- a/src/interfaces/IServiceManager.sol +++ b/src/interfaces/IServiceManager.sol @@ -6,6 +6,8 @@ import {IServiceManagerUI} from "./IServiceManagerUI.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; + /** * @title Minimal interface for a ServiceManager-type contract that forms the single point for an AVS to push updates to EigenLayer @@ -39,6 +41,13 @@ interface IServiceManager is IServiceManagerUI { ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature ) external; + /** + * @notice Sets the AVS registrar address in the AllocationManager + * @param registrar The new AVS registrar address + * @dev Only callable by the registry coordinator + */ + function setAVSRegistrar(IAVSRegistrar registrar) external; + /** * @notice Forwards a call to EigenLayer's AVSDirectory contract to deregister an operator from operator sets * @param operator The address of the operator to deregister. diff --git a/src/interfaces/IStakeRegistry.sol b/src/interfaces/IStakeRegistry.sol index ded09290..62756d3a 100644 --- a/src/interfaces/IStakeRegistry.sol +++ b/src/interfaces/IStakeRegistry.sol @@ -47,7 +47,6 @@ interface IStakeRegistry is IRegistry { uint96 stake ); - /// @notice emitted when the look ahead time for checking operator shares is updated event LookAheadPeriodChanged(uint32 oldLookAheadDays, uint32 newLookAheadDays); diff --git a/src/unaudited/ECDSAServiceManagerBase.sol b/src/unaudited/ECDSAServiceManagerBase.sol index c358796d..4fc517d9 100644 --- a/src/unaudited/ECDSAServiceManagerBase.sol +++ b/src/unaudited/ECDSAServiceManagerBase.sol @@ -12,6 +12,10 @@ import {IStakeRegistry} from "../interfaces/IStakeRegistry.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; import {Quorum} from "../interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; import {ECDSAStakeRegistry} from "../unaudited/ECDSAStakeRegistry.sol"; +import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; +import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; + + abstract contract ECDSAServiceManagerBase is IServiceManager, @@ -227,6 +231,15 @@ abstract contract ECDSAServiceManagerBase is return strategies; } + /** + * @notice Sets the AVS registrar address in the AllocationManager + * @param registrar The new AVS registrar address + * @dev Only callable by the registry coordinator + */ + function setAVSRegistrar(IAVSRegistrar registrar) external onlyOwner { + IAllocationManager(allocationManager).setAVSRegistrar(address(this), registrar); + } + /** * @notice Retrieves the addresses of strategies where the operator has restaked. * @dev This function fetches the quorum details from the ECDSAStakeRegistry, retrieves the operator's shares for each strategy, diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index a162746c..79089178 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -204,6 +204,14 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { GENESIS_REWARDS_TIMESTAMP ); + AllocationManager allocationManagerImplementation = new AllocationManager( + delegationManager, + pauserRegistry, + permissionController, + uint32(7 days), // DEALLOCATION_DELAY + uint32(1 days) // ALLOCATION_CONFIGURATION_DELAY + ); + // Third, upgrade the proxy contracts to point to the implementations uint256 minWithdrawalDelayBlocks = 7 days / 12 seconds; IStrategy[] memory initializeStrategiesToSetDelayBlocks = new IStrategy[](0); @@ -215,11 +223,7 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { abi.encodeWithSelector( DelegationManager.initialize.selector, eigenLayerReputedMultisig, // initialOwner - pauserRegistry, - 0, /* initialPausedStatus */ - minWithdrawalDelayBlocks, - initializeStrategiesToSetDelayBlocks, - initializeWithdrawalDelayBlocks + 0 /* initialPausedStatus */ ) ); // StrategyManager @@ -230,7 +234,6 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { StrategyManager.initialize.selector, eigenLayerReputedMultisig, //initialOwner eigenLayerReputedMultisig, //initial whitelister - pauserRegistry, 0 // initialPausedStatus ) ); @@ -241,11 +244,9 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { abi.encodeWithSelector( EigenPodManager.initialize.selector, eigenLayerReputedMultisig, // initialOwner - pauserRegistry, 0 // initialPausedStatus ) ); - console.log("HERE"); // AVSDirectory proxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(avsDirectory))), @@ -258,7 +259,6 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { ) ); - console.log("HERE 2"); proxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(permissionController))), address(permissionControllerImplementation), @@ -280,6 +280,16 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { ) ); + proxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(allocationManager))), + address(allocationManagerImplementation), + abi.encodeWithSelector( + AllocationManager.initialize.selector, + eigenLayerReputedMultisig, // initialOwner + 0 // initialPausedStatus + ) + ); + // Deploy and whitelist strategies baseStrategyImplementation = new StrategyBase(strategyManager, pauserRegistry); for (uint256 i = 0; i < MAX_STRATEGY_COUNT; i++) { diff --git a/test/integration/User.t.sol b/test/integration/User.t.sol index b31914bd..b98a8cd3 100644 --- a/test/integration/User.t.sol +++ b/test/integration/User.t.sol @@ -265,9 +265,7 @@ contract User is Test { function exitEigenlayer() public createSnapshot virtual returns (IStrategy[] memory, uint256[] memory) { _log("exitEigenlayer (core)"); - IStrategy[] memory strategies; - uint256[] memory shares; - // = delegationManager.getDelegatableShares(address(this)); // TODO: Fix + (IStrategy[] memory strategies, uint256[] memory shares) = delegationManager.getDepositedShares(address(this)); IDelegationManagerTypes.QueuedWithdrawalParams[] memory params = new IDelegationManager.QueuedWithdrawalParams[](1); params[0] = IDelegationManagerTypes.QueuedWithdrawalParams({ @@ -284,7 +282,6 @@ contract User is Test { /** * EIP1271 Signatures: */ - bytes4 internal constant EIP1271_MAGICVALUE = 0x1626ba7e; function isValidSignature(bytes32 digestHash, bytes memory) public view returns (bytes4) { diff --git a/test/unit/ECDSAServiceManager.t.sol b/test/unit/ECDSAServiceManager.t.sol index a20c6d00..487db94a 100644 --- a/test/unit/ECDSAServiceManager.t.sol +++ b/test/unit/ECDSAServiceManager.t.sol @@ -44,6 +44,7 @@ contract MockAllocationManager {} contract MockRewardsCoordinator { function createAVSRewardsSubmission( + address avs, IRewardsCoordinator.RewardsSubmission[] calldata ) external pure {} } @@ -146,19 +147,18 @@ contract ECDSAServiceManagerSetup is Test { strategies[0] = IStrategy(address(420)); strategies[1] = IStrategy(address(421)); - uint256[] memory shares = new uint256[](2); + uint96[] memory shares = new uint96[](2); shares[0] = 0; shares[1] = 1; - // TODO: Fix - // vm.mockCall( - // address(mockDelegationManager), - // abi.encodeCall( - // IDelegationManager.getOperatorShares, - // (operator, strategies) - // ), - // abi.encode(shares) - // ); + vm.mockCall( + address(mockDelegationManager), + abi.encodeCall( + IDelegationManager.getOperatorShares, + (operator, strategies) + ), + abi.encode(shares) + ); address[] memory restakedStrategies = serviceManager .getOperatorRestakedStrategies(operator); diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index 47eb1724..dc272be7 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -1886,3 +1886,540 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit ); } } + +contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnitTests { + function test_registerALMHook_Reverts() public { + cheats.prank(address(serviceManager.allocationManager())); + cheats.expectRevert(); + registryCoordinator.registerOperator(defaultOperator, new uint32[](0), abi.encode(defaultSocket, pubkeyRegistrationParams)); + } + + function test_deregisterALMHook_Reverts() public { + uint32[] memory operatorSetIds = new uint32[](1); + operatorSetIds[0] = 0; + cheats.prank(address(serviceManager.allocationManager())); + cheats.expectRevert(); + registryCoordinator.deregisterOperator(defaultOperator, operatorSetIds); + } + + function test_CreateTotalDelegatedStakeQuorum() public { + _deployMockEigenLayerAndAVS(0); + // Set up test params + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: 10, + kickBIPsOfOperatorStake: 0, + kickBIPsOfTotalStake: 0 + }); + uint96 minimumStake = 100; + IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = IStakeRegistry.StrategyParams({ + strategy: IStrategy(address(0x1)), + multiplier: 1000 + }); + + // Get initial quorum count + uint8 initialQuorumCount = registryCoordinator.quorumCount(); + + // Create quorum with total delegated stake type + cheats.prank(registryCoordinatorOwner); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams, + minimumStake, + strategyParams + ); + + // Verify quorum was created + assertEq(registryCoordinator.quorumCount(), initialQuorumCount + 1); + + // Verify quorum params were set correctly + IRegistryCoordinator.OperatorSetParam memory storedParams = registryCoordinator.getOperatorSetParams(initialQuorumCount); + assertEq(storedParams.maxOperatorCount, operatorSetParams.maxOperatorCount); + assertEq(storedParams.kickBIPsOfOperatorStake, operatorSetParams.kickBIPsOfOperatorStake); + assertEq(storedParams.kickBIPsOfTotalStake, operatorSetParams.kickBIPsOfTotalStake); + } + + function test_CreateSlashableStakeQuorum_Reverts() public { + _deployMockEigenLayerAndAVS(0); + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: 10, + kickBIPsOfOperatorStake: 0, + kickBIPsOfTotalStake: 0 + }); + uint96 minimumStake = 100; + IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = IStakeRegistry.StrategyParams({ + strategy: IStrategy(address(0x1)), + multiplier: 1000 + }); + uint32 lookAheadPeriod = 100; + + // Attempt to create quorum with slashable stake type before enabling operator sets + cheats.prank(registryCoordinatorOwner); + cheats.expectRevert(); + registryCoordinator.createSlashableStakeQuorum( + operatorSetParams, + minimumStake, + strategyParams, + lookAheadPeriod + ); + } + + function test_MigrateToOperatorSets() public { + _deployMockEigenLayerAndAVS(0); + cheats.prank(registryCoordinatorOwner); + registryCoordinator.enableOperatorSets(); + assertTrue(registryCoordinator.isUsingOperatorSets()); + } +} + +contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitTests { + function test_MigrateToOperatorSets() public { + cheats.prank(registryCoordinatorOwner); + registryCoordinator.enableOperatorSets(); + assertTrue(registryCoordinator.isUsingOperatorSets()); + } + + function test_M2_Deregister() public { + // vm.skip(true); + /// Create 2 M2 quorums + _deployMockEigenLayerAndAVS(2); + + address operatorToRegister = address(420); + + ISignatureUtils.SignatureWithSaltAndExpiry memory emptySignature = ISignatureUtils.SignatureWithSaltAndExpiry({ + signature: new bytes(0), + salt: bytes32(0), + expiry: 0 + }); + + IBLSApkRegistry.PubkeyRegistrationParams memory operatorRegisterApkParams = IBLSApkRegistry.PubkeyRegistrationParams({ + pubkeyRegistrationSignature: BN254.G1Point({ + X: 0, + Y: 0 + }), + pubkeyG1: BN254.G1Point({ + X: 0, + Y: 0 + }), + pubkeyG2: BN254.G2Point({ + X: [uint256(0), uint256(0)], + Y: [uint256(0), uint256(0)] + }) + }); + + string memory socket = "socket"; + + // register for quorum 0 + vm.prank(operatorToRegister); + registryCoordinator.registerOperator( + new bytes(1), // Convert 0 to bytes1 first + socket, + operatorRegisterApkParams, + emptySignature + ); + + /// migrate to operator sets + registryCoordinator.enableOperatorSets(); + + /// Deregistration for m2 should for the first two operator sets + vm.prank(defaultOperator); + registryCoordinator.deregisterOperator(new bytes(1)); + + // Verify operator was deregistered by checking their bitmap is empty + bytes32 operatorId = registryCoordinator.getOperatorId(operatorToRegister); + uint192 bitmap = registryCoordinator.getCurrentQuorumBitmap(operatorId); + assertEq(bitmap, 0, "Operator bitmap should be empty after deregistration"); + + // Verify operator status is NEVER_REGISTERED + IRegistryCoordinator.OperatorStatus status = registryCoordinator.getOperatorStatus(operatorToRegister); + assertEq(uint8(status), uint8(IRegistryCoordinator.OperatorStatus.NEVER_REGISTERED), "Operator status should be NEVER_REGISTERED"); + } + + function test_M2_Register_Reverts() public { + cheats.prank(registryCoordinatorOwner); + registryCoordinator.enableOperatorSets(); + + bytes memory quorumNumbers = new bytes(1); + quorumNumbers[0] = bytes1(uint8(0)); + IBLSApkRegistry.PubkeyRegistrationParams memory params; + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; + + cheats.expectRevert(); + registryCoordinator.registerOperator( + quorumNumbers, + defaultSocket, + params, + operatorSignature + ); + } + + function test_createSlashableStakeQuorum() public { + // Deploy with 0 quorums + _deployMockEigenLayerAndAVS(0); + + // Enable operator sets first + cheats.prank(registryCoordinatorOwner); + registryCoordinator.enableOperatorSets(); + + // Create quorum params + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: 10, + kickBIPsOfOperatorStake: 1000, + kickBIPsOfTotalStake: 100 + }); + uint96 minimumStake = 100; + IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = IStakeRegistry.StrategyParams({ + strategy: IStrategy(address(1)), + multiplier: 1 + }); + uint32 lookAheadPeriod = 100; + + // Create slashable stake quorum + cheats.prank(registryCoordinatorOwner); + registryCoordinator.createSlashableStakeQuorum( + operatorSetParams, + minimumStake, + strategyParams, + lookAheadPeriod + ); + } + + function test_createTotalDelegatedStakeQuorum() public { + // Deploy with 0 quorums + _deployMockEigenLayerAndAVS(0); + + // Enable operator sets first + cheats.prank(registryCoordinatorOwner); + registryCoordinator.enableOperatorSets(); + + // Create quorum params + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: 10, + kickBIPsOfOperatorStake: 1000, + kickBIPsOfTotalStake: 100 + }); + uint96 minimumStake = 100; + IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = IStakeRegistry.StrategyParams({ + strategy: IStrategy(address(1)), + multiplier: 10000 + }); + + // Create total delegated stake quorum + cheats.prank(registryCoordinatorOwner); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams, + minimumStake, + strategyParams + ); + } + + function test_registerHook() public { + vm.skip(true); + + _deployMockEigenLayerAndAVS(0); + // Enable operator sets first + cheats.prank(registryCoordinatorOwner); + registryCoordinator.enableOperatorSets(); + + // Create quorum params + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: 10, + kickBIPsOfOperatorStake: 1000, + kickBIPsOfTotalStake: 100 + }); + + uint96 minimumStake = 100; + IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = IStakeRegistry.StrategyParams({ + strategy: IStrategy(address(1)), + multiplier: 10000 + }); + + // Create total delegated stake quorum + cheats.prank(registryCoordinatorOwner); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams, + 0, + strategyParams + ); + + + uint32[] memory operatorSetIds = new uint32[](1); + operatorSetIds[0] = 0; + + string memory socket = "socket"; + IBLSApkRegistry.PubkeyRegistrationParams memory params; + // TODO: + // params = IBLSApkRegistry.PubkeyRegistrationParams({ + // pubkeyG1: defaultPubKey, + // pubkeyG2: defaultPubKeyG2, + // pubkeySignature: defaultPubKeySignature + // }); + + bytes memory data = abi.encode(socket, params); + + address allocationManager = address(serviceManager.allocationManager()); + cheats.prank(allocationManager); + registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); + } + + function test_registerHook_WithChurn() public { + _deployMockEigenLayerAndAVS(0); + // Enable operator sets first + cheats.prank(registryCoordinatorOwner); + registryCoordinator.enableOperatorSets(); + + // Create quorum params + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: 10, + kickBIPsOfOperatorStake: 1000, + kickBIPsOfTotalStake: 100 + }); + + uint96 minimumStake = 100; + IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = IStakeRegistry.StrategyParams({ + strategy: IStrategy(address(1)), + multiplier: 10000 + }); + + // Create total delegated stake quorum + cheats.prank(registryCoordinatorOwner); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams, + 0, + strategyParams + ); + + uint32[] memory operatorSetIds = new uint32[](1); + operatorSetIds[0] = 0; + + string memory socket = "socket"; + IBLSApkRegistry.PubkeyRegistrationParams memory params; + // TODO: + // params = IBLSApkRegistry.PubkeyRegistrationParams({ + // pubkeyG1: defaultPubKey, + // pubkeyG2: defaultPubKeyG2, + // pubkeySignature: defaultPubKeySignature + // }); + + IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = new IRegistryCoordinator.OperatorKickParam[](1); + operatorKickParams[0] = IRegistryCoordinator.OperatorKickParam({ + operator: address(0x1), + quorumNumber: 0 + }); + + ISignatureUtils.SignatureWithSaltAndExpiry memory churnApproverSignature; + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; + + bytes memory registerParams = abi.encode( + socket, + params, + operatorKickParams, + churnApproverSignature, + operatorSignature + ); + + // Prank as allocation manager and call register hook + address allocationManager = address(serviceManager.allocationManager()); + cheats.prank(allocationManager); + registryCoordinator.registerOperator(defaultOperator, operatorSetIds, registerParams); + } + + function test_updateStakesForQuorum() public { + vm.skip(true); + _deployMockEigenLayerAndAVS(0); + + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: defaultMaxOperatorCount, + kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, + kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake + }); + + uint96 minimumStake = 100; + IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = IStakeRegistry.StrategyParams({ + strategy: IStrategy(address(1)), + multiplier: 10000 + }); + + cheats.prank(registryCoordinatorOwner); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams, + minimumStake, + strategyParams + ); + + uint256 quorumBitmap = 0; + + // TODO: register actually and update stakes + } + + function test_deregisterHook() public { + + _deployMockEigenLayerAndAVS(0); + // Enable operator sets first + cheats.prank(registryCoordinatorOwner); + registryCoordinator.enableOperatorSets(); + + // Create quorum params + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: 10, + kickBIPsOfOperatorStake: 1000, + kickBIPsOfTotalStake: 100 + }); + + uint96 minimumStake = 100; + IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = IStakeRegistry.StrategyParams({ + strategy: IStrategy(address(1)), + multiplier: 10000 + }); + + // Create total delegated stake quorum + cheats.prank(registryCoordinatorOwner); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams, + 0, + strategyParams + ); + + // Prank as allocation manager and call register hook + uint32[] memory operatorSetIds = new uint32[](1); + operatorSetIds[0] = 0; + + string memory socket = "socket"; + IBLSApkRegistry.PubkeyRegistrationParams memory params; + // TODO: + // params = IBLSApkRegistry.PubkeyRegistrationParams({ + // pubkeyG1: defaultPubKey, + // pubkeyG2: defaultPubKeyG2, + // pubkeySignature: defaultPubKeySignature + // }); + + bytes memory data = abi.encode(socket, params); + + + address allocationManager = address(serviceManager.allocationManager()); + cheats.startPrank(allocationManager); + registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); + + registryCoordinator.deregisterOperator(defaultOperator, operatorSetIds); + + cheats.stopPrank(); + } + + function test_registerHook_Reverts_WhenNotALM() public { + + _deployMockEigenLayerAndAVS(0); + // Enable operator sets first + cheats.prank(registryCoordinatorOwner); + registryCoordinator.enableOperatorSets(); + + // Create quorum params + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: 10, + kickBIPsOfOperatorStake: 1000, + kickBIPsOfTotalStake: 100 + }); + + uint96 minimumStake = 100; + IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = IStakeRegistry.StrategyParams({ + strategy: IStrategy(address(1)), + multiplier: 10000 + }); + + // Create total delegated stake quorum + cheats.prank(registryCoordinatorOwner); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams, + 0, + strategyParams + ); + + + uint32[] memory operatorSetIds = new uint32[](1); + operatorSetIds[0] = 0; + + string memory socket = "socket"; + IBLSApkRegistry.PubkeyRegistrationParams memory params; + // TODO: + // params = IBLSApkRegistry.PubkeyRegistrationParams({ + // pubkeyG1: defaultPubKey, + // pubkeyG2: defaultPubKeyG2, + // pubkeySignature: defaultPubKeySignature + // }); + + bytes memory data = abi.encode(socket, params); + + vm.expectRevert(); + registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); + } + + function test_deregisterHook_Reverts_WhenNotALM() public { + + _deployMockEigenLayerAndAVS(0); + // Enable operator sets first + cheats.prank(registryCoordinatorOwner); + registryCoordinator.enableOperatorSets(); + + // Create quorum params + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: 10, + kickBIPsOfOperatorStake: 1000, + kickBIPsOfTotalStake: 100 + }); + + uint96 minimumStake = 100; + IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = IStakeRegistry.StrategyParams({ + strategy: IStrategy(address(1)), + multiplier: 10000 + }); + + // Create total delegated stake quorum + cheats.prank(registryCoordinatorOwner); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams, + 0, + strategyParams + ); + + // Prank as allocation manager and call register hook + uint32[] memory operatorSetIds = new uint32[](1); + operatorSetIds[0] = 0; + + string memory socket = "socket"; + IBLSApkRegistry.PubkeyRegistrationParams memory params; + // TODO: + // params = IBLSApkRegistry.PubkeyRegistrationParams({ + // pubkeyG1: defaultPubKey, + // pubkeyG2: defaultPubKeyG2, + // pubkeySignature: defaultPubKeySignature + // }); + + bytes memory data = abi.encode(socket, params); + + + address allocationManager = address(serviceManager.allocationManager()); + cheats.startPrank(allocationManager); + registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); + cheats.stopPrank(); + + cheats.expectRevert(); + registryCoordinator.deregisterOperator(defaultOperator, operatorSetIds); + + } + + function test_DeregisterHook_Reverts_WhenM2Quorum() public { + vm.skip(true); + } + + function test_registerHook_Reverts_WhenM2Quorum() public { + vm.skip(true); + } + +} From 6fd466ec4ddc96070a7820feceeb9a14e0bb3e27 Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Tue, 10 Dec 2024 12:25:51 -0500 Subject: [PATCH 27/52] chore: bump dependency for slashing mags updates (#329) --- lib/eigenlayer-contracts | 2 +- src/interfaces/ISlasher.sol | 4 ++-- src/slashers/VetoableSlasher.sol | 2 +- src/slashers/base/SlasherBase.sol | 2 +- test/integration/CoreRegistration.t.sol | 9 ++++++++- test/integration/IntegrationDeployer.t.sol | 11 ++++------- test/mocks/AllocationManagerMock.sol | 5 +++++ 7 files changed, 22 insertions(+), 13 deletions(-) diff --git a/lib/eigenlayer-contracts b/lib/eigenlayer-contracts index f8c12749..d3109212 160000 --- a/lib/eigenlayer-contracts +++ b/lib/eigenlayer-contracts @@ -1 +1 @@ -Subproject commit f8c127498a3e5f019732a3e35387a2066935cc6b +Subproject commit d3109212d8869ebba791790bfe0e22bdfadd7e5f diff --git a/src/interfaces/ISlasher.sol b/src/interfaces/ISlasher.sol index 018cf16c..b938e915 100644 --- a/src/interfaces/ISlasher.sol +++ b/src/interfaces/ISlasher.sol @@ -10,7 +10,7 @@ interface ISlasherEvents { uint256 indexed requestId, address indexed operator, uint32 indexed operatorSetId, - uint256 wadToSlash, + uint256[] wadsToSlash, string description ); @@ -20,7 +20,7 @@ interface ISlasherEvents { uint256 indexed slashingRequestId, address indexed operator, uint32 indexed operatorSetId, - uint256 wadToSlash, + uint256[] wadsToSlash, string description ); } diff --git a/src/slashers/VetoableSlasher.sol b/src/slashers/VetoableSlasher.sol index b65442b6..697bbd04 100644 --- a/src/slashers/VetoableSlasher.sol +++ b/src/slashers/VetoableSlasher.sol @@ -63,7 +63,7 @@ contract VetoableSlashing is SlasherBase { status: SlashingStatus.Requested }); - emit SlashingRequested(requestId, params.operator, params.operatorSetId, params.wadToSlash, params.description); + emit SlashingRequested(requestId, params.operator, params.operatorSetId, params.wadsToSlash, params.description); } function _cancelSlashingRequest(uint256 requestId) internal virtual { diff --git a/src/slashers/base/SlasherBase.sol b/src/slashers/base/SlasherBase.sol index 8357c6f4..181dae59 100644 --- a/src/slashers/base/SlasherBase.sol +++ b/src/slashers/base/SlasherBase.sol @@ -24,7 +24,7 @@ abstract contract SlasherBase is Initializable, SlasherStorage { IAllocationManager.SlashingParams memory _params ) internal virtual { IServiceManager(serviceManager).slashOperator(_params); - emit OperatorSlashed(_requestId, _params.operator, _params.operatorSetId, _params.wadToSlash, _params.description); + emit OperatorSlashed(_requestId, _params.operator, _params.operatorSetId, _params.wadsToSlash, _params.description); } function _checkSlasher(address account) internal view virtual { diff --git a/test/integration/CoreRegistration.t.sol b/test/integration/CoreRegistration.t.sol index f385c7e2..a237e410 100644 --- a/test/integration/CoreRegistration.t.sol +++ b/test/integration/CoreRegistration.t.sol @@ -29,7 +29,14 @@ contract Test_CoreRegistration is MockAVSDeployer { // Deploy New DelegationManager PermissionController permissionController; // TODO: Fix - DelegationManager delegationManagerImplementation = new DelegationManager(avsDirectoryMock, IStrategyManager(address(strategyManagerMock)), eigenPodManagerMock, allocationManagerMock, pauserRegistry, permissionController, 0); + DelegationManager delegationManagerImplementation = new DelegationManager( + IStrategyManager(address(strategyManagerMock)), + eigenPodManagerMock, + allocationManagerMock, + pauserRegistry, + permissionController, + 0 + ); IStrategy[] memory initializeStrategiesToSetDelayBlocks = new IStrategy[](0); uint256[] memory initializeWithdrawalDelayBlocks = new uint256[](0); delegationManager = DelegationManager( diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index 79089178..db3fb704 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -182,11 +182,11 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs DelegationManager delegationImplementation = - new DelegationManager(avsDirectory, strategyManager, eigenPodManager, allocationManager, pauserRegistry, permissionController, 0); + new DelegationManager(strategyManager, eigenPodManager, allocationManager, pauserRegistry, permissionController, 0); StrategyManager strategyManagerImplementation = new StrategyManager(delegationManager, pauserRegistry); EigenPodManager eigenPodManagerImplementation = new EigenPodManager( - ethPOSDeposit, eigenPodBeacon, strategyManager, delegationManager, pauserRegistry + ethPOSDeposit, eigenPodBeacon, delegationManager, pauserRegistry ); console.log("HERE Impl"); AVSDirectory avsDirectoryImplementation = new AVSDirectory(delegationManager, pauserRegistry); @@ -259,12 +259,9 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { ) ); - proxyAdmin.upgradeAndCall( + proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(permissionController))), - address(permissionControllerImplementation), - abi.encodeWithSelector( - PermissionController.initialize.selector - ) + address(permissionControllerImplementation) ); proxyAdmin.upgradeAndCall( diff --git a/test/mocks/AllocationManagerMock.sol b/test/mocks/AllocationManagerMock.sol index adf06c62..fdb11248 100644 --- a/test/mocks/AllocationManagerMock.sol +++ b/test/mocks/AllocationManagerMock.sol @@ -163,6 +163,11 @@ contract AllocationManagerIntermediate is IAllocationManager { IStrategy[] memory strategies, uint32 futureBlock ) external view virtual returns (uint256[][] memory slashableStake) {} + + function isMemberOfOperatorSet( + address operator, + OperatorSet memory operatorSet + ) external view virtual returns (bool) {} } contract AllocationManagerMock is AllocationManagerIntermediate { From 19751c9f612c99e8b1bf8cd82997fdf69b967bb0 Mon Sep 17 00:00:00 2001 From: Nadir Akhtar Date: Fri, 13 Dec 2024 06:45:27 -0800 Subject: [PATCH 28/52] fix: internal slashing security review (#332) * docs: match file and library name, and add docstrings * docs: update error strings to match function * style: forge fmt + moving variables around + fixing error strings * fix: enforce max quorum count for EjectionManager * style: more error string fixes + formatting * fix: correctly set StakeRegistryStorage gap * style: more error string corrections + typos --- ...gradeLib.sol => OperatorSetUpgradeLib.sol} | 16 ++++++++-- src/BLSApkRegistry.sol | 30 +++++++++---------- src/EjectionManager.sol | 30 +++++++++++-------- src/IndexRegistry.sol | 28 ++++++++--------- src/RegistryCoordinator.sol | 10 +++---- src/ServiceManagerBase.sol | 2 +- src/StakeRegistryStorage.sol | 2 +- src/interfaces/IServiceManager.sol | 2 +- src/slashers/VetoableSlasher.sol | 12 ++++---- src/slashers/base/SlasherBase.sol | 2 +- 10 files changed, 76 insertions(+), 58 deletions(-) rename script/utils/{UpgradeLib.sol => OperatorSetUpgradeLib.sol} (72%) diff --git a/script/utils/UpgradeLib.sol b/script/utils/OperatorSetUpgradeLib.sol similarity index 72% rename from script/utils/UpgradeLib.sol rename to script/utils/OperatorSetUpgradeLib.sol index 0b136c8e..30e921dc 100644 --- a/script/utils/UpgradeLib.sol +++ b/script/utils/OperatorSetUpgradeLib.sol @@ -10,10 +10,22 @@ import {stdJson} from "forge-std/StdJson.sol"; library OperatorSetUpgradeLib { using stdJson for string; - Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + // address(uint160(uint256(keccak256("hevm cheat code")))) == 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D + // solhint-disable-next-line const-name-snakecase + Vm private constant vm = Vm(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D); + + /** + * @dev Storage slot with the address of the current implementation. + * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1. + */ bytes32 internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; + /** + * @dev Storage slot with the admin of the contract. + * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. + */ bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; @@ -28,7 +40,7 @@ library OperatorSetUpgradeLib { admin.upgrade(TransparentUpgradeableProxy(payable(proxy)), implementation); } - function getAdmin(address proxy) internal view returns (address){ + function getAdmin(address proxy) internal view returns (address) { bytes32 value = vm.load(proxy, ADMIN_SLOT); return address(uint160(uint256(value))); } diff --git a/src/BLSApkRegistry.sol b/src/BLSApkRegistry.sol index 2bad724b..d7d3c5eb 100644 --- a/src/BLSApkRegistry.sol +++ b/src/BLSApkRegistry.sol @@ -114,17 +114,17 @@ contract BLSApkRegistry is BLSApkRegistryStorage { // gamma = h(sigma, P, P', H(m)) uint256 gamma = uint256(keccak256(abi.encodePacked( - params.pubkeyRegistrationSignature.X, - params.pubkeyRegistrationSignature.Y, - params.pubkeyG1.X, - params.pubkeyG1.Y, - params.pubkeyG2.X, - params.pubkeyG2.Y, - pubkeyRegistrationMessageHash.X, + params.pubkeyRegistrationSignature.X, + params.pubkeyRegistrationSignature.Y, + params.pubkeyG1.X, + params.pubkeyG1.Y, + params.pubkeyG2.X, + params.pubkeyG2.Y, + pubkeyRegistrationMessageHash.X, pubkeyRegistrationMessageHash.Y ))) % BN254.FR_MODULUS; - - // e(sigma + P * gamma, [-1]_2) = e(H(m) + [1]_1 * gamma, P') + + // e(sigma + P * gamma, [-1]_2) = e(H(m) + [1]_1 * gamma, P') require(BN254.pairing( params.pubkeyRegistrationSignature.plus(params.pubkeyG1.scalar_mul(gamma)), BN254.negGeneratorG2(), @@ -189,7 +189,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage { pubkeyHash != bytes32(0), "BLSApkRegistry.getRegisteredPubkey: operator is not registered" ); - + return (pubkey, pubkeyHash); } @@ -202,10 +202,10 @@ contract BLSApkRegistry is BLSApkRegistryStorage { uint256 blockNumber ) external view returns (uint32[] memory) { uint32[] memory indices = new uint32[](quorumNumbers.length); - + for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); - + uint256 quorumApkUpdatesLength = apkHistory[quorumNumber].length; if (quorumApkUpdatesLength == 0 || blockNumber < apkHistory[quorumNumber][0].updateBlockNumber) { revert("BLSApkRegistry.getApkIndicesAtBlockNumber: blockNumber is before the first update"); @@ -253,11 +253,11 @@ contract BLSApkRegistry is BLSApkRegistryStorage { */ require( blockNumber >= quorumApkUpdate.updateBlockNumber, - "BLSApkRegistry._validateApkHashAtBlockNumber: index too recent" + "BLSApkRegistry.getApkHashAtBlockNumberAndIndex: index too recent" ); require( quorumApkUpdate.nextUpdateBlockNumber == 0 || blockNumber < quorumApkUpdate.nextUpdateBlockNumber, - "BLSApkRegistry._validateApkHashAtBlockNumber: not latest apk update" + "BLSApkRegistry.getApkHashAtBlockNumberAndIndex: not latest apk update" ); return quorumApkUpdate.apkHash; @@ -282,7 +282,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage { function _checkRegistryCoordinator() internal view { require( msg.sender == address(registryCoordinator), - "BLSApkRegistry.onlyRegistryCoordinator: caller is not the registry coordinator" + "BLSApkRegistry._checkRegistryCoordinator: caller is not the registry coordinator" ); } } diff --git a/src/EjectionManager.sol b/src/EjectionManager.sol index 3a164f57..316fcb29 100644 --- a/src/EjectionManager.sol +++ b/src/EjectionManager.sol @@ -10,10 +10,13 @@ import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; * @title Used for automated ejection of operators from the RegistryCoordinator under a ratelimit * @author Layr Labs, Inc. */ -contract EjectionManager is IEjectionManager, OwnableUpgradeable{ +contract EjectionManager is IEjectionManager, OwnableUpgradeable { /// @notice The basis point denominator for the ejectable stake percent - uint16 internal constant BIPS_DENOMINATOR = 10000; + uint16 internal constant BIPS_DENOMINATOR = 10_000; + + /// @notice The max number of quorums + uint8 internal constant MAX_QUORUM_COUNT = 192; /// @notice the RegistryCoordinator contract that is the entry point for ejection IRegistryCoordinator public immutable registryCoordinator; @@ -64,7 +67,7 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable{ * @dev The owner can eject operators without recording of stake ejection */ function ejectOperators(bytes32[][] memory _operatorIds) external { - require(isEjector[msg.sender] || msg.sender == owner(), "Ejector: Only owner or ejector can eject"); + require(isEjector[msg.sender] || msg.sender == owner(), "EjectionManager.ejectOperators: Only owner or ejector can eject"); for(uint i = 0; i < _operatorIds.length; ++i) { uint8 quorumNumber = uint8(i); @@ -98,7 +101,7 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable{ registryCoordinator.getOperatorFromId(_operatorIds[i][j]), abi.encodePacked(quorumNumber) ); - + emit OperatorEjected(_operatorIds[i][j], quorumNumber); } @@ -134,6 +137,7 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable{ ///@dev internal function to set the quorum ejection params function _setQuorumEjectionParams(uint8 _quorumNumber, QuorumEjectionParams memory _quorumEjectionParams) internal { + require(_quorumNumber < MAX_QUORUM_COUNT, "EjectionManager._setQuorumEjectionParams: Quorum number exceeds MAX_QUORUM_COUNT"); quorumEjectionParams[_quorumNumber] = _quorumEjectionParams; emit QuorumEjectionParamsSet(_quorumNumber, _quorumEjectionParams.rateLimitWindow, _quorumEjectionParams.ejectableStakePercent); } @@ -149,25 +153,27 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable{ * @param _quorumNumber The quorum number to view ejectable stake for */ function amountEjectableForQuorum(uint8 _quorumNumber) public view returns (uint256) { - uint256 cutoffTime = block.timestamp - quorumEjectionParams[_quorumNumber].rateLimitWindow; - uint256 totalEjectable = uint256(quorumEjectionParams[_quorumNumber].ejectableStakePercent) * uint256(stakeRegistry.getCurrentTotalStake(_quorumNumber)) / uint256(BIPS_DENOMINATOR); - uint256 totalEjected; - uint256 i; + uint256 totalEjectable = uint256(quorumEjectionParams[_quorumNumber].ejectableStakePercent) + * uint256(stakeRegistry.getCurrentTotalStake(_quorumNumber)) / uint256(BIPS_DENOMINATOR); + if (stakeEjectedForQuorum[_quorumNumber].length == 0) { return totalEjectable; } - i = stakeEjectedForQuorum[_quorumNumber].length - 1; - while(stakeEjectedForQuorum[_quorumNumber][i].timestamp > cutoffTime) { + uint256 cutoffTime = block.timestamp - quorumEjectionParams[_quorumNumber].rateLimitWindow; + uint256 totalEjected = 0; + uint256 i = stakeEjectedForQuorum[_quorumNumber].length - 1; + + while (stakeEjectedForQuorum[_quorumNumber][i].timestamp > cutoffTime) { totalEjected += stakeEjectedForQuorum[_quorumNumber][i].stakeEjected; - if(i == 0){ + if (i == 0) { break; } else { --i; } } - if(totalEjected >= totalEjectable){ + if (totalEjected >= totalEjectable) { return 0; } return totalEjectable - totalEjected; diff --git a/src/IndexRegistry.sol b/src/IndexRegistry.sol index 8df2c0a1..83e039c8 100644 --- a/src/IndexRegistry.sol +++ b/src/IndexRegistry.sol @@ -38,7 +38,7 @@ contract IndexRegistry is IndexRegistryStorage { * 4) the operator is not already registered */ function registerOperator( - bytes32 operatorId, + bytes32 operatorId, bytes calldata quorumNumbers ) public virtual onlyRegistryCoordinator returns(uint32[] memory) { uint32[] memory numOperatorsPerQuorum = new uint32[](quorumNumbers.length); @@ -80,7 +80,7 @@ contract IndexRegistry is IndexRegistryStorage { * 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for */ function deregisterOperator( - bytes32 operatorId, + bytes32 operatorId, bytes calldata quorumNumbers ) public virtual onlyRegistryCoordinator { for (uint256 i = 0; i < quorumNumbers.length; i++) { @@ -131,7 +131,7 @@ contract IndexRegistry is IndexRegistryStorage { function _increaseOperatorCount(uint8 quorumNumber) internal returns (uint32) { QuorumUpdate storage lastUpdate = _latestQuorumUpdate(quorumNumber); uint32 newOperatorCount = lastUpdate.numOperators + 1; - + _updateOperatorCountHistory(quorumNumber, lastUpdate, newOperatorCount); // If this is the first time we're using this operatorIndex, push its first update @@ -152,9 +152,9 @@ contract IndexRegistry is IndexRegistryStorage { function _decreaseOperatorCount(uint8 quorumNumber) internal returns (uint32) { QuorumUpdate storage lastUpdate = _latestQuorumUpdate(quorumNumber); uint32 newOperatorCount = lastUpdate.numOperators - 1; - + _updateOperatorCountHistory(quorumNumber, lastUpdate, newOperatorCount); - + return newOperatorCount; } @@ -198,7 +198,7 @@ contract IndexRegistry is IndexRegistryStorage { * @param operatorId operatorId of the operator to update * @param quorumNumber quorumNumber of the operator to update * @param operatorIndex the latest index of that operator in the list of operators registered for this quorum - */ + */ function _assignOperatorToIndex(bytes32 operatorId, uint8 quorumNumber, uint32 operatorIndex) internal { OperatorUpdate storage lastUpdate = _latestOperatorIndexUpdate(quorumNumber, operatorIndex); @@ -249,7 +249,7 @@ contract IndexRegistry is IndexRegistryStorage { * @dev Reverts if the quorum does not exist, or if the blockNumber is from before the quorum existed */ function _operatorCountAtBlockNumber( - uint8 quorumNumber, + uint8 quorumNumber, uint32 blockNumber ) internal view returns (uint32){ uint256 historyLength = _operatorCountHistory[quorumNumber].length; @@ -262,17 +262,17 @@ contract IndexRegistry is IndexRegistryStorage { return quorumUpdate.numOperators; } } - + revert("IndexRegistry._operatorCountAtBlockNumber: quorum did not exist at given block number"); } - + /** * @return operatorId at the given `operatorIndex` at the given `blockNumber` for the given `quorumNumber` * Precondition: requires that the operatorIndex was used active at the given block number for quorum */ function _operatorIdForIndexAtBlockNumber( - uint8 quorumNumber, - uint32 operatorIndex, + uint8 quorumNumber, + uint32 operatorIndex, uint32 blockNumber ) internal view returns(bytes32) { uint256 historyLength = _operatorIndexHistory[quorumNumber][operatorIndex].length; @@ -320,7 +320,7 @@ contract IndexRegistry is IndexRegistryStorage { /// @notice Returns an ordered list of operators of the services for the given `quorumNumber` at the given `blockNumber` function getOperatorListAtBlockNumber( - uint8 quorumNumber, + uint8 quorumNumber, uint32 blockNumber ) external view returns (bytes32[] memory){ uint32 operatorCount = _operatorCountAtBlockNumber(quorumNumber, blockNumber); @@ -328,7 +328,7 @@ contract IndexRegistry is IndexRegistryStorage { for (uint256 i = 0; i < operatorCount; i++) { operatorList[i] = _operatorIdForIndexAtBlockNumber(quorumNumber, uint32(i), blockNumber); require( - operatorList[i] != OPERATOR_DOES_NOT_EXIST_ID, + operatorList[i] != OPERATOR_DOES_NOT_EXIST_ID, "IndexRegistry.getOperatorListAtBlockNumber: operator does not exist at the given block number" ); } @@ -342,6 +342,6 @@ contract IndexRegistry is IndexRegistryStorage { } function _checkRegistryCoordinator() internal view { - require(msg.sender == address(registryCoordinator), "IndexRegistry.onlyRegistryCoordinator: caller is not the registry coordinator"); + require(msg.sender == address(registryCoordinator), "IndexRegistry._checkRegistryCoordinator: caller is not the registry coordinator"); } } diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 102e462f..884f99cd 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -273,7 +273,7 @@ contract RegistryCoordinator is _deregisterOperator({operator: msg.sender, quorumNumbers: quorumNumbers}); } - function isUsingOperatorSets() public view returns (bool){ + function isUsingOperatorSets() public view returns (bool) { return isOperatorSetAVS; } @@ -641,7 +641,7 @@ contract RegistryCoordinator is return results; } - /** + /** * @notice Register the operator for one or more quorums. This method updates the * operator's quorum bitmap, socket, and status, then registers them with each registry. */ @@ -662,18 +662,18 @@ contract RegistryCoordinator is uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); uint192 currentBitmap = _currentOperatorBitmap(operatorId); require( - !quorumsToAdd.isEmpty(), "RegistryCoordinator._registerOperator: bitmap empty" + !quorumsToAdd.isEmpty(), "RegistryCoordinator._registerOperatorToOperatorSet: bitmap empty" ); require( quorumsToAdd.noBitsInCommon(currentBitmap), - "RegistryCoordinator._registerOperator: operator already registered for some quorums being registered for" + "RegistryCoordinator._registerOperatorToOperatorSet: operator already registered for some quorums being registered for" ); uint192 newBitmap = uint192(currentBitmap.plus(quorumsToAdd)); // Check that the operator can reregister if ejected require( lastEjectionTimestamp[operator] + ejectionCooldown < block.timestamp, - "RegistryCoordinator._registerOperator: operator cannot reregister yet" + "RegistryCoordinator._registerOperatorToOperatorSet: operator cannot reregister yet" ); /** diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index ed0f743e..7ec25bd3 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -94,7 +94,7 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { * @notice Creates a new rewards submission to the EigenLayer RewardsCoordinator contract, to be split amongst the * set of stakers delegated to operators who are registered to this `avs` * @param rewardsSubmissions The rewards submissions being created - * @dev Only callabe by the permissioned rewardsInitiator address + * @dev Only callable by the permissioned rewardsInitiator address * @dev The duration of the `rewardsSubmission` cannot exceed `MAX_REWARDS_DURATION` * @dev The tokens are sent to the `RewardsCoordinator` contract * @dev Strategies must be in ascending order of addresses to check for duplicates diff --git a/src/StakeRegistryStorage.sol b/src/StakeRegistryStorage.sol index 2cfcba43..acc80dd7 100644 --- a/src/StakeRegistryStorage.sol +++ b/src/StakeRegistryStorage.sol @@ -70,5 +70,5 @@ abstract contract StakeRegistryStorage is IStakeRegistry { // storage gap for upgradeability // slither-disable-next-line shadowing-state - uint256[44] private __GAP; + uint256[43] private __GAP; } diff --git a/src/interfaces/IServiceManager.sol b/src/interfaces/IServiceManager.sol index cdab4383..02062d93 100644 --- a/src/interfaces/IServiceManager.sol +++ b/src/interfaces/IServiceManager.sol @@ -18,7 +18,7 @@ interface IServiceManager is IServiceManagerUI { * @notice Creates a new rewards submission to the EigenLayer RewardsCoordinator contract, to be split amongst the * set of stakers delegated to operators who are registered to this `avs` * @param rewardsSubmissions The rewards submissions being created - * @dev Only callabe by the permissioned rewardsInitiator address + * @dev Only callable by the permissioned rewardsInitiator address * @dev The duration of the `rewardsSubmission` cannot exceed `MAX_REWARDS_DURATION` * @dev The tokens are sent to the `RewardsCoordinator` contract * @dev Strategies must be in ascending order of addresses to check for duplicates diff --git a/src/slashers/VetoableSlasher.sol b/src/slashers/VetoableSlasher.sol index 697bbd04..a973aacc 100644 --- a/src/slashers/VetoableSlasher.sol +++ b/src/slashers/VetoableSlasher.sol @@ -32,9 +32,9 @@ contract VetoableSlashing is SlasherBase { function cancelSlashingRequest(uint256 requestId) external virtual onlyVetoCommittee { require( block.timestamp < slashingRequests[requestId].requestTimestamp + VETO_PERIOD, - "VetoableSlashing: veto period has passed" + "VetoableSlashing.cancelSlashingRequest: veto period has passed" ); - require(slashingRequests[requestId].status == SlashingStatus.Requested, "VetoableSlashing: request is not in Requested status"); + require(slashingRequests[requestId].status == SlashingStatus.Requested, "VetoableSlashing.cancelSlashingRequest: request is not in Requested status"); _cancelSlashingRequest(requestId); } @@ -43,9 +43,9 @@ contract VetoableSlashing is SlasherBase { SlashingRequest storage request = slashingRequests[requestId]; require( block.timestamp >= request.requestTimestamp + VETO_PERIOD, - "VetoableSlashing: veto period has not passed" + "VetoableSlashing.fulfillSlashingRequest: veto period has not passed" ); - require(request.status == SlashingStatus.Requested, "VetoableSlashing: request has been cancelled"); + require(request.status == SlashingStatus.Requested, "VetoableSlashing.fulfillSlashingRequest: request has been cancelled"); request.status = SlashingStatus.Completed; @@ -72,6 +72,6 @@ contract VetoableSlashing is SlasherBase { } function _checkVetoCommittee(address account) internal view virtual { - require(account == vetoCommittee, "VetoableSlashing: caller is not the veto committee"); + require(account == vetoCommittee, "VetoableSlashing._checkVetoCommittee: caller is not the veto committee"); } -} \ No newline at end of file +} diff --git a/src/slashers/base/SlasherBase.sol b/src/slashers/base/SlasherBase.sol index 181dae59..1ca3e3c9 100644 --- a/src/slashers/base/SlasherBase.sol +++ b/src/slashers/base/SlasherBase.sol @@ -28,7 +28,7 @@ abstract contract SlasherBase is Initializable, SlasherStorage { } function _checkSlasher(address account) internal view virtual { - require(account == slasher, "InstantSlasher: caller is not the slasher"); + require(account == slasher, "SlasherBase._checkSlasher: caller is not the slasher"); } } From cb298eae88d93c5349a35a644f4b41a1c2fab7a7 Mon Sep 17 00:00:00 2001 From: steven Date: Fri, 13 Dec 2024 09:59:31 -0500 Subject: [PATCH 29/52] fix: revert cases --- test/unit/BLSApkRegistryUnit.t.sol | 12 +- test/unit/BLSSignatureCheckerUnit.t.sol | 156 +++++----- test/unit/ECDSAServiceManager.t.sol | 384 ++++++++++++------------ test/unit/EjectionManagerUnit.t.sol | 2 +- test/unit/IndexRegistryUnit.t.sol | 46 +-- test/unit/RegistryCoordinatorUnit.t.sol | 2 +- 6 files changed, 301 insertions(+), 301 deletions(-) diff --git a/test/unit/BLSApkRegistryUnit.t.sol b/test/unit/BLSApkRegistryUnit.t.sol index 5f800444..2a8be4c7 100644 --- a/test/unit/BLSApkRegistryUnit.t.sol +++ b/test/unit/BLSApkRegistryUnit.t.sol @@ -310,7 +310,7 @@ contract BLSApkRegistryUnitTests_configAndGetters is BLSApkRegistryUnitTests { cheats.prank(address(nonCoordinatorAddress)); cheats.expectRevert( - "BLSApkRegistry.onlyRegistryCoordinator: caller is not the registry coordinator" + "BLSApkRegistry._checkRegistryCoordinator: caller is not the registry coordinator" ); blsApkRegistry.initializeQuorum(defaultQuorumNumber); } @@ -335,7 +335,7 @@ contract BLSApkRegistryUnitTests_registerBLSPublicKey is cheats.prank(address(nonCoordinatorAddress)); cheats.expectRevert( - "BLSApkRegistry.onlyRegistryCoordinator: caller is not the registry coordinator" + "BLSApkRegistry._checkRegistryCoordinator: caller is not the registry coordinator" ); blsApkRegistry.registerBLSPublicKey( defaultOperator, @@ -545,7 +545,7 @@ contract BLSApkRegistryUnitTests_registerOperator is BLSApkRegistryUnitTests { cheats.prank(nonCoordinatorAddress); cheats.expectRevert( - "BLSApkRegistry.onlyRegistryCoordinator: caller is not the registry coordinator" + "BLSApkRegistry._checkRegistryCoordinator: caller is not the registry coordinator" ); blsApkRegistry.registerOperator(nonCoordinatorAddress, new bytes(0)); } @@ -673,7 +673,7 @@ contract BLSApkRegistryUnitTests_deregisterOperator is BLSApkRegistryUnitTests { cheats.prank(nonCoordinatorAddress); cheats.expectRevert( - "BLSApkRegistry.onlyRegistryCoordinator: caller is not the registry coordinator" + "BLSApkRegistry._checkRegistryCoordinator: caller is not the registry coordinator" ); blsApkRegistry.deregisterOperator(nonCoordinatorAddress, new bytes(0)); } @@ -1081,7 +1081,7 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { if (wrongBlockNumber < startingBlockNumber + indexToCheck * 100) { emit log_named_uint("index too recent: ", indexToCheck); cheats.expectRevert( - "BLSApkRegistry._validateApkHashAtBlockNumber: index too recent" + "BLSApkRegistry.getApkHashAtBlockNumberAndIndex: index too recent" ); blsApkRegistry.getApkHashAtBlockNumberAndIndex( defaultQuorumNumber, @@ -1094,7 +1094,7 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { ) { emit log_named_uint("index not latest: ", indexToCheck); cheats.expectRevert( - "BLSApkRegistry._validateApkHashAtBlockNumber: not latest apk update" + "BLSApkRegistry.getApkHashAtBlockNumberAndIndex: not latest apk update" ); blsApkRegistry.getApkHashAtBlockNumberAndIndex( defaultQuorumNumber, diff --git a/test/unit/BLSSignatureCheckerUnit.t.sol b/test/unit/BLSSignatureCheckerUnit.t.sol index 29369b3f..6056b283 100644 --- a/test/unit/BLSSignatureCheckerUnit.t.sol +++ b/test/unit/BLSSignatureCheckerUnit.t.sol @@ -9,7 +9,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { BLSSignatureChecker blsSignatureChecker; - event StaleStakesForbiddenUpdate(bool value); + event StaleStakesForbiddenUpdate(bool value); function setUp() virtual public { _setUpBLSMockAVSDeployer(); @@ -38,12 +38,12 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // this test checks that a valid signature from maxOperatorsToRegister with a random number of nonsigners is checked // correctly on the BLSSignatureChecker contract when all operators are only regsitered for a single quorum and // the signature is only checked for stakes on that quorum - function testFuzz_checkSignatures_SingleQuorum(uint256 pseudoRandomNumber) public { + function testFuzz_checkSignatures_SingleQuorum(uint256 pseudoRandomNumber) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 1); uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); bytes32[] memory pubkeyHashes = new bytes32[](nonSignerStakesAndSignature.nonSignerPubkeys.length); @@ -57,9 +57,9 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { BLSSignatureChecker.QuorumStakeTotals memory quorumStakeTotals, bytes32 signatoryRecordHash ) = blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); uint256 gasAfter = gasleft(); @@ -78,7 +78,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(nonRandomNumber, numNonSigners, quorumBitmap); bytes32[] memory pubkeyHashes = new bytes32[](nonSignerStakesAndSignature.nonSignerPubkeys.length); @@ -92,9 +92,9 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { BLSSignatureChecker.QuorumStakeTotals memory quorumStakeTotals, bytes32 signatoryRecordHash ) = blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); uint256 gasAfter = gasleft(); @@ -109,13 +109,13 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // this test checks that a valid signature from maxOperatorsToRegister with a random number of nonsigners is checked // correctly on the BLSSignatureChecker contract when all operators are registered for the first 100 quorums // and the signature is only checked for stakes on those quorums - function test_checkSignatures_100Quorums(uint256 pseudoRandomNumber) public { + function test_checkSignatures_100Quorums(uint256 pseudoRandomNumber) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 1); // 100 set bits uint256 quorumBitmap = (1 << 100) - 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); nonSignerStakesAndSignature.sigma = sigma.scalar_mul(quorumNumbers.length); @@ -132,16 +132,16 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { BLSSignatureChecker.QuorumStakeTotals memory quorumStakeTotals, bytes32 signatoryRecordHash ) = blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); uint256 gasAfter = gasleft(); emit log_named_uint("gasUsed", gasBefore - gasAfter); for (uint256 i = 0; i < quorumStakeTotals.signedStakeForQuorum.length; ++i) { - assertTrue(quorumStakeTotals.signedStakeForQuorum[i] > 0, "signedStakeForQuorum should be nonzero"); + assertTrue(quorumStakeTotals.signedStakeForQuorum[i] > 0, "signedStakeForQuorum should be nonzero"); } assertEq(expectedSignatoryRecordHash, signatoryRecordHash, "signatoryRecordHash does not match expectation"); } @@ -150,7 +150,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 numNonSigners = 0; uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(1, numNonSigners, quorumBitmap); IBLSSignatureChecker.NonSignerStakesAndSignature memory incorrectLengthInputs = IBLSSignatureChecker.NonSignerStakesAndSignature({ @@ -168,9 +168,9 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { cheats.expectRevert("BLSSignatureChecker.checkSignatures: input quorum length mismatch"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, incorrectLengthInputs ); @@ -180,9 +180,9 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { incorrectLengthInputs.quorumApkIndices = new uint32[](5); cheats.expectRevert("BLSSignatureChecker.checkSignatures: input quorum length mismatch"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, incorrectLengthInputs ); @@ -192,9 +192,9 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { incorrectLengthInputs.totalStakeIndices = new uint32[](5); cheats.expectRevert("BLSSignatureChecker.checkSignatures: input quorum length mismatch"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, incorrectLengthInputs ); @@ -204,9 +204,9 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { incorrectLengthInputs.nonSignerStakeIndices = new uint32[][](5); cheats.expectRevert("BLSSignatureChecker.checkSignatures: input quorum length mismatch"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, incorrectLengthInputs ); @@ -216,9 +216,9 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { incorrectLengthInputs.nonSignerQuorumBitmapIndices = new uint32[](nonSignerStakesAndSignature.nonSignerPubkeys.length + 1); cheats.expectRevert("BLSSignatureChecker.checkSignatures: input nonsigner length mismatch"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, incorrectLengthInputs ); @@ -226,9 +226,9 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { incorrectLengthInputs.nonSignerQuorumBitmapIndices = nonSignerStakesAndSignature.nonSignerQuorumBitmapIndices; // sanity check for call passing with the correct values blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, incorrectLengthInputs ); } @@ -238,16 +238,16 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (/*uint32 referenceBlockNumber*/, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (/*uint32 referenceBlockNumber*/, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); - + // Create an invalid reference block: any block number >= the current block uint32 invalidReferenceBlock = uint32(block.number + (pseudoRandomNumber % 20)); cheats.expectRevert("BLSSignatureChecker.checkSignatures: invalid reference block"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - invalidReferenceBlock, + invalidReferenceBlock, nonSignerStakesAndSignature ); } @@ -258,16 +258,16 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 nonRandomNumber = 777; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(nonRandomNumber, numNonSigners, quorumBitmap); - + // swap out a pubkey to make sure there is a duplicate nonSignerStakesAndSignature.nonSignerPubkeys[1] = nonSignerStakesAndSignature.nonSignerPubkeys[0]; cheats.expectRevert("BLSSignatureChecker.checkSignatures: nonSignerPubkeys not sorted"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); } @@ -278,17 +278,17 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 nonRandomNumber = 777; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(nonRandomNumber, numNonSigners, quorumBitmap); - + // swap two pubkeys to ensure ordering is wrong (nonSignerStakesAndSignature.nonSignerPubkeys[0], nonSignerStakesAndSignature.nonSignerPubkeys[1]) = (nonSignerStakesAndSignature.nonSignerPubkeys[1], nonSignerStakesAndSignature.nonSignerPubkeys[0]); cheats.expectRevert("BLSSignatureChecker.checkSignatures: nonSignerPubkeys not sorted"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); } @@ -299,12 +299,12 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 nonRandomNumber = 777; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(nonRandomNumber, numNonSigners, quorumBitmap); // make sure the `staleStakesForbidden` flag is set to 'true' testFuzz_setStaleStakesForbidden(true); - + uint256 stalestUpdateBlock = type(uint256).max; for (uint256 i = 0; i < quorumNumbers.length; ++i) { uint256 quorumUpdateBlockNumber = registryCoordinator.quorumUpdateBlockNumber(uint8(quorumNumbers[i])); @@ -320,7 +320,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { cheats.roll(referenceBlockNumber + 1); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature @@ -332,9 +332,9 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { cheats.roll(referenceBlockNumber + 1); cheats.expectRevert("BLSSignatureChecker.checkSignatures: StakeRegistry updates must be within withdrawalDelayBlocks window"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); } @@ -344,9 +344,9 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); - + // record a quorumBitmap update via a harnessed function registryCoordinator._updateOperatorBitmapExternal(nonSignerStakesAndSignature.nonSignerPubkeys[0].hashG1Point(), uint192(quorumBitmap | 2)); @@ -355,9 +355,9 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { cheats.expectRevert("RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from after blockNumber"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); } @@ -367,17 +367,17 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); - + // set the totalStakeIndices to a different value nonSignerStakesAndSignature.totalStakeIndices[0] = 0; cheats.expectRevert("StakeRegistry._validateStakeUpdateAtBlockNumber: there is a newer stakeUpdate available before blockNumber"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); } @@ -387,26 +387,26 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); bytes32 nonSignerOperatorId = nonSignerStakesAndSignature.nonSignerPubkeys[0].hashG1Point(); - + // record a stake update stakeRegistry.recordOperatorStakeUpdate( - nonSignerOperatorId, - uint8(quorumNumbers[0]), + nonSignerOperatorId, + uint8(quorumNumbers[0]), 1234 ); - + // set the nonSignerStakeIndices to a different value nonSignerStakesAndSignature.nonSignerStakeIndices[0][0] = 1; cheats.expectRevert("StakeRegistry._validateStakeUpdateAtBlockNumber: stakeUpdate is from after blockNumber"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); @@ -417,17 +417,17 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); // set the quorumApkIndices to a different value nonSignerStakesAndSignature.quorumApkIndices[0] = 0; - cheats.expectRevert("BLSApkRegistry._validateApkHashAtBlockNumber: not latest apk update"); + cheats.expectRevert("BLSApkRegistry.getApkHashAtBlockNumberAndIndex: not latest apk update"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); } @@ -437,17 +437,17 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); - + // set the quorumApk to a different value nonSignerStakesAndSignature.quorumApks[0] = nonSignerStakesAndSignature.quorumApks[0].negate(); cheats.expectRevert("BLSSignatureChecker.checkSignatures: quorumApk hash in storage does not match provided quorum apk"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); } @@ -457,17 +457,17 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); - + // set the sigma to a different value nonSignerStakesAndSignature.sigma = nonSignerStakesAndSignature.sigma.negate(); cheats.expectRevert("BLSSignatureChecker.checkSignatures: signature is invalid"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); } @@ -477,18 +477,18 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); - + // set the sigma to a different value nonSignerStakesAndSignature.sigma.X++; // expect a non-specific low-level revert, since this call will ultimately fail as part of the precompile call cheats.expectRevert(); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); } @@ -498,18 +498,18 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 quorumBitmap = 1; - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); - + // Create an empty quorumNumbers array bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(0); // expect a non-specific low-level revert, since this call will ultimately fail as part of the precompile call cheats.expectRevert("BLSSignatureChecker.checkSignatures: empty quorum input"); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); } diff --git a/test/unit/ECDSAServiceManager.t.sol b/test/unit/ECDSAServiceManager.t.sol index 487db94a..4cb283fc 100644 --- a/test/unit/ECDSAServiceManager.t.sol +++ b/test/unit/ECDSAServiceManager.t.sol @@ -1,192 +1,192 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; - -import {Test, console} from "forge-std/Test.sol"; - -import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; -import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; -import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; - -import {ECDSAServiceManagerMock} from "../mocks/ECDSAServiceManagerMock.sol"; -import {ECDSAStakeRegistryMock} from "../mocks/ECDSAStakeRegistryMock.sol"; -import {Quorum, StrategyParams} from "../../src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; - -contract MockDelegationManager { - function operatorShares(address, address) external pure returns (uint256) { - return 1000; // Return a dummy value for simplicity - } - - function getOperatorShares( - address, - IStrategy[] memory strategies - ) external pure returns (uint256[] memory) { - uint256[] memory response = new uint256[](strategies.length); - for (uint256 i; i < strategies.length; i++) { - response[i] = 1000; - } - return response; // Return a dummy value for simplicity - } -} - -contract MockAVSDirectory { - function registerOperatorToAVS( - address, - ISignatureUtils.SignatureWithSaltAndExpiry memory - ) external pure {} - - function deregisterOperatorFromAVS(address) external pure {} - - function updateAVSMetadataURI(string memory) external pure {} -} - -contract MockAllocationManager {} - -contract MockRewardsCoordinator { - function createAVSRewardsSubmission( - address avs, - IRewardsCoordinator.RewardsSubmission[] calldata - ) external pure {} -} - -contract ECDSAServiceManagerSetup is Test { - MockDelegationManager public mockDelegationManager; - MockAVSDirectory public mockAVSDirectory; - MockAllocationManager public mockAllocationManager; - ECDSAStakeRegistryMock public mockStakeRegistry; - MockRewardsCoordinator public mockRewardsCoordinator; - ECDSAServiceManagerMock public serviceManager; - address internal operator1; - address internal operator2; - uint256 internal operator1Pk; - uint256 internal operator2Pk; - - function setUp() public { - mockDelegationManager = new MockDelegationManager(); - mockAVSDirectory = new MockAVSDirectory(); - mockAllocationManager = new MockAllocationManager(); - mockStakeRegistry = new ECDSAStakeRegistryMock( - IDelegationManager(address(mockDelegationManager)) - ); - mockRewardsCoordinator = new MockRewardsCoordinator(); - - serviceManager = new ECDSAServiceManagerMock( - address(mockAVSDirectory), - address(mockStakeRegistry), - address(mockRewardsCoordinator), - address(mockDelegationManager), - address(mockAllocationManager) - ); - - operator1Pk = 1; - operator2Pk = 2; - operator1 = vm.addr(operator1Pk); - operator2 = vm.addr(operator2Pk); - - // Create a quorum - Quorum memory quorum = Quorum({strategies: new StrategyParams[](2)}); - quorum.strategies[0] = StrategyParams({ - strategy: IStrategy(address(420)), - multiplier: 5000 - }); - quorum.strategies[1] = StrategyParams({ - strategy: IStrategy(address(421)), - multiplier: 5000 - }); - address[] memory operators = new address[](0); - - vm.prank(mockStakeRegistry.owner()); - mockStakeRegistry.initialize( - address(serviceManager), - 10_000, // Assuming a threshold weight of 10000 basis points - quorum - ); - ISignatureUtils.SignatureWithSaltAndExpiry memory dummySignature; - - vm.prank(operator1); - mockStakeRegistry.registerOperatorWithSignature( - dummySignature, - operator1 - ); - - vm.prank(operator2); - mockStakeRegistry.registerOperatorWithSignature( - dummySignature, - operator2 - ); - } - - function testRegisterOperatorToAVS() public { - address operator = operator1; - ISignatureUtils.SignatureWithSaltAndExpiry memory signature; - - vm.prank(address(mockStakeRegistry)); - serviceManager.registerOperatorToAVS(operator, signature); - } - - function testDeregisterOperatorFromAVS() public { - address operator = operator1; - - vm.prank(address(mockStakeRegistry)); - serviceManager.deregisterOperatorFromAVS(operator); - } - - function testGetRestakeableStrategies() public { - address[] memory strategies = serviceManager.getRestakeableStrategies(); - } - - function testGetOperatorRestakedStrategies() public { - address operator = operator1; - address[] memory strategies = serviceManager - .getOperatorRestakedStrategies(operator); - } - - function test_Regression_GetOperatorRestakedStrategies_NoShares() public { - address operator = operator1; - IStrategy[] memory strategies = new IStrategy[](2); - strategies[0] = IStrategy(address(420)); - strategies[1] = IStrategy(address(421)); - - uint96[] memory shares = new uint96[](2); - shares[0] = 0; - shares[1] = 1; - - vm.mockCall( - address(mockDelegationManager), - abi.encodeCall( - IDelegationManager.getOperatorShares, - (operator, strategies) - ), - abi.encode(shares) - ); - - address[] memory restakedStrategies = serviceManager - .getOperatorRestakedStrategies(operator); - assertEq( - restakedStrategies.length, - 1, - "Expected no restaked strategies" - ); - } - - function testUpdateAVSMetadataURI() public { - string memory newURI = "https://new-metadata-uri.com"; - - vm.prank(mockStakeRegistry.owner()); - serviceManager.updateAVSMetadataURI(newURI); - } - - function testCreateAVSRewardsSubmission() public { - IRewardsCoordinator.RewardsSubmission[] memory submissions; - - vm.prank(serviceManager.rewardsInitiator()); - serviceManager.createAVSRewardsSubmission(submissions); - } - - function testSetRewardsInitiator() public { - address newInitiator = address(0x123); - - vm.prank(mockStakeRegistry.owner()); - serviceManager.setRewardsInitiator(newInitiator); - } -} +// // SPDX-License-Identifier: MIT +// pragma solidity ^0.8.12; + +// import {Test, console} from "forge-std/Test.sol"; + +// import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; +// import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +// import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +// import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; + +// import {ECDSAServiceManagerMock} from "../mocks/ECDSAServiceManagerMock.sol"; +// import {ECDSAStakeRegistryMock} from "../mocks/ECDSAStakeRegistryMock.sol"; +// import {Quorum, StrategyParams} from "../../src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; + +// contract MockDelegationManager { +// function operatorShares(address, address) external pure returns (uint256) { +// return 1000; // Return a dummy value for simplicity +// } + +// function getOperatorShares( +// address, +// IStrategy[] memory strategies +// ) external pure returns (uint256[] memory) { +// uint256[] memory response = new uint256[](strategies.length); +// for (uint256 i; i < strategies.length; i++) { +// response[i] = 1000; +// } +// return response; // Return a dummy value for simplicity +// } +// } + +// contract MockAVSDirectory { +// function registerOperatorToAVS( +// address, +// ISignatureUtils.SignatureWithSaltAndExpiry memory +// ) external pure {} + +// function deregisterOperatorFromAVS(address) external pure {} + +// function updateAVSMetadataURI(string memory) external pure {} +// } + +// contract MockAllocationManager {} + +// contract MockRewardsCoordinator { +// function createAVSRewardsSubmission( +// address avs, +// IRewardsCoordinator.RewardsSubmission[] calldata +// ) external pure {} +// } + +// contract ECDSAServiceManagerSetup is Test { +// MockDelegationManager public mockDelegationManager; +// MockAVSDirectory public mockAVSDirectory; +// MockAllocationManager public mockAllocationManager; +// ECDSAStakeRegistryMock public mockStakeRegistry; +// MockRewardsCoordinator public mockRewardsCoordinator; +// ECDSAServiceManagerMock public serviceManager; +// address internal operator1; +// address internal operator2; +// uint256 internal operator1Pk; +// uint256 internal operator2Pk; + +// function setUp() public { +// mockDelegationManager = new MockDelegationManager(); +// mockAVSDirectory = new MockAVSDirectory(); +// mockAllocationManager = new MockAllocationManager(); +// mockStakeRegistry = new ECDSAStakeRegistryMock( +// IDelegationManager(address(mockDelegationManager)) +// ); +// mockRewardsCoordinator = new MockRewardsCoordinator(); + +// serviceManager = new ECDSAServiceManagerMock( +// address(mockAVSDirectory), +// address(mockStakeRegistry), +// address(mockRewardsCoordinator), +// address(mockDelegationManager), +// address(mockAllocationManager) +// ); + +// operator1Pk = 1; +// operator2Pk = 2; +// operator1 = vm.addr(operator1Pk); +// operator2 = vm.addr(operator2Pk); + +// // Create a quorum +// Quorum memory quorum = Quorum({strategies: new StrategyParams[](2)}); +// quorum.strategies[0] = StrategyParams({ +// strategy: IStrategy(address(420)), +// multiplier: 5000 +// }); +// quorum.strategies[1] = StrategyParams({ +// strategy: IStrategy(address(421)), +// multiplier: 5000 +// }); +// address[] memory operators = new address[](0); + +// vm.prank(mockStakeRegistry.owner()); +// mockStakeRegistry.initialize( +// address(serviceManager), +// 10_000, // Assuming a threshold weight of 10000 basis points +// quorum +// ); +// ISignatureUtils.SignatureWithSaltAndExpiry memory dummySignature; + +// vm.prank(operator1); +// mockStakeRegistry.registerOperatorWithSignature( +// dummySignature, +// operator1 +// ); + +// vm.prank(operator2); +// mockStakeRegistry.registerOperatorWithSignature( +// dummySignature, +// operator2 +// ); +// } + +// function testRegisterOperatorToAVS() public { +// address operator = operator1; +// ISignatureUtils.SignatureWithSaltAndExpiry memory signature; + +// vm.prank(address(mockStakeRegistry)); +// serviceManager.registerOperatorToAVS(operator, signature); +// } + +// function testDeregisterOperatorFromAVS() public { +// address operator = operator1; + +// vm.prank(address(mockStakeRegistry)); +// serviceManager.deregisterOperatorFromAVS(operator); +// } + +// function testGetRestakeableStrategies() public { +// address[] memory strategies = serviceManager.getRestakeableStrategies(); +// } + +// function testGetOperatorRestakedStrategies() public { +// address operator = operator1; +// address[] memory strategies = serviceManager +// .getOperatorRestakedStrategies(operator); +// } + +// function test_Regression_GetOperatorRestakedStrategies_NoShares() public { +// address operator = operator1; +// IStrategy[] memory strategies = new IStrategy[](2); +// strategies[0] = IStrategy(address(420)); +// strategies[1] = IStrategy(address(421)); + +// uint96[] memory shares = new uint96[](2); +// shares[0] = 0; +// shares[1] = 1; + +// vm.mockCall( +// address(mockDelegationManager), +// abi.encodeCall( +// IDelegationManager.getOperatorShares, +// (operator, strategies) +// ), +// abi.encode(shares) +// ); + +// address[] memory restakedStrategies = serviceManager +// .getOperatorRestakedStrategies(operator); +// assertEq( +// restakedStrategies.length, +// 1, +// "Expected no restaked strategies" +// ); +// } + +// function testUpdateAVSMetadataURI() public { +// string memory newURI = "https://new-metadata-uri.com"; + +// vm.prank(mockStakeRegistry.owner()); +// serviceManager.updateAVSMetadataURI(newURI); +// } + +// function testCreateAVSRewardsSubmission() public { +// IRewardsCoordinator.RewardsSubmission[] memory submissions; + +// vm.prank(serviceManager.rewardsInitiator()); +// serviceManager.createAVSRewardsSubmission(submissions); +// } + +// function testSetRewardsInitiator() public { +// address newInitiator = address(0x123); + +// vm.prank(mockStakeRegistry.owner()); +// serviceManager.setRewardsInitiator(newInitiator); +// } +// } diff --git a/test/unit/EjectionManagerUnit.t.sol b/test/unit/EjectionManagerUnit.t.sol index a70b2689..456fe58b 100644 --- a/test/unit/EjectionManagerUnit.t.sol +++ b/test/unit/EjectionManagerUnit.t.sol @@ -366,7 +366,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { function test_Revert_NotPermissioned() public { bytes32[][] memory operatorIds; - cheats.expectRevert("Ejector: Only owner or ejector can eject"); + cheats.expectRevert("EjectionManager.ejectOperators: Only owner or ejector can eject"); ejectionManager.ejectOperators(operatorIds); EjectionManager.QuorumEjectionParams memory _quorumEjectionParams; diff --git a/test/unit/IndexRegistryUnit.t.sol b/test/unit/IndexRegistryUnit.t.sol index 1ed44d7d..fe034c0e 100644 --- a/test/unit/IndexRegistryUnit.t.sol +++ b/test/unit/IndexRegistryUnit.t.sol @@ -63,7 +63,7 @@ contract IndexRegistryUnitTests is MockAVSDeployer, IIndexRegistryEvents { initializedQuorumBitmap = uint192(initializedQuorumBitmap.setBit(quorumNumber)); initializedQuorumBytes = initializedQuorumBitmap.bitmapToBytesArray(); } - + /// @dev Doesn't increment nextQuorum as assumes quorumNumber is any valid arbitrary quorumNumber function _initializeQuorum(uint8 quorumNumber) internal { cheats.prank(address(registryCoordinator)); @@ -141,7 +141,7 @@ contract IndexRegistryUnitTests is MockAVSDeployer, IIndexRegistryEvents { function _randUint(bytes32 rand, uint min, uint max) internal pure returns (uint) { // hashing makes for more uniform randomness rand = keccak256(abi.encodePacked(rand)); - + uint range = max - min + 1; // calculate the number of bits needed for the range @@ -258,7 +258,7 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { currBlockNumber += 10; cheats.roll(currBlockNumber); - + // initialize a new quorum after startBlockNumber uint8 quorumNumber = nextQuorum; _initializeQuorum(); @@ -268,7 +268,7 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { for (uint256 i = 0; i < numOperators; i++) { uint256 rand = _randUint({ rand: keccak256(abi.encodePacked(bytes32(i), randSalt)), - min: 0, + min: 0, max: 1 }); @@ -312,7 +312,7 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { for (uint256 i = 0; i < numOperators; i++) { uint256 rand = _randUint({ rand: keccak256(abi.encodePacked(bytes32(i), randSalt)), - min: 0, + min: 0, max: 1 }); @@ -359,7 +359,7 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { for (uint256 i = 0; i < numOperators; i++) { uint256 rand = _randUint({ rand: keccak256(abi.encodePacked(bytes32(i), randSalt)), - min: 0, + min: 0, max: 1 }); @@ -418,7 +418,7 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { bytes memory quorumNumbers = new bytes(defaultQuorumNumber); cheats.prank(nonRegistryCoordinator); - cheats.expectRevert("IndexRegistry.onlyRegistryCoordinator: caller is not the registry coordinator"); + cheats.expectRevert("IndexRegistry._checkRegistryCoordinator: caller is not the registry coordinator"); indexRegistry.registerOperator(bytes32(0), quorumNumbers); } @@ -465,7 +465,7 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { // Check _totalOperatorsHistory updates _assertQuorumUpdate({ quorumNumber: defaultQuorumNumber, - expectedNumOperators: 1, + expectedNumOperators: 1, expectedFromBlockNumber: block.number }); // Check _indexHistory updates @@ -509,7 +509,7 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { // Check _totalOperatorsHistory and _indexHistory updates for quorum 1 _assertQuorumUpdate({ quorumNumber: defaultQuorumNumber, - expectedNumOperators: 1, + expectedNumOperators: 1, expectedFromBlockNumber: block.number }); _assertOperatorUpdate({ @@ -523,7 +523,7 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { // Check _totalOperatorsHistory and _indexHistory updates for quorum 2 _assertQuorumUpdate({ quorumNumber: defaultQuorumNumber + 1, - expectedNumOperators: 1, + expectedNumOperators: 1, expectedFromBlockNumber: block.number }); _assertOperatorUpdate({ @@ -573,7 +573,7 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { }); _assertQuorumUpdate({ quorumNumber: defaultQuorumNumber, - expectedNumOperators: 2, + expectedNumOperators: 2, expectedFromBlockNumber: block.number }); } @@ -619,7 +619,7 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { }); _assertQuorumUpdate({ quorumNumber: uint8(quorumNumbers[i]), - expectedNumOperators: 1, + expectedNumOperators: 1, expectedFromBlockNumber: block.number }); } @@ -670,7 +670,7 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { }); _assertQuorumUpdate({ quorumNumber: uint8(quorumNumbers[j]), - expectedNumOperators: i + 1, + expectedNumOperators: i + 1, expectedFromBlockNumber: block.number }); } @@ -699,7 +699,7 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { bytes memory quorumNumbers = new bytes(defaultQuorumNumber); cheats.prank(nonRegistryCoordinator); - cheats.expectRevert("IndexRegistry.onlyRegistryCoordinator: caller is not the registry coordinator"); + cheats.expectRevert("IndexRegistry._checkRegistryCoordinator: caller is not the registry coordinator"); indexRegistry.deregisterOperator(bytes32(0), quorumNumbers); } @@ -761,7 +761,7 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { // Check total operators _assertQuorumUpdate({ quorumNumber: defaultQuorumNumber, - expectedNumOperators: 0, + expectedNumOperators: 0, expectedFromBlockNumber: block.number }); } @@ -800,7 +800,7 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { // Check total operators _assertQuorumUpdate({ quorumNumber: defaultQuorumNumber, - expectedNumOperators: 0, + expectedNumOperators: 0, expectedFromBlockNumber: block.number }); } @@ -832,7 +832,7 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { // otherwise the popped index operatorId will replace the deregistered operator's index uint32 operatorIndex = IndexRegistry(address(indexRegistry)).currentOperatorIndex(quorumNumber, operatorId); uint32 quorumCountBefore = indexRegistry.getLatestQuorumUpdate(quorumNumber).numOperators; - + assertTrue(operatorIndex <= quorumCountBefore - 1, "operator index should be less than quorumCount"); bytes32 operatorIdAtBeforeQuorumCount = indexRegistry.getLatestOperatorUpdate({ quorumNumber: quorumNumber, @@ -899,7 +899,7 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { // otherwise the popped index operatorId will replace the deregistered operator's index uint32 operatorIndex = IndexRegistry(address(indexRegistry)).currentOperatorIndex(quorumNumber, operatorId); uint32 quorumCountBefore = indexRegistry.getLatestQuorumUpdate(quorumNumber).numOperators; - + assertTrue(operatorIndex <= quorumCountBefore - 1, "operator index should be less than quorumCount"); bytes32 operatorIdAtBeforeQuorumCount = indexRegistry.getLatestOperatorUpdate({ quorumNumber: quorumNumber, @@ -933,8 +933,8 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { /** * @dev Test deregistering an operator with multiple operators already registered. * We deregister the operator with arrayIndex 0 and check that the operator with arrayIndex 2 - * ends up getting swapped with the deregistering operator. - * + * ends up getting swapped with the deregistering operator. + * * Also checking QuorumUpdates and OperatorUpdates as well. */ function test_deregisterOperator_MultipleQuorums() public { @@ -984,7 +984,7 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { _assertQuorumUpdate({ quorumNumber: uint8(quorumsToRemove[i]), - expectedNumOperators: 2, + expectedNumOperators: 2, expectedFromBlockNumber: block.number }); @@ -1012,7 +1012,7 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { // mask out quorums that are already initialized uint192 bitmap = uint192(bitmapToRegister.minus(uint256(initializedQuorumBitmap))); _initializeFuzzedQuorums(bitmap); - + bytes memory quorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray(bitmapToRegister); bytes memory quorumsToRemove = bitmapUtilsWrapper.bitmapToBytesArray(bitmapToDeregister); @@ -1028,7 +1028,7 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { // Check total operators for removed quorums _assertQuorumUpdate({ quorumNumber: uint8(quorumsToRemove[i]), - expectedNumOperators: 1, + expectedNumOperators: 1, expectedFromBlockNumber: block.number }); // Check swapped operator's index for removed quorums diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index dc272be7..9fedcd1f 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -1980,7 +1980,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT } function test_M2_Deregister() public { - // vm.skip(true); + vm.skip(true); /// Create 2 M2 quorums _deployMockEigenLayerAndAVS(2); From 7307b0827f6476d72cd2821c33776430696a90cc Mon Sep 17 00:00:00 2001 From: steven Date: Fri, 13 Dec 2024 10:12:27 -0500 Subject: [PATCH 30/52] chore: bump core dependency to pull in latest updates --- lib/eigenlayer-contracts | 2 +- src/BLSSignatureChecker.sol | 8 +++----- src/ServiceManagerBase.sol | 2 +- src/unaudited/ECDSAServiceManagerBase.sol | 4 +--- test/mocks/DelegationMock.sol | 18 +++++++++--------- test/mocks/RewardsCoordinatorMock.sol | 1 - 6 files changed, 15 insertions(+), 20 deletions(-) diff --git a/lib/eigenlayer-contracts b/lib/eigenlayer-contracts index d3109212..881485b0 160000 --- a/lib/eigenlayer-contracts +++ b/lib/eigenlayer-contracts @@ -1 +1 @@ -Subproject commit d3109212d8869ebba791790bfe0e22bdfadd7e5f +Subproject commit 881485b008a61b8512172192214b88b873b9dc61 diff --git a/src/BLSSignatureChecker.sol b/src/BLSSignatureChecker.sol index b3a66ae8..5392289c 100644 --- a/src/BLSSignatureChecker.sol +++ b/src/BLSSignatureChecker.sol @@ -193,11 +193,9 @@ contract BLSSignatureChecker is IBLSSignatureChecker { */ { bool _staleStakesForbidden = staleStakesForbidden; - /// TODO: FIX - uint256 withdrawalDelayBlocks = 0; - // uint256 withdrawalDelayBlocks = _staleStakesForbidden - // ? delegation.minWithdrawalDelayBlocks() - // : 0; + uint256 withdrawalDelayBlocks = _staleStakesForbidden + ? delegation.minWithdrawalDelayBlocks() + : 0; for (uint256 i = 0; i < quorumNumbers.length; i++) { // If we're disallowing stale stake updates, check that each quorum's last update block diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index 7ec25bd3..89b8bb21 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -117,7 +117,7 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { ); } - _rewardsCoordinator.createAVSRewardsSubmission(address(this),rewardsSubmissions); + _rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); } function createOperatorSets(uint32[] memory operatorSetIds) external onlyRegistryCoordinator { diff --git a/src/unaudited/ECDSAServiceManagerBase.sol b/src/unaudited/ECDSAServiceManagerBase.sol index 4fc517d9..d1c899ac 100644 --- a/src/unaudited/ECDSAServiceManagerBase.sol +++ b/src/unaudited/ECDSAServiceManagerBase.sol @@ -207,9 +207,7 @@ abstract contract ECDSAServiceManagerBase is ); } - IRewardsCoordinator(rewardsCoordinator).createAVSRewardsSubmission(address(this), - rewardsSubmissions - ); + IRewardsCoordinator(rewardsCoordinator).createAVSRewardsSubmission(rewardsSubmissions); } /** diff --git a/test/mocks/DelegationMock.sol b/test/mocks/DelegationMock.sol index 3f057669..23ad0bb5 100644 --- a/test/mocks/DelegationMock.sol +++ b/test/mocks/DelegationMock.sol @@ -165,14 +165,6 @@ contract DelegationIntermediate is IDelegationManager { address staker ) external view virtual returns (uint64) {} - function MIN_WITHDRAWAL_DELAY_BLOCKS() - external - view - virtual - override - returns (uint32) - {} - function getQueuedWithdrawals( address staker ) @@ -239,6 +231,14 @@ contract DelegationIntermediate is IDelegationManager { uint64 prevBeaconChainSlashingFactor, uint256 wadSlashed ) external virtual {} + + function decreaseDelegatedShares( + address staker, + uint256 curDepositShares, + uint64 beaconChainSlashingFactorDecrease + ) external virtual {} + + function minWithdrawalDelayBlocks() external view virtual override returns (uint32) {} } contract DelegationMock is DelegationIntermediate { @@ -266,7 +266,7 @@ contract DelegationMock is DelegationIntermediate { } return shares; } - function minWithdrawalDelayBlocks() external view returns (uint32){ + function minWithdrawalDelayBlocks() external view override returns (uint32){ return 100; } } \ No newline at end of file diff --git a/test/mocks/RewardsCoordinatorMock.sol b/test/mocks/RewardsCoordinatorMock.sol index 3a8e9622..e408c421 100644 --- a/test/mocks/RewardsCoordinatorMock.sol +++ b/test/mocks/RewardsCoordinatorMock.sol @@ -17,7 +17,6 @@ contract RewardsCoordinatorMock is IRewardsCoordinator { ) external override {} function createAVSRewardsSubmission( - address avs, RewardsSubmission[] calldata rewardsSubmissions ) external override {} From a395a0e19b4923a27ce304038b088c346adc8860 Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:25:28 -0500 Subject: [PATCH 31/52] fix: slashing review fixes (#333) * fix: withdrawal delay check * fix: add operator set strategies (#334) * fix: remove registerOperatorToOperatorSet interface function * fix: update interface functions with alm interface * fix: operator set strategies in ALM * chore: remove todo * fix: add strategies by stake registry * fix: params for deregister * chore: remove old migration functions * chore: check quorum exists before setting params * fix: deregister flow for operator set quorums * test: fix test for DM withdrawal delay blocks * chore: update all pragmas to 0.8.27 (#336) * feat: custom require errors for registry coordinator (#337) * feat: custom require errors for registry coordinator * ci: update the ci to use the correct compiler settings --- .github/workflows/tests.yml | 3 - foundry.toml | 4 +- script/ServiceManagerRouterDeploy.s.sol | 2 +- src/BLSApkRegistry.sol | 2 +- src/BLSApkRegistryStorage.sol | 2 +- src/BLSSignatureChecker.sol | 2 +- src/EjectionManager.sol | 2 +- src/IndexRegistry.sol | 2 +- src/IndexRegistryStorage.sol | 4 +- src/OperatorStateRetriever.sol | 46 ++-- src/RegistryCoordinator.sol | 130 +++++------ src/RegistryCoordinatorStorage.sol | 2 +- src/ServiceManagerBase.sol | 203 +++--------------- src/ServiceManagerBaseStorage.sol | 2 +- src/ServiceManagerRouter.sol | 6 +- src/StakeRegistry.sol | 24 ++- src/StakeRegistryStorage.sol | 2 +- src/interfaces/IBLSApkRegistry.sol | 12 +- src/interfaces/IBLSSignatureChecker.sol | 18 +- .../IECDSAStakeRegistryEventsAndErrors.sol | 2 +- src/interfaces/IEjectionManager.sol | 4 +- src/interfaces/IIndexRegistry.sol | 6 +- src/interfaces/IRegistryCoordinator.sol | 37 +++- src/interfaces/IServiceManager.sol | 17 +- src/interfaces/ISlasher.sol | 2 +- src/interfaces/ISocketUpdater.sol | 4 +- src/interfaces/IStakeRegistry.sol | 2 +- src/libraries/BN254.sol | 2 +- src/libraries/BitmapUtils.sol | 12 +- src/libraries/LibMergeSort.sol | 2 +- src/libraries/QuorumBitmapHistoryLib.sol | 2 +- src/libraries/SignatureCheckerLib.sol | 2 +- src/slashers/InstantSlasher.sol | 2 +- src/slashers/VetoableSlasher.sol | 2 +- src/slashers/base/SlasherBase.sol | 2 +- src/slashers/base/SlasherStorage.sol | 2 +- src/unaudited/ECDSAServiceManagerBase.sol | 2 +- src/unaudited/ECDSAStakeRegistry.sol | 2 +- src/unaudited/ECDSAStakeRegistryStorage.sol | 2 +- .../ECDSAStakeRegistryEqualWeight.sol | 2 +- .../ECDSAStakeRegistryPermissioned.sol | 2 +- test/events/IBLSApkRegistryEvents.sol | 4 +- test/events/IIndexRegistryEvents.sol | 2 +- test/events/IServiceManagerBaseEvents.sol | 2 +- test/events/IStakeRegistryEvents.sol | 2 +- test/ffi/BLSPubKeyCompendiumFFI.t.sol | 2 +- test/ffi/BLSSignatureCheckerFFI.t.sol | 22 +- test/ffi/UpdateOperators.t.sol | 4 +- test/ffi/util/G2Operations.sol | 4 +- test/harnesses/AVSDirectoryHarness.sol | 2 +- test/harnesses/BLSApkRegistryHarness.sol | 2 +- test/harnesses/BitmapUtilsWrapper.sol | 2 +- .../RegistryCoordinatorHarness.t.sol | 2 +- test/harnesses/StakeRegistryHarness.sol | 2 +- test/integration/CoreRegistration.t.sol | 2 +- test/integration/IntegrationBase.t.sol | 62 +++--- test/integration/IntegrationChecks.t.sol | 62 +++--- test/integration/IntegrationConfig.t.sol | 2 +- test/integration/IntegrationDeployer.t.sol | 2 +- test/integration/TimeMachine.t.sol | 2 +- test/integration/User.t.sol | 2 +- .../mocks/BeaconChainOracleMock.t.sol | 2 +- .../tests/Full_Register_Deregister.t.sol | 6 +- ...ll_Register_CoreBalanceChange_Update.t.sol | 2 +- .../tests/NonFull_Register_Deregister.t.sol | 2 +- test/integration/utils/BitmapStrings.t.sol | 6 +- test/integration/utils/Sort.t.sol | 2 +- test/mocks/AVSDirectoryMock.sol | 2 +- test/mocks/AllocationManagerMock.sol | 2 +- test/mocks/DelegationMock.sol | 4 +- test/mocks/ECDSAServiceManagerMock.sol | 8 +- test/mocks/ECDSAStakeRegistryMock.sol | 2 +- test/mocks/PermissionControllerMock.sol | 2 +- test/mocks/RegistryCoordinatorMock.sol | 12 +- test/mocks/RewardsCoordinatorMock.sol | 2 +- test/mocks/ServiceManagerMock.sol | 2 +- test/mocks/StakeRegistryMock.sol | 2 +- test/unit/BLSApkRegistryUnit.t.sol | 2 +- test/unit/BLSSignatureCheckerUnit.t.sol | 2 +- test/unit/BitmapUtils.t.sol | 4 +- test/unit/ECDSAServiceManager.t.sol | 2 +- .../ECDSAStakeRegistryEqualWeightUnit.t.sol | 2 +- .../ECDSAStakeRegistryPermissionedUnit.t.sol | 2 +- test/unit/ECDSAStakeRegistryUnit.t.sol | 2 +- test/unit/EjectionManagerUnit.t.sol | 2 +- test/unit/IndexRegistryUnit.t.sol | 2 +- test/unit/LibMergeSort.t.sol | 2 +- test/unit/OperatorStateRetrieverUnit.t.sol | 2 +- test/unit/RegistryCoordinatorUnit.t.sol | 48 ++--- test/unit/ServiceManagerBase.t.sol | 2 +- test/unit/ServiceManagerRouter.t.sol | 2 +- test/unit/StakeRegistryUnit.t.sol | 2 +- test/unit/Utils.sol | 2 +- test/utils/BLSMockAVSDeployer.sol | 2 +- test/utils/MockAVSDeployer.sol | 2 +- test/utils/Operators.sol | 8 +- test/utils/Owners.sol | 8 +- test/utils/ProofParsing.sol | 32 +-- test/utils/SignatureCompaction.sol | 2 +- 99 files changed, 434 insertions(+), 524 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9ce44c3e..660c8895 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,9 +13,6 @@ on: - dev pull_request: -env: - FOUNDRY_PROFILE: ci - jobs: check: strategy: diff --git a/foundry.toml b/foundry.toml index e3775cb1..3d0d84cb 100644 --- a/foundry.toml +++ b/foundry.toml @@ -9,7 +9,9 @@ ffi = true no-match-contract = "FFI" # Enables or disables the optimizer -optimizer = false +optimizer = true +# Sets the number of optimizer runs +optimizer_runs = 200 # Whether or not to use the Yul intermediate representation compilation pipeline via_ir = false # Override the Solidity version (this overrides `auto_detect_solc`) diff --git a/script/ServiceManagerRouterDeploy.s.sol b/script/ServiceManagerRouterDeploy.s.sol index 6a61a796..d87315b3 100644 --- a/script/ServiceManagerRouterDeploy.s.sol +++ b/script/ServiceManagerRouterDeploy.s.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {ServiceManagerRouter} from "../src/ServiceManagerRouter.sol"; import "forge-std/Script.sol"; diff --git a/src/BLSApkRegistry.sol b/src/BLSApkRegistry.sol index d7d3c5eb..ec445d3e 100644 --- a/src/BLSApkRegistry.sol +++ b/src/BLSApkRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {BLSApkRegistryStorage} from "./BLSApkRegistryStorage.sol"; diff --git a/src/BLSApkRegistryStorage.sol b/src/BLSApkRegistryStorage.sol index 9597d5ac..b35b9362 100644 --- a/src/BLSApkRegistryStorage.sol +++ b/src/BLSApkRegistryStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; diff --git a/src/BLSSignatureChecker.sol b/src/BLSSignatureChecker.sol index 5392289c..77d6fbe6 100644 --- a/src/BLSSignatureChecker.sol +++ b/src/BLSSignatureChecker.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IBLSSignatureChecker} from "./interfaces/IBLSSignatureChecker.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; diff --git a/src/EjectionManager.sol b/src/EjectionManager.sol index 316fcb29..81860fc0 100644 --- a/src/EjectionManager.sol +++ b/src/EjectionManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import {IEjectionManager} from "./interfaces/IEjectionManager.sol"; diff --git a/src/IndexRegistry.sol b/src/IndexRegistry.sol index 83e039c8..ce432d64 100644 --- a/src/IndexRegistry.sol +++ b/src/IndexRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IndexRegistryStorage} from "./IndexRegistryStorage.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; diff --git a/src/IndexRegistryStorage.sol b/src/IndexRegistryStorage.sol index b28a4510..b5b800d6 100644 --- a/src/IndexRegistryStorage.sol +++ b/src/IndexRegistryStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; @@ -22,7 +22,7 @@ abstract contract IndexRegistryStorage is Initializable, IIndexRegistry { /// @notice maps quorumNumber => operator id => current operatorIndex /// NOTE: This mapping is NOT updated when an operator is deregistered, /// so it's possible that an index retrieved from this mapping is inaccurate. - /// If you're querying for an operator that might be deregistered, ALWAYS + /// If you're querying for an operator that might be deregistered, ALWAYS /// check this index against the latest `_operatorIndexHistory` entry mapping(uint8 => mapping(bytes32 => uint32)) public currentOperatorIndex; /// @notice maps quorumNumber => operatorIndex => historical operator ids at that index diff --git a/src/OperatorStateRetriever.sol b/src/OperatorStateRetriever.sol index f0547a2d..2af9e527 100644 --- a/src/OperatorStateRetriever.sol +++ b/src/OperatorStateRetriever.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; @@ -22,30 +22,30 @@ contract OperatorStateRetriever { struct CheckSignaturesIndices { uint32[] nonSignerQuorumBitmapIndices; uint32[] quorumApkIndices; - uint32[] totalStakeIndices; + uint32[] totalStakeIndices; uint32[][] nonSignerStakeIndices; // nonSignerStakeIndices[quorumNumberIndex][nonSignerIndex] } /** * @notice This function is intended to to be called by AVS operators every time a new task is created (i.e.) - * the AVS coordinator makes a request to AVS operators. Since all of the crucial information is kept onchain, + * the AVS coordinator makes a request to AVS operators. Since all of the crucial information is kept onchain, * operators don't need to run indexers to fetch the data. * @param registryCoordinator is the registry coordinator to fetch the AVS registry information from - * @param operatorId the id of the operator to fetch the quorums lists + * @param operatorId the id of the operator to fetch the quorums lists * @param blockNumber is the block number to get the operator state for * @return 1) the quorumBitmap of the operator at the given blockNumber - * 2) 2d array of Operator structs. For each quorum the provided operator + * 2) 2d array of Operator structs. For each quorum the provided operator * was a part of at `blockNumber`, an ordered list of operators. */ function getOperatorState( - IRegistryCoordinator registryCoordinator, - bytes32 operatorId, + IRegistryCoordinator registryCoordinator, + bytes32 operatorId, uint32 blockNumber ) external view returns (uint256, Operator[][] memory) { bytes32[] memory operatorIds = new bytes32[](1); operatorIds[0] = operatorId; uint256 index = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds)[0]; - + uint256 quorumBitmap = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); @@ -54,7 +54,7 @@ contract OperatorStateRetriever { } /** - * @notice returns the ordered list of operators (id and stake) for each quorum. The AVS coordinator + * @notice returns the ordered list of operators (id and stake) for each quorum. The AVS coordinator * may call this function directly to get the operator state for a given block number * @param registryCoordinator is the registry coordinator to fetch the AVS registry information from * @param quorumNumbers are the ids of the quorums to get the operator state for @@ -62,8 +62,8 @@ contract OperatorStateRetriever { * @return 2d array of Operators. For each quorum, an ordered list of Operators */ function getOperatorState( - IRegistryCoordinator registryCoordinator, - bytes memory quorumNumbers, + IRegistryCoordinator registryCoordinator, + bytes memory quorumNumbers, uint32 blockNumber ) public view returns(Operator[][] memory) { IStakeRegistry stakeRegistry = registryCoordinator.stakeRegistry(); @@ -83,28 +83,28 @@ contract OperatorStateRetriever { }); } } - + return operators; } /** * @notice this is called by the AVS operator to get the relevant indices for the checkSignatures function - * if they are not running an indexer + * if they are not running an indexer * @param registryCoordinator is the registry coordinator to fetch the AVS registry information from * @param referenceBlockNumber is the block number to get the indices for * @param quorumNumbers are the ids of the quorums to get the operator state for * @param nonSignerOperatorIds are the ids of the nonsigning operators * @return 1) the indices of the quorumBitmaps for each of the operators in the @param nonSignerOperatorIds array at the given blocknumber * 2) the indices of the total stakes entries for the given quorums at the given blocknumber - * 3) the indices of the stakes of each of the nonsigners in each of the quorums they were a + * 3) the indices of the stakes of each of the nonsigners in each of the quorums they were a * part of (for each nonsigner, an array of length the number of quorums they were a part of * that are also part of the provided quorumNumbers) at the given blocknumber * 4) the indices of the quorum apks for each of the provided quorums at the given blocknumber */ function getCheckSignaturesIndices( IRegistryCoordinator registryCoordinator, - uint32 referenceBlockNumber, - bytes calldata quorumNumbers, + uint32 referenceBlockNumber, + bytes calldata quorumNumbers, bytes32[] calldata nonSignerOperatorIds ) external view returns (CheckSignaturesIndices memory) { IStakeRegistry stakeRegistry = registryCoordinator.stakeRegistry(); @@ -115,7 +115,7 @@ contract OperatorStateRetriever { // get the indices of the totalStake updates for each of the quorums in the quorumNumbers array checkSignaturesIndices.totalStakeIndices = stakeRegistry.getTotalStakeIndicesAtBlockNumber(referenceBlockNumber, quorumNumbers); - + checkSignaturesIndices.nonSignerStakeIndices = new uint32[][](quorumNumbers.length); for (uint8 quorumNumberIndex = 0; quorumNumberIndex < quorumNumbers.length; quorumNumberIndex++) { uint256 numNonSignersForQuorum = 0; @@ -124,15 +124,15 @@ contract OperatorStateRetriever { for (uint i = 0; i < nonSignerOperatorIds.length; i++) { // get the quorumBitmap for the operator at the given blocknumber and index - uint192 nonSignerQuorumBitmap = + uint192 nonSignerQuorumBitmap = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex( - nonSignerOperatorIds[i], - referenceBlockNumber, + nonSignerOperatorIds[i], + referenceBlockNumber, checkSignaturesIndices.nonSignerQuorumBitmapIndices[i] ); - + require(nonSignerQuorumBitmap != 0, "OperatorStateRetriever.getCheckSignaturesIndices: operator must be registered at blocknumber"); - + // if the operator was a part of the quorum and the quorum is a part of the provided quorumNumbers if ((nonSignerQuorumBitmap >> uint8(quorumNumbers[quorumNumberIndex])) & 1 == 1) { // get the index of the stake update for the operator at the given blocknumber and quorum number @@ -210,5 +210,5 @@ contract OperatorStateRetriever { operators[i] = registryCoordinator.getOperatorFromId(operatorIds[i]); } } - + } diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 884f99cd..99073714 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -1,10 +1,11 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {IAVSDirectory } from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; -import { OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IStrategy } from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; +import { IAllocationManager, OperatorSet, IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {ISocketUpdater} from "./interfaces/ISocketUpdater.sol"; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; @@ -26,7 +27,6 @@ import {Pausable} from "eigenlayer-contracts/src/contracts/permissions/Pausable. import {RegistryCoordinatorStorage} from "./RegistryCoordinatorStorage.sol"; import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; - /** * @title A `RegistryCoordinator` that has three registries: * 1) a `StakeRegistry` that keeps track of operators' stakes @@ -101,7 +101,7 @@ contract RegistryCoordinator is && _minimumStakes.length == _strategyParams.length && _strategyParams.length == _stakeTypes.length && _stakeTypes.length == _lookAheadPeriods.length, - "RegistryCoordinator.initialize: input length mismatch" + InputLengthMismatch() ); // Initialize roles @@ -143,7 +143,7 @@ contract RegistryCoordinator is IBLSApkRegistry.PubkeyRegistrationParams memory params, SignatureWithSaltAndExpiry memory operatorSignature ) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { - require(!isUsingOperatorSets(), "RegistryCoordinator.registerOperator: operator sets enabled"); + require(!isUsingOperatorSets(), OperatorSetsEnabled()); /** * If the operator has NEVER registered a pubkey before, use `params` to register * their pubkey in blsApkRegistry @@ -170,7 +170,7 @@ contract RegistryCoordinator is require( numOperatorsPerQuorum[i] <= _quorumParams[quorumNumber].maxOperatorCount, - "RegistryCoordinator.registerOperator: operator exceeds max" + MaxQuorumsReached() ); } } @@ -195,10 +195,10 @@ contract RegistryCoordinator is SignatureWithSaltAndExpiry memory churnApproverSignature, SignatureWithSaltAndExpiry memory operatorSignature ) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { - require(!isUsingOperatorSets(), "RegistryCoordinator.registerOperatorWithChurn: operator sets not supported"); + require(!isUsingOperatorSets(), OperatorSetsEnabled()); require( operatorKickParams.length == quorumNumbers.length, - "RegistryCoordinator.registerOperatorWithChurn: input length mismatch" + InputLengthMismatch() ); /** @@ -267,7 +267,7 @@ contract RegistryCoordinator is uint8 quorumNumber = uint8(quorumNumbers[i]); require( !isOperatorSetAVS || isM2Quorum[quorumNumber], - "RegistryCoordinator.deregisterOperator: cannot deregister from non-M2 quorum after operator sets enabled" + OperatorSetsEnabled() ); } _deregisterOperator({operator: msg.sender, quorumNumbers: quorumNumbers}); @@ -300,11 +300,11 @@ contract RegistryCoordinator is uint32[] memory operatorSetIds, bytes memory data ) external override onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { - require(isUsingOperatorSets(), "RegistryCoordinator.registerOperator: operator sets not enabled"); + require(isUsingOperatorSets(), OperatorSetsNotEnabled()); for (uint256 i = 0; i < operatorSetIds.length; i++) { - require(!isM2Quorum[uint8(operatorSetIds[i])], "RegistryCoordinator.registerOperator: cannot register for M2 quorum"); + require(!isM2Quorum[uint8(operatorSetIds[i])], OperatorSetsNotSupported()); } - require(msg.sender == address(serviceManager.allocationManager()), "Only allocation manager can register operators"); + require(msg.sender == address(serviceManager.allocationManager()), OnlyAllocationManager()); // Decode registration data from bytes ( @@ -326,22 +326,17 @@ contract RegistryCoordinator is quorumNumbers: quorumNumbers, socket: socket }); - - /// TODO: Register with Churn doesn't seem to be used in practice. I would advocate for not even handling the - /// the case and just killing off the function. This would free up code size as well - /// TODO: alternatively, Correctly handle decoding the registration with churn and the normal registration flow parameters - } function deregisterOperator( address operator, uint32[] memory operatorSetIds ) external override onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { - require(isUsingOperatorSets(), "RegistryCoordinator.deregisterOperator: operator sets not enabled"); + require(isUsingOperatorSets(), OperatorSetsNotEnabled()); for (uint256 i = 0; i < operatorSetIds.length; i++) { - require(!isM2Quorum[uint8(operatorSetIds[i])], "RegistryCoordinator.deregisterOperator: cannot deregister from M2 quorum"); + require(!isM2Quorum[uint8(operatorSetIds[i])], OperatorSetsNotSupported()); } - require(msg.sender == address(serviceManager.allocationManager()), "Only allocation manager can register operators"); + require(msg.sender == address(serviceManager.allocationManager()), OnlyAllocationManager()); bytes memory quorumNumbers = new bytes(operatorSetIds.length); for (uint256 i = 0; i < operatorSetIds.length; i++) { quorumNumbers[i] = bytes1(uint8(operatorSetIds[i])); @@ -398,7 +393,7 @@ contract RegistryCoordinator is uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); require( operatorsPerQuorum.length == quorumNumbers.length, - "RegistryCoordinator.updateOperatorsForQuorum: input length mismatch" + InputLengthMismatch() ); // For each quorum, update ALL registered operators @@ -409,7 +404,7 @@ contract RegistryCoordinator is address[] memory currQuorumOperators = operatorsPerQuorum[i]; require( currQuorumOperators.length == indexRegistry.totalOperatorsForQuorum(quorumNumber), - "RegistryCoordinator.updateOperatorsForQuorum: number of updated operators does not match quorum total" + QuorumOperatorCountMismatch() ); address prevOperatorAddress = address(0); @@ -428,12 +423,12 @@ contract RegistryCoordinator is // Check that the operator is registered require( BitmapUtils.isSet(currentBitmap, quorumNumber), - "RegistryCoordinator.updateOperatorsForQuorum: operator not in quorum" + NotRegisteredForQuorum() ); // Prevent duplicate operators require( operator > prevOperatorAddress, - "RegistryCoordinator.updateOperatorsForQuorum: operators must be sorted" + NotSorted() ); } @@ -455,7 +450,7 @@ contract RegistryCoordinator is function updateSocket(string memory socket) external { require( _operatorInfo[msg.sender].status == OperatorStatus.REGISTERED, - "RegistryCoordinator.updateSocket: not registered" + NotRegistered() ); emit OperatorSocketUpdate(_operatorInfo[msg.sender].operatorId, socket); } @@ -519,7 +514,7 @@ contract RegistryCoordinator is IStakeRegistry.StrategyParams[] memory strategyParams, uint32 lookAheadPeriod ) external virtual onlyOwner { - require(isUsingOperatorSets(), "RegistryCoordinator.createSlashableStakeQuorum: operator sets not enabled"); + require(isUsingOperatorSets(), OperatorSetsNotEnabled()); _createQuorum(operatorSetParams, minimumStake, strategyParams, StakeType.TOTAL_SLASHABLE, lookAheadPeriod); } @@ -599,18 +594,18 @@ contract RegistryCoordinator is uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); uint192 currentBitmap = _currentOperatorBitmap(operatorId); require( - !quorumsToAdd.isEmpty(), "RegistryCoordinator._registerOperator: bitmap empty" + !quorumsToAdd.isEmpty(), BitmapEmpty() ); require( quorumsToAdd.noBitsInCommon(currentBitmap), - "RegistryCoordinator._registerOperator: operator already registered for some quorums being registered for" + AlreadyRegisteredForQuorums() ); uint192 newBitmap = uint192(currentBitmap.plus(quorumsToAdd)); // Check that the operator can reregister if ejected require( lastEjectionTimestamp[operator] + ejectionCooldown < block.timestamp, - "RegistryCoordinator._registerOperator: operator cannot reregister yet" + CannotReregisterYet() ); /** @@ -662,18 +657,18 @@ contract RegistryCoordinator is uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); uint192 currentBitmap = _currentOperatorBitmap(operatorId); require( - !quorumsToAdd.isEmpty(), "RegistryCoordinator._registerOperatorToOperatorSet: bitmap empty" + !quorumsToAdd.isEmpty(), BitmapEmpty() ); require( quorumsToAdd.noBitsInCommon(currentBitmap), - "RegistryCoordinator._registerOperatorToOperatorSet: operator already registered for some quorums being registered for" + AlreadyRegisteredForQuorums() ); uint192 newBitmap = uint192(currentBitmap.plus(quorumsToAdd)); // Check that the operator can reregister if ejected require( lastEjectionTimestamp[operator] + ejectionCooldown < block.timestamp, - "RegistryCoordinator._registerOperatorToOperatorSet: operator cannot reregister yet" + CannotReregisterYet() ); /** @@ -704,13 +699,14 @@ contract RegistryCoordinator is * @dev Reverts if the caller is not the ejector */ function _checkEjector() internal view { - require(msg.sender == ejector, "RegistryCoordinator.onlyEjector: not ejector"); + require(msg.sender == ejector, OnlyEjector()); } function _checkAllocationManager() internal view { address allocationManager = address(serviceManager.allocationManager()); - require(msg.sender == allocationManager, "RegistryCoordinator.onlyAllocationManager: not allocation manager"); + require(msg.sender == allocationManager, OnlyAllocationManager()); } + /** * @notice Checks if a quorum exists * @param quorumNumber The quorum number to check @@ -718,7 +714,8 @@ contract RegistryCoordinator is */ function _checkQuorumExists(uint8 quorumNumber) internal view { require( - quorumNumber < quorumCount, "RegistryCoordinator.quorumExists: quorum does not exist" + quorumNumber < quorumCount, + QuorumDoesNotExist() ); } @@ -772,22 +769,23 @@ contract RegistryCoordinator is address operatorToKick = kickParams.operator; bytes32 idToKick = _operatorInfo[operatorToKick].operatorId; require( - newOperator != operatorToKick, "RegistryCoordinator._validateChurn: cannot churn self" + newOperator != operatorToKick, + CannotChurnSelf() ); require( kickParams.quorumNumber == quorumNumber, - "RegistryCoordinator._validateChurn: quorumNumber not the same as signed" + QuorumOperatorCountMismatch() ); // Get the target operator's stake and check that it is below the kick thresholds uint96 operatorToKickStake = stakeRegistry.getCurrentStake(idToKick, quorumNumber); require( newOperatorStake > _individualKickThreshold(operatorToKickStake, setParams), - "RegistryCoordinator._validateChurn: incoming operator has insufficient stake for churn" + InsufficientStakeForChurn() ); require( operatorToKickStake < _totalKickThreshold(totalQuorumStake, setParams), - "RegistryCoordinator._validateChurn: cannot kick operator with more than kickBIPsOfTotalStake" + CannotKickOperatorAboveThreshold() ); } @@ -802,7 +800,7 @@ contract RegistryCoordinator is bytes32 operatorId = operatorInfo.operatorId; require( operatorInfo.status == OperatorStatus.REGISTERED, - "RegistryCoordinator._deregisterOperator: not registered" + NotRegistered() ); /** @@ -817,35 +815,23 @@ contract RegistryCoordinator is uint192 currentBitmap = _currentOperatorBitmap(operatorId); require( !quorumsToRemove.isEmpty(), - "RegistryCoordinator._deregisterOperator: bitmap cannot be 0" + BitmapCannotBeZero() ); require( quorumsToRemove.isSubsetOf(currentBitmap), - "RegistryCoordinator._deregisterOperator: not registered for quorum" + NotRegisteredForQuorum() ); uint192 newBitmap = uint192(currentBitmap.minus(quorumsToRemove)); // Update operator's bitmap and status _updateOperatorBitmap({operatorId: operatorId, newBitmap: newBitmap}); - bool operatorSetAVS = isUsingOperatorSets(); - // = IAVSDirectory(serviceManager.avsDirectory()).isOperatorSetAVS(address(serviceManager)); - if (operatorSetAVS){ - bytes memory quorumBytes = BitmapUtils.bitmapToBytesArray(quorumsToRemove); - uint32[] memory operatorSetIds = new uint32[](quorumBytes.length); - for (uint256 i = 0; i < quorumBytes.length; i++) { - operatorSetIds[i] = uint8(quorumBytes[i]); - } - - serviceManager.deregisterOperatorFromOperatorSets(operator, operatorSetIds); - } else { - // If the operator is no longer registered for any quorums, update their status and deregister - // them from the AVS via the EigenLayer core contracts - if (newBitmap.isEmpty()) { - operatorInfo.status = OperatorStatus.DEREGISTERED; - serviceManager.deregisterOperatorFromAVS(operator); - emit OperatorDeregistered(operator, operatorId); - } + // If the operator is no longer registered for any quorums, update their status and deregister + // them from the AVS via the EigenLayer core contracts + if (newBitmap.isEmpty()) { + operatorInfo.status = OperatorStatus.DEREGISTERED; + serviceManager.deregisterOperatorFromAVS(operator); + emit OperatorDeregistered(operator, operatorId); } // Deregister operator with each of the registry contracts @@ -912,11 +898,11 @@ contract RegistryCoordinator is // make sure the salt hasn't been used already require( !isChurnApproverSaltUsed[churnApproverSignature.salt], - "RegistryCoordinator._verifyChurnApproverSignature: salt spent" + ChurnApproverSaltUsed() ); require( churnApproverSignature.expiry >= block.timestamp, - "RegistryCoordinator._verifyChurnApproverSignature: signature expired" + SignatureExpired() ); // set salt used to true @@ -955,7 +941,7 @@ contract RegistryCoordinator is uint8 prevQuorumCount = quorumCount; require( prevQuorumCount < MAX_QUORUM_COUNT, - "RegistryCoordinator.createQuorum: max quorums reached" + MaxQuorumsReached() ); quorumCount = prevQuorumCount + 1; @@ -965,6 +951,24 @@ contract RegistryCoordinator is // Initialize the quorum here and in each registry _setOperatorSetParams(quorumNumber, operatorSetParams); + /// Update the AllocationManager if operatorSetQuorum + if (isOperatorSetAVS && !isM2Quorum[quorumNumber]) { + // Create array of CreateSetParams for the new quorum + IAllocationManagerTypes.CreateSetParams[] memory createSetParams = new IAllocationManagerTypes.CreateSetParams[](1); + + // Extract strategies from strategyParams + IStrategy[] memory strategies = new IStrategy[](strategyParams.length); + for (uint256 i = 0; i < strategyParams.length; i++) { + strategies[i] = strategyParams[i].strategy; + } + + // Initialize CreateSetParams with quorumNumber as operatorSetId + createSetParams[0] = IAllocationManagerTypes.CreateSetParams({ + operatorSetId: quorumNumber, + strategies: strategies + }); + serviceManager.createOperatorSets(createSetParams); + } // Initialize stake registry based on stake type if (stakeType == StakeType.TOTAL_DELEGATED) { stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); diff --git a/src/RegistryCoordinatorStorage.sol b/src/RegistryCoordinatorStorage.sol index 145bc840..8e343fbd 100644 --- a/src/RegistryCoordinatorStorage.sol +++ b/src/RegistryCoordinatorStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index 89b8bb21..86c1e937 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -1,12 +1,13 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; -import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManager, IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {ServiceManagerBaseStorage} from "./ServiceManagerBaseStorage.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; @@ -48,6 +49,12 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _; } + /// @notice only StakeRegistry can call functions with this modifier + modifier onlyStakeRegistry() { + _checkStakeRegistry(); + _; + } + /// @notice Sets the (immutable) `_registryCoordinator` address constructor( IAVSDirectory __avsDirectory, @@ -120,9 +127,16 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); } - function createOperatorSets(uint32[] memory operatorSetIds) external onlyRegistryCoordinator { - /// TODO: - // _avsDirectory.createOperatorSets(operatorSetIds); + function createOperatorSets(IAllocationManager.CreateSetParams[] memory params) external onlyRegistryCoordinator { + _allocationManager.createOperatorSets(address(this), params); + } + + function addStrategyToOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) external onlyStakeRegistry { + _allocationManager.addStrategiesToOperatorSet(address(this), operatorSetId, strategies); + } + + function removeStrategiesFromOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) external onlyStakeRegistry { + _allocationManager.removeStrategiesFromOperatorSet(address(this), operatorSetId, strategies); } /** @@ -145,20 +159,6 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _avsDirectory.deregisterOperatorFromAVS(operator); } - /** - * @notice Forwards a call to EigenLayer's AVSDirectory contract to register an operator to operator sets - * @param operator The address of the operator to register. - * @param operatorSetIds The IDs of the operator sets. - * @param operatorSignature The signature, salt, and expiry of the operator's signature. - */ - function registerOperatorToOperatorSets( - address operator, - uint32[] calldata operatorSetIds, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature - ) public virtual onlyRegistryCoordinator { - // _avsDirectory.registerOperatorToOperatorSets(operator, operatorSetIds, operatorSignature); - } - /** * @notice Forwards a call to EigenLayer's AVSDirectory contract to deregister an operator from operator sets * @param operator The address of the operator to deregister. @@ -168,7 +168,11 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { address operator, uint32[] calldata operatorSetIds ) public virtual onlyRegistryCoordinator { - // _avsDirectory.deregisterOperatorFromOperatorSets(operator, operatorSetIds); + _allocationManager.deregisterFromOperatorSets(IAllocationManagerTypes.DeregisterParams({ + operator: operator, + avs: address(this), + operatorSetIds: operatorSetIds + })); } /** @@ -211,158 +215,6 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { delete proposedSlasher; } - /** - * @notice Migrates the AVS to use operator sets and creates new operator set IDs. - * @param operatorSetsToCreate An array of operator set IDs to create. - * @dev This function can only be called by the contract owner. - */ - function migrateAndCreateOperatorSetIds(uint32[] memory operatorSetsToCreate) - external - onlyOwner - { - _migrateAndCreateOperatorSetIds(operatorSetsToCreate); - } - - /** - * @notice Migrates operators to their respective operator sets. - * @param operatorSetIds A 2D array where each sub-array contains the operator set IDs for a specific operator. - * @param operators An array of operator addresses to migrate. - * @dev This function can only be called by the contract owner. - * @dev Reverts if the migration has already been finalized. - */ - function migrateToOperatorSets( - uint32[][] memory operatorSetIds, - address[] memory operators - ) external onlyOwner { - require(!migrationFinalized, "ServiceManager: Migration Already Finalized"); - _migrateToOperatorSets(operatorSetIds, operators); - } - - /** - * @notice Finalizes the migration process, preventing further migrations. - * @dev This function can only be called by the contract owner. - * @dev Reverts if the migration has already been finalized. - */ - function finalizeMigration() external onlyOwner { - require(!migrationFinalized, "ServiceManager: Migration Already Finalized"); - migrationFinalized = true; - } - - /** - * @notice Migrates the AVS to use operator sets and create new operator set IDs. - * @param operatorSetIdsToCreate An array of operator set IDs to create. - */ - function _migrateAndCreateOperatorSetIds(uint32[] memory operatorSetIdsToCreate) internal { - // _avsDirectory.becomeOperatorSetAVS(); - // IAVSDirectory(address(_avsDirectory)).createOperatorSets(operatorSetIdsToCreate); - } - - /** - * @notice Migrates operators to their respective operator sets. - * @param operatorSetIds A 2D array where each sub-array contains the operator set IDs for a specific operator. - * @param operators An array of operator addresses to migrate. - */ - function _migrateToOperatorSets( - uint32[][] memory operatorSetIds, - address[] memory operators - ) internal { - require( - operators.length == operatorSetIds.length, "ServiceManager: Input array length mismatch" - ); - for (uint256 i; i < operators.length; i++) { - _isOperatorRegisteredForQuorums(operators[i], operatorSetIds[i]); - } - // IAVSDirectory(address(_avsDirectory)).migrateOperatorsToOperatorSets( - // operators, operatorSetIds - // ); - } - - /** - * @notice Checks if an operator is registered for a specific quorum - * @param operator The address of the operator to check - * @param quorumNumbers The quorum number to check the registration for - * @return bool Returns true if the operator is registered for the specified quorum, false otherwise - */ - function _isOperatorRegisteredForQuorums( - address operator, - uint32[] memory quorumNumbers - ) internal view returns (bool) { - bytes32 operatorId = _registryCoordinator.getOperatorId(operator); - uint192 operatorBitmap = _registryCoordinator.getCurrentQuorumBitmap(operatorId); - for (uint256 i; i < quorumNumbers.length; i++) { - require( - BitmapUtils.isSet(operatorBitmap, uint8(quorumNumbers[i])), - "ServiceManager: Operator not in quorum" - ); - } - } - - /** - * @notice Retrieves the operators to migrate along with their respective operator set IDs. - * @return operatorSetIdsToCreate An array of operator set IDs to create. - * @return operatorSetIds A 2D array where each sub-array contains the operator set IDs for a specific operator. - * @return allOperators An array of all unique operator addresses. - */ - function getOperatorsToMigrate() - public - view - returns ( - uint32[] memory operatorSetIdsToCreate, - uint32[][] memory operatorSetIds, - address[] memory allOperators - ) - { - uint256 quorumCount = _registryCoordinator.quorumCount(); - - allOperators = new address[](0); - operatorSetIdsToCreate = new uint32[](quorumCount); - - // Step 1: Iterate through quorum numbers and get a list of unique operators - for (uint8 quorumNumber = 0; quorumNumber < quorumCount; quorumNumber++) { - // Step 2: Get operator list for quorum at current block - bytes32[] memory operatorIds = _registryCoordinator.indexRegistry() - .getOperatorListAtBlockNumber(quorumNumber, uint32(block.number)); - - // Step 3: Convert to address list and maintain a sorted array of operators - address[] memory operators = new address[](operatorIds.length); - for (uint256 i = 0; i < operatorIds.length; i++) { - operators[i] = - _registryCoordinator.blsApkRegistry().getOperatorFromPubkeyHash(operatorIds[i]); - // Insert into sorted array of all operators - allOperators = - LibMergeSort.mergeSortArrays(allOperators, LibMergeSort.sort(operators)); - } - address[] memory filteredOperators = new address[](allOperators.length); - uint256 count = 0; - for (uint256 i = 0; i < allOperators.length; i++) { - if (allOperators[i] != address(0)) { - filteredOperators[count++] = allOperators[i]; - } - } - // Resize array to remove empty slots - assembly { - mstore(filteredOperators, count) - } - allOperators = filteredOperators; - - operatorSetIdsToCreate[quorumNumber] = uint32(quorumNumber); - } - - operatorSetIds = new uint32[][](allOperators.length); - // Loop through each unique operator to get the quorums they are registered for - for (uint256 i = 0; i < allOperators.length; i++) { - address operator = allOperators[i]; - bytes32 operatorId = _registryCoordinator.getOperatorId(operator); - uint192 quorumsBitmap = _registryCoordinator.getCurrentQuorumBitmap(operatorId); - bytes memory quorumBytesArray = BitmapUtils.bitmapToBytesArray(quorumsBitmap); - uint32[] memory quorums = new uint32[](quorumBytesArray.length); - for (uint256 j = 0; j < quorumBytesArray.length; j++) { - quorums[j] = uint32(uint8(quorumBytesArray[j])); - } - operatorSetIds[i] = quorums; - } - } - function _setRewardsInitiator(address newRewardsInitiator) internal { emit RewardsInitiatorUpdated(rewardsInitiator, newRewardsInitiator); rewardsInitiator = newRewardsInitiator; @@ -468,6 +320,13 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { ); } + function _checkStakeRegistry() internal view { + require( + msg.sender == address(_stakeRegistry), + "ServiceManagerBase.onlyStakeRegistry: caller is not the stake registry" + ); + } + function _checkSlasher() internal view { require( diff --git a/src/ServiceManagerBaseStorage.sol b/src/ServiceManagerBaseStorage.sol index 51365228..6b8ee27b 100644 --- a/src/ServiceManagerBaseStorage.sol +++ b/src/ServiceManagerBaseStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; diff --git a/src/ServiceManagerRouter.sol b/src/ServiceManagerRouter.sol index e2259cfb..05a56780 100644 --- a/src/ServiceManagerRouter.sol +++ b/src/ServiceManagerRouter.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IServiceManagerUI} from "./interfaces/IServiceManagerUI.sol"; /** * @title Contract that proxies calls to a ServiceManager contract. * This contract is designed to be used by off-chain services which need - * errors to be handled gracefully. + * errors to be handled gracefully. * @author Layr Labs, Inc. */ @@ -40,7 +40,7 @@ contract ServiceManagerRouter { /** * @notice Internal helper function to make static calls - * @dev Handles calls to contracts that don't implement the given function and to EOAs by + * @dev Handles calls to contracts that don't implement the given function and to EOAs by * returning a failed call address */ function _makeCall(address serviceManager, bytes memory data) internal view returns (address[] memory) { diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index 0a5d8d97..fe861b7b 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IAVSDirectory } from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; @@ -154,10 +154,6 @@ contract StakeRegistry is StakeRegistryStorage { ) external onlyRegistryCoordinator returns (uint192) { uint192 quorumsToRemove; - bool isOperatorSetAVS; - // TODO: logic for determining if it's an operator set quorum number or not - // avsDirectory.isOperatorSetAVS(address(serviceManager)); - /** * For each quorum, update the operator's stake and record the delta * in the quorum's total stake. @@ -246,7 +242,7 @@ contract StakeRegistry is StakeRegistryStorage { * @param quorumNumber The quorum number to set the stake type for * @param _stakeType The type of stake to track (TOTAL_DELEGATED, TOTAL_SLASHABLE, or BOTH) */ - function setStakeType(uint8 quorumNumber, StakeType _stakeType) external onlyCoordinatorOwner { + function setStakeType(uint8 quorumNumber, StakeType _stakeType) external onlyCoordinatorOwner quorumExists(quorumNumber) { _setStakeType(quorumNumber, _stakeType); } @@ -255,9 +251,10 @@ contract StakeRegistry is StakeRegistryStorage { * @param quorumNumber The quorum number to set the look ahead period for * @param _lookAheadPeriod The number of days to look ahead when checking shares */ - function setSlashableStakeLookahead(uint8 quorumNumber, uint32 _lookAheadPeriod) external onlyCoordinatorOwner { + function setSlashableStakeLookahead(uint8 quorumNumber, uint32 _lookAheadPeriod) external onlyCoordinatorOwner quorumExists(quorumNumber) { _setLookAheadPeriod(quorumNumber, _lookAheadPeriod); } + /** * @notice Adds strategies and weights to the quorum * @dev Checks to make sure that the *same* strategy cannot be added multiple times (checks against both against existing and new strategies). @@ -574,6 +571,19 @@ contract StakeRegistry is StakeRegistryStorage { VIEW FUNCTIONS *******************************************************************************/ + /** + * @notice Returns whether a quorum is an operator set quorum based on its stake type + * @dev A quorum is an operator set quorum if it has TOTAL_SLASHABLE stake type + * and is not an M2 quorum + * @param quorumNumber The quorum number to check + * @return True if the quorum is an operator set quorum + */ + function isOperatorSetQuorum(uint8 quorumNumber) external view returns (bool) { + bool isM2 = IRegistryCoordinator(registryCoordinator).isM2Quorum(quorumNumber); + bool isOperatorSet = IRegistryCoordinator(registryCoordinator).isOperatorSetAVS(); + return isOperatorSet && !isM2; + } + /** * @notice This function computes the total weight of the @param operator in the quorum @param quorumNumber. * @dev reverts if the quorum does not exist diff --git a/src/StakeRegistryStorage.sol b/src/StakeRegistryStorage.sol index acc80dd7..fb4967ac 100644 --- a/src/StakeRegistryStorage.sol +++ b/src/StakeRegistryStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; diff --git a/src/interfaces/IBLSApkRegistry.sol b/src/interfaces/IBLSApkRegistry.sol index 2812a0ce..ced99f6c 100644 --- a/src/interfaces/IBLSApkRegistry.sol +++ b/src/interfaces/IBLSApkRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IRegistry} from "./IRegistry.sol"; @@ -24,9 +24,9 @@ interface IBLSApkRegistry is IRegistry { /** * @notice Struct used when registering a new public key * @param pubkeyRegistrationSignature is the registration message signed by the private key of the operator - * @param pubkeyG1 is the corresponding G1 public key of the operator + * @param pubkeyG1 is the corresponding G1 public key of the operator * @param pubkeyG2 is the corresponding G2 public key of the operator - */ + */ struct PubkeyRegistrationParams { BN254.G1Point pubkeyRegistrationSignature; BN254.G1Point pubkeyG1; @@ -46,7 +46,7 @@ interface IBLSApkRegistry is IRegistry { // @notice Emitted when an operator pubkey is removed from a set of quorums event OperatorRemovedFromQuorums( - address operator, + address operator, bytes32 operatorId, bytes quorumNumbers ); @@ -75,9 +75,9 @@ interface IBLSApkRegistry is IRegistry { * 3) `quorumNumbers` is ordered in ascending order * 4) the operator is not already deregistered * 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for - */ + */ function deregisterOperator(address operator, bytes calldata quorumNumbers) external; - + /** * @notice Initializes a new quorum by pushing its first apk update * @param quorumNumber The number of the new quorum diff --git a/src/interfaces/IBLSSignatureChecker.sol b/src/interfaces/IBLSSignatureChecker.sol index 844c7217..aa92e56f 100644 --- a/src/interfaces/IBLSSignatureChecker.sol +++ b/src/interfaces/IBLSSignatureChecker.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IRegistryCoordinator} from "./IRegistryCoordinator.sol"; import {IBLSApkRegistry} from "./IBLSApkRegistry.sol"; @@ -42,8 +42,8 @@ interface IBLSSignatureChecker { // EVENTS /// @notice Emitted when `staleStakesForbiddenUpdate` is set - event StaleStakesForbiddenUpdate(bool value); - + event StaleStakesForbiddenUpdate(bool value); + // CONSTANTS & IMMUTABLES function registryCoordinator() external view returns (IRegistryCoordinator); @@ -59,21 +59,21 @@ interface IBLSSignatureChecker { * The thesis of this procedure entails: * - getting the aggregated pubkey of all registered nodes at the time of pre-commit by the * disperser (represented by apk in the parameters), - * - subtracting the pubkeys of all the signers not in the quorum (nonSignerPubkeys) and storing + * - subtracting the pubkeys of all the signers not in the quorum (nonSignerPubkeys) and storing * the output in apk to get aggregated pubkey of all operators that are part of quorum. * - use this aggregated pubkey to verify the aggregated signature under BLS scheme. - * + * * @dev Before signature verification, the function verifies operator stake information. This includes ensuring that the provided `referenceBlockNumber` * 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 * for the total stake (or the operator) or latest before the referenceBlockNumber. */ function checkSignatures( - bytes32 msgHash, + bytes32 msgHash, bytes calldata quorumNumbers, - uint32 referenceBlockNumber, + uint32 referenceBlockNumber, NonSignerStakesAndSignature memory nonSignerStakesAndSignature - ) - external + ) + external view returns ( QuorumStakeTotals memory, diff --git a/src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol b/src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol index 445db814..b43743d3 100644 --- a/src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol +++ b/src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; diff --git a/src/interfaces/IEjectionManager.sol b/src/interfaces/IEjectionManager.sol index 9a02991e..545e0a7c 100644 --- a/src/interfaces/IEjectionManager.sol +++ b/src/interfaces/IEjectionManager.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; /** * @title Interface for a contract that ejects operators from an AVSs RegistryCoordinator @@ -25,7 +25,7 @@ interface IEjectionManager { event QuorumEjectionParamsSet(uint8 quorumNumber, uint32 rateLimitWindow, uint16 ejectableStakePercent); ///@notice Emitted when an operator is ejected event OperatorEjected(bytes32 operatorId, uint8 quorumNumber); - ///@notice Emitted when operators are ejected for a quroum + ///@notice Emitted when operators are ejected for a quroum event QuorumEjection(uint32 ejectedOperators, bool ratelimitHit); /** diff --git a/src/interfaces/IIndexRegistry.sol b/src/interfaces/IIndexRegistry.sol index 72a702d8..579fb23b 100644 --- a/src/interfaces/IIndexRegistry.sol +++ b/src/interfaces/IIndexRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IRegistry} from "./IRegistry.sol"; @@ -9,13 +9,13 @@ import {IRegistry} from "./IRegistry.sol"; */ interface IIndexRegistry is IRegistry { // EVENTS - + // emitted when an operator's index in the ordered operator list for the quorum with number `quorumNumber` is updated event QuorumIndexUpdate(bytes32 indexed operatorId, uint8 quorumNumber, uint32 newOperatorIndex); // DATA STRUCTURES - // struct used to give definitive ordering to operators at each blockNumber. + // struct used to give definitive ordering to operators at each blockNumber. struct OperatorUpdate { // blockNumber number from which `operatorIndex` was the operators index // the operator's index is the first entry such that `blockNumber >= entry.fromBlockNumber` diff --git a/src/interfaces/IRegistryCoordinator.sol b/src/interfaces/IRegistryCoordinator.sol index da20a3bc..4ce2e917 100644 --- a/src/interfaces/IRegistryCoordinator.sol +++ b/src/interfaces/IRegistryCoordinator.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IServiceManager} from "./IServiceManager.sol"; import {IBLSApkRegistry} from "./IBLSApkRegistry.sol"; @@ -7,11 +7,35 @@ import {IStakeRegistry} from "./IStakeRegistry.sol"; import {IIndexRegistry} from "./IIndexRegistry.sol"; import {BN254} from "../libraries/BN254.sol"; +interface IRegistryCoordinatorErrors { + error InputLengthMismatch(); + error OperatorSetsEnabled(); + error OperatorSetsNotEnabled(); + error OperatorSetsNotSupported(); + error OnlyAllocationManager(); + error OnlyEjector(); + error QuorumDoesNotExist(); + error BitmapEmpty(); + error AlreadyRegisteredForQuorums(); + error CannotReregisterYet(); + error NotRegistered(); + error CannotChurnSelf(); + error QuorumOperatorCountMismatch(); + error InsufficientStakeForChurn(); + error CannotKickOperatorAboveThreshold(); + error BitmapCannotBeZero(); + error NotRegisteredForQuorum(); + error MaxQuorumsReached(); + error SaltAlreadyUsed(); + error RegistryCoordinatorSignatureExpired(); + error ChurnApproverSaltUsed(); + error NotSorted(); +} /** * @title Interface for a contract that coordinates between various registries for an AVS. * @author Layr Labs, Inc. */ -interface IRegistryCoordinator { +interface IRegistryCoordinator is IRegistryCoordinatorErrors{ // EVENTS /// Emits when an operator is registered @@ -140,6 +164,15 @@ interface IRegistryCoordinator { /// @notice Returns the number of registries function numRegistries() external view returns (uint256); + /// @notice Returns whether a quorum is an M2 quorum + /// @param quorumNumber The quorum number to check + /// @return True if the quorum is an M2 quorum + function isM2Quorum(uint8 quorumNumber) external view returns (bool); + + /// @notice Returns whether the AVS is an operator set AVS + /// @return True if the AVS is an operator set AVS + function isOperatorSetAVS() external view returns (bool); + /** * @notice Returns the message hash that an operator must sign to register their BLS public key. * @param operator is the address of the operator registering their BLS public key diff --git a/src/interfaces/IServiceManager.sol b/src/interfaces/IServiceManager.sol index 02062d93..133c3789 100644 --- a/src/interfaces/IServiceManager.sol +++ b/src/interfaces/IServiceManager.sol @@ -6,6 +6,7 @@ import {IServiceManagerUI} from "./IServiceManagerUI.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; @@ -27,19 +28,11 @@ interface IServiceManager is IServiceManagerUI { */ function createAVSRewardsSubmission(IRewardsCoordinator.RewardsSubmission[] calldata rewardsSubmissions) external; - function createOperatorSets(uint32[] memory operatorSetIds) external; + function createOperatorSets(IAllocationManager.CreateSetParams[] memory params) external; - /** - * @notice Forwards a call to EigenLayer's AVSDirectory contract to register an operator to operator sets - * @param operator The address of the operator to register. - * @param operatorSetIds The IDs of the operator sets. - * @param operatorSignature The signature, salt, and expiry of the operator's signature. - */ - function registerOperatorToOperatorSets( - address operator, - uint32[] calldata operatorSetIds, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature - ) external; + function addStrategyToOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) external; + + function removeStrategiesFromOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) external; /** * @notice Sets the AVS registrar address in the AllocationManager diff --git a/src/interfaces/ISlasher.sol b/src/interfaces/ISlasher.sol index b938e915..a150bc94 100644 --- a/src/interfaces/ISlasher.sol +++ b/src/interfaces/ISlasher.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; diff --git a/src/interfaces/ISocketUpdater.sol b/src/interfaces/ISocketUpdater.sol index dcf5a865..dc17ecfa 100644 --- a/src/interfaces/ISocketUpdater.sol +++ b/src/interfaces/ISocketUpdater.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; /** * @title Interface for an `ISocketUpdater` where operators can update their sockets. @@ -11,7 +11,7 @@ interface ISocketUpdater { event OperatorSocketUpdate(bytes32 indexed operatorId, string socket); // FUNCTIONS - + /** * @notice Updates the socket of the msg.sender given they are a registered operator * @param socket is the new socket of the operator diff --git a/src/interfaces/IStakeRegistry.sol b/src/interfaces/IStakeRegistry.sol index 62756d3a..3b82fefb 100644 --- a/src/interfaces/IStakeRegistry.sol +++ b/src/interfaces/IStakeRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; diff --git a/src/libraries/BN254.sol b/src/libraries/BN254.sol index 37e3d273..61a20929 100644 --- a/src/libraries/BN254.sol +++ b/src/libraries/BN254.sol @@ -19,7 +19,7 @@ // The remainder of the code in this library is written by LayrLabs Inc. and is also under an MIT license -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; /** * @title Library for operations on the BN254 elliptic curve. diff --git a/src/libraries/BitmapUtils.sol b/src/libraries/BitmapUtils.sol index 41f9ef48..9c53aadd 100644 --- a/src/libraries/BitmapUtils.sol +++ b/src/libraries/BitmapUtils.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; /** * @title Library for Bitmap utilities such as converting between an array of bytes and a bitmap and finding the number of 1s in a bitmap. @@ -62,7 +62,7 @@ library BitmapUtils { function orderedBytesArrayToBitmap(bytes memory orderedBytesArray, uint8 bitUpperBound) internal pure returns (uint256) { uint256 bitmap = orderedBytesArrayToBitmap(orderedBytesArray); - require((1 << bitUpperBound) > bitmap, + require((1 << bitUpperBound) > bitmap, "BitmapUtils.orderedBytesArrayToBitmap: bitmap exceeds max value" ); @@ -95,11 +95,11 @@ library BitmapUtils { if (uint256(uint8(bytesArray[i])) <= uint256(uint8(singleByte))) { return false; } - + // Pull the next byte out of the array singleByte = bytesArray[i]; } - + return true; } @@ -149,9 +149,9 @@ library BitmapUtils { function isSet(uint256 bitmap, uint8 bit) internal pure returns (bool) { return 1 == ((bitmap >> bit) & 1); } - + /** - * @notice Returns a copy of `bitmap` with `bit` set. + * @notice Returns a copy of `bitmap` with `bit` set. * @dev IMPORTANT: we're dealing with stack values here, so this doesn't modify * the original bitmap. Using this correctly requires an assignment statement: * `bitmap = bitmap.setBit(bit);` diff --git a/src/libraries/LibMergeSort.sol b/src/libraries/LibMergeSort.sol index 012feed4..11eb91b1 100644 --- a/src/libraries/LibMergeSort.sol +++ b/src/libraries/LibMergeSort.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; library LibMergeSort { function sort(address[] memory array) internal pure returns (address[] memory) { diff --git a/src/libraries/QuorumBitmapHistoryLib.sol b/src/libraries/QuorumBitmapHistoryLib.sol index c971d64d..72cbf114 100644 --- a/src/libraries/QuorumBitmapHistoryLib.sol +++ b/src/libraries/QuorumBitmapHistoryLib.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IRegistryCoordinator} from "../interfaces/IRegistryCoordinator.sol"; diff --git a/src/libraries/SignatureCheckerLib.sol b/src/libraries/SignatureCheckerLib.sol index 410462cc..864e4afb 100644 --- a/src/libraries/SignatureCheckerLib.sol +++ b/src/libraries/SignatureCheckerLib.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin-upgrades/contracts/utils/cryptography/SignatureCheckerUpgradeable.sol"; diff --git a/src/slashers/InstantSlasher.sol b/src/slashers/InstantSlasher.sol index b30d5881..976ad896 100644 --- a/src/slashers/InstantSlasher.sol +++ b/src/slashers/InstantSlasher.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; diff --git a/src/slashers/VetoableSlasher.sol b/src/slashers/VetoableSlasher.sol index a973aacc..0f9c623f 100644 --- a/src/slashers/VetoableSlasher.sol +++ b/src/slashers/VetoableSlasher.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {SlasherBase} from "./base/SlasherBase.sol"; diff --git a/src/slashers/base/SlasherBase.sol b/src/slashers/base/SlasherBase.sol index 1ca3e3c9..283a764c 100644 --- a/src/slashers/base/SlasherBase.sol +++ b/src/slashers/base/SlasherBase.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; import {IServiceManager} from "../../interfaces/IServiceManager.sol"; diff --git a/src/slashers/base/SlasherStorage.sol b/src/slashers/base/SlasherStorage.sol index 1024811a..a3924f34 100644 --- a/src/slashers/base/SlasherStorage.sol +++ b/src/slashers/base/SlasherStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {ISlasher} from "../../interfaces/ISlasher.sol"; contract SlasherStorage is ISlasher { diff --git a/src/unaudited/ECDSAServiceManagerBase.sol b/src/unaudited/ECDSAServiceManagerBase.sol index d1c899ac..805a961a 100644 --- a/src/unaudited/ECDSAServiceManagerBase.sol +++ b/src/unaudited/ECDSAServiceManagerBase.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; diff --git a/src/unaudited/ECDSAStakeRegistry.sol b/src/unaudited/ECDSAStakeRegistry.sol index b333d504..0e341067 100644 --- a/src/unaudited/ECDSAStakeRegistry.sol +++ b/src/unaudited/ECDSAStakeRegistry.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {ECDSAStakeRegistryStorage, Quorum, StrategyParams} from "./ECDSAStakeRegistryStorage.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; diff --git a/src/unaudited/ECDSAStakeRegistryStorage.sol b/src/unaudited/ECDSAStakeRegistryStorage.sol index 0742157a..6509f214 100644 --- a/src/unaudited/ECDSAStakeRegistryStorage.sol +++ b/src/unaudited/ECDSAStakeRegistryStorage.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {CheckpointsUpgradeable} from "@openzeppelin-upgrades/contracts/utils/CheckpointsUpgradeable.sol"; diff --git a/src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol b/src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol index 23b8be2a..adfd2751 100644 --- a/src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol +++ b/src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {ECDSAStakeRegistryPermissioned} from "./ECDSAStakeRegistryPermissioned.sol"; diff --git a/src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol b/src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol index ef2e691c..ab0bca02 100644 --- a/src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol +++ b/src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {ECDSAStakeRegistry} from "../ECDSAStakeRegistry.sol"; diff --git a/test/events/IBLSApkRegistryEvents.sol b/test/events/IBLSApkRegistryEvents.sol index 1ed588de..6921203d 100644 --- a/test/events/IBLSApkRegistryEvents.sol +++ b/test/events/IBLSApkRegistryEvents.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {BN254} from "../../src/libraries/BN254.sol"; @@ -17,7 +17,7 @@ interface IBLSApkRegistryEvents { // @notice Emitted when an operator pubkey is removed from a set of quorums event OperatorRemovedFromQuorums( - address operator, + address operator, bytes32 operatorId, bytes quorumNumbers ); diff --git a/test/events/IIndexRegistryEvents.sol b/test/events/IIndexRegistryEvents.sol index 79494de0..21a0f0f2 100644 --- a/test/events/IIndexRegistryEvents.sol +++ b/test/events/IIndexRegistryEvents.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; interface IIndexRegistryEvents { // emitted when an operator's index in the ordered operator list for the quorum with number `quorumNumber` is updated diff --git a/test/events/IServiceManagerBaseEvents.sol b/test/events/IServiceManagerBaseEvents.sol index 6defff0d..1efb8fa0 100644 --- a/test/events/IServiceManagerBaseEvents.sol +++ b/test/events/IServiceManagerBaseEvents.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import { IRewardsCoordinator, diff --git a/test/events/IStakeRegistryEvents.sol b/test/events/IStakeRegistryEvents.sol index 3e6f7e24..1b585ceb 100644 --- a/test/events/IStakeRegistryEvents.sol +++ b/test/events/IStakeRegistryEvents.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IStakeRegistry, IStrategy} from "src/interfaces/IStakeRegistry.sol"; diff --git a/test/ffi/BLSPubKeyCompendiumFFI.t.sol b/test/ffi/BLSPubKeyCompendiumFFI.t.sol index 18d49a17..4f3906ba 100644 --- a/test/ffi/BLSPubKeyCompendiumFFI.t.sol +++ b/test/ffi/BLSPubKeyCompendiumFFI.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/BLSApkRegistry.sol"; import "../ffi/util/G2Operations.sol"; diff --git a/test/ffi/BLSSignatureCheckerFFI.t.sol b/test/ffi/BLSSignatureCheckerFFI.t.sol index 16f72b4e..16c22ebe 100644 --- a/test/ffi/BLSSignatureCheckerFFI.t.sol +++ b/test/ffi/BLSSignatureCheckerFFI.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {G2Operations} from "../ffi/util/G2Operations.sol"; import {MockAVSDeployer} from "../utils/MockAVSDeployer.sol"; @@ -30,13 +30,13 @@ contract BLSSignatureCheckerFFITests is MockAVSDeployer, G2Operations { // this test checks that a valid signature from maxOperatorsToRegister with a random number of nonsigners is checked // correctly on the BLSSignatureChecker contract when all operators are only regsitered for a single quorum and // the signature is only checked for stakes on that quorum - function testBLSSignatureChecker_SingleQuorum_Valid(uint256 pseudoRandomNumber) public { + function testBLSSignatureChecker_SingleQuorum_Valid(uint256 pseudoRandomNumber) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 1); uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); uint256 gasBefore = gasleft(); @@ -44,9 +44,9 @@ contract BLSSignatureCheckerFFITests is MockAVSDeployer, G2Operations { BLSSignatureChecker.QuorumStakeTotals memory quorumStakeTotals, /* bytes32 signatoryRecordHash */ ) = blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); uint256 gasAfter = gasleft(); @@ -61,14 +61,14 @@ contract BLSSignatureCheckerFFITests is MockAVSDeployer, G2Operations { // this test checks that a valid signature from maxOperatorsToRegister with a random number of nonsigners is checked // correctly on the BLSSignatureChecker contract when all operators are registered for the first 100 quorums // and the signature is only checked for stakes on those quorums - function testBLSSignatureChecker_100Quorums_Valid(uint256 pseudoRandomNumber) public { + function testBLSSignatureChecker_100Quorums_Valid(uint256 pseudoRandomNumber) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 1); // 100 set bits uint256 quorumBitmap = (1 << 100) - 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = + (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); nonSignerStakesAndSignature.sigma = sigma.scalar_mul(quorumNumbers.length); @@ -76,9 +76,9 @@ contract BLSSignatureCheckerFFITests is MockAVSDeployer, G2Operations { uint256 gasBefore = gasleft(); blsSignatureChecker.checkSignatures( - msgHash, + msgHash, quorumNumbers, - referenceBlockNumber, + referenceBlockNumber, nonSignerStakesAndSignature ); uint256 gasAfter = gasleft(); @@ -168,8 +168,8 @@ contract BLSSignatureCheckerFFITests is MockAVSDeployer, G2Operations { OperatorStateRetriever.CheckSignaturesIndices memory checkSignaturesIndices = operatorStateRetriever.getCheckSignaturesIndices( registryCoordinator, - referenceBlockNumber, - quorumNumbers, + referenceBlockNumber, + quorumNumbers, nonSignerOperatorIds ); diff --git a/test/ffi/UpdateOperators.t.sol b/test/ffi/UpdateOperators.t.sol index 26fad27d..64e3ecbc 100644 --- a/test/ffi/UpdateOperators.t.sol +++ b/test/ffi/UpdateOperators.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "test/integration/User.t.sol"; @@ -37,7 +37,7 @@ contract Integration_AVS_Sync_GasCosts_FFI is IntegrationChecks { config_data, string.concat(".G1y[", vm.toString(i), "]") ); - // G2 + // G2 pubkey.pubkeyG2.X[1] = stdJson.readUint( config_data, string.concat(".G2x1[", vm.toString(i), "]") diff --git a/test/ffi/util/G2Operations.sol b/test/ffi/util/G2Operations.sol index f25cbbb7..016011da 100644 --- a/test/ffi/util/G2Operations.sol +++ b/test/ffi/util/G2Operations.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; import "openzeppelin-contracts/contracts/utils/Strings.sol"; @@ -13,7 +13,7 @@ contract G2Operations is Test { inputs[0] = "go"; inputs[1] = "run"; inputs[2] = "test/ffi/go/g2mul.go"; - inputs[3] = x.toString(); + inputs[3] = x.toString(); inputs[4] = "1"; bytes memory res = vm.ffi(inputs); diff --git a/test/harnesses/AVSDirectoryHarness.sol b/test/harnesses/AVSDirectoryHarness.sol index 262e8903..995f62a6 100644 --- a/test/harnesses/AVSDirectoryHarness.sol +++ b/test/harnesses/AVSDirectoryHarness.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; diff --git a/test/harnesses/BLSApkRegistryHarness.sol b/test/harnesses/BLSApkRegistryHarness.sol index 546d355c..7cc8ec60 100644 --- a/test/harnesses/BLSApkRegistryHarness.sol +++ b/test/harnesses/BLSApkRegistryHarness.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/BLSApkRegistry.sol"; diff --git a/test/harnesses/BitmapUtilsWrapper.sol b/test/harnesses/BitmapUtilsWrapper.sol index 19e1135e..95322d21 100644 --- a/test/harnesses/BitmapUtilsWrapper.sol +++ b/test/harnesses/BitmapUtilsWrapper.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/libraries/BitmapUtils.sol"; diff --git a/test/harnesses/RegistryCoordinatorHarness.t.sol b/test/harnesses/RegistryCoordinatorHarness.t.sol index 9dede138..8110fb13 100644 --- a/test/harnesses/RegistryCoordinatorHarness.t.sol +++ b/test/harnesses/RegistryCoordinatorHarness.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/RegistryCoordinator.sol"; diff --git a/test/harnesses/StakeRegistryHarness.sol b/test/harnesses/StakeRegistryHarness.sol index ca3cd2af..7d00b107 100644 --- a/test/harnesses/StakeRegistryHarness.sol +++ b/test/harnesses/StakeRegistryHarness.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/StakeRegistry.sol"; diff --git a/test/integration/CoreRegistration.t.sol b/test/integration/CoreRegistration.t.sol index a237e410..5d875e3e 100644 --- a/test/integration/CoreRegistration.t.sol +++ b/test/integration/CoreRegistration.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../utils/MockAVSDeployer.sol"; import { AVSDirectory } from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; diff --git a/test/integration/IntegrationBase.t.sol b/test/integration/IntegrationBase.t.sol index 7a0265f9..0baf32b4 100644 --- a/test/integration/IntegrationBase.t.sol +++ b/test/integration/IntegrationBase.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; @@ -164,7 +164,7 @@ abstract contract IntegrationBase is IntegrationConfig { } /// AVSDirectory: - + function assert_NotRegisteredToAVS(User operator, string memory err) internal { IAVSDirectoryTypes.OperatorAVSRegistrationStatus status = avsDirectory.avsOperatorStatus(address(serviceManager), address(operator)); @@ -222,7 +222,7 @@ abstract contract IntegrationBase is IntegrationConfig { function assert_Snap_Unchanged_QuorumBitmap(User user, string memory err) internal { bytes32 operatorId = user.operatorId(); - + uint192 curBitmap = _getQuorumBitmap(operatorId); uint192 prevBitmap = _getPrevQuorumBitmap(operatorId); @@ -288,11 +288,11 @@ abstract contract IntegrationBase is IntegrationConfig { for (uint i = 0; i < churnedQuorums.length; i++) { BN254.G1Point memory churnedPubkey = churnedOperators[i].pubkeyG1(); - BN254.G1Point memory expectedApk + BN254.G1Point memory expectedApk = prevApks[i] .plus(churnedPubkey.negate()) .plus(incomingPubkey); - + assertEq(expectedApk.X, curApks[i].X, err); assertEq(expectedApk.Y, curApks[i].Y, err); } @@ -300,7 +300,7 @@ abstract contract IntegrationBase is IntegrationConfig { /// @dev Check that specific weights were added to the operator and total stakes for each quorum function assert_Snap_AddedWeightToStakes( - User user, + User user, bytes memory quorums, uint96[] memory addedWeights, string memory err @@ -320,7 +320,7 @@ abstract contract IntegrationBase is IntegrationConfig { /// @dev Check that the operator's stake weight was added to the operator and total /// stakes for each quorum function assert_Snap_Added_OperatorWeight( - User user, + User user, bytes memory quorums, string memory err ) internal { @@ -362,7 +362,7 @@ abstract contract IntegrationBase is IntegrationConfig { } function assert_Snap_Unchanged_OperatorStake( - User user, + User user, bytes memory quorums, string memory err ) internal { @@ -431,7 +431,7 @@ abstract contract IntegrationBase is IntegrationConfig { } function assert_Snap_Removed_TotalStake( - User user, + User user, bytes memory quorums, string memory err ) internal { @@ -462,7 +462,7 @@ abstract contract IntegrationBase is IntegrationConfig { function assert_Snap_Added_OperatorCount(bytes memory quorums, string memory err) internal { uint32[] memory curOperatorCounts = _getOperatorCounts(quorums); uint32[] memory prevOperatorCounts = _getPrevOperatorCounts(quorums); - + for (uint i = 0; i < quorums.length; i++) { assertEq(curOperatorCounts[i], prevOperatorCounts[i] + 1, err); } @@ -471,7 +471,7 @@ abstract contract IntegrationBase is IntegrationConfig { function assert_Snap_Reduced_OperatorCount(bytes memory quorums, string memory err) internal { uint32[] memory curOperatorCounts = _getOperatorCounts(quorums); uint32[] memory prevOperatorCounts = _getPrevOperatorCounts(quorums); - + for (uint i = 0; i < quorums.length; i++) { assertEq(curOperatorCounts[i], prevOperatorCounts[i] - 1, err); } @@ -480,7 +480,7 @@ abstract contract IntegrationBase is IntegrationConfig { function assert_Snap_Unchanged_OperatorCount(bytes memory quorums, string memory err) internal { uint32[] memory curOperatorCounts = _getOperatorCounts(quorums); uint32[] memory prevOperatorCounts = _getPrevOperatorCounts(quorums); - + for (uint i = 0; i < quorums.length; i++) { assertEq(curOperatorCounts[i], prevOperatorCounts[i], err); } @@ -491,7 +491,7 @@ abstract contract IntegrationBase is IntegrationConfig { /// - that the operator is in the current list, but not the previous list function assert_Snap_Added_OperatorListEntry( User operator, - bytes memory quorums, + bytes memory quorums, string memory err ) internal { bytes32[][] memory curOperatorLists = _getOperatorLists(quorums); @@ -510,7 +510,7 @@ abstract contract IntegrationBase is IntegrationConfig { /// - that the operator is in the previous list, but not the current list function assert_Snap_Removed_OperatorListEntry( User operator, - bytes memory quorums, + bytes memory quorums, string memory err ) internal { bytes32[][] memory curOperatorLists = _getOperatorLists(quorums); @@ -541,12 +541,12 @@ abstract contract IntegrationBase is IntegrationConfig { function assert_Snap_Replaced_OperatorListEntries( User incomingOperator, User[] memory churnedOperators, - bytes memory churnedQuorums, + bytes memory churnedQuorums, string memory err ) internal { // Sanity check input lengths assertEq(churnedOperators.length, churnedQuorums.length, "assert_Snap_Replaced_OperatorListEntries: input length mismatch"); - + bytes32[][] memory curOperatorLists = _getOperatorLists(churnedQuorums); bytes32[][] memory prevOperatorLists = _getPrevOperatorLists(churnedQuorums); @@ -568,11 +568,11 @@ abstract contract IntegrationBase is IntegrationConfig { TIME TRAVELERS ONLY BEYOND THIS POINT *******************************************************************************/ - /// @dev Check that the operator has `addedShares` additional operator shares + /// @dev Check that the operator has `addedShares` additional operator shares // for each strategy since the last snapshot function assert_Snap_Added_OperatorShares( - User operator, - IStrategy[] memory strategies, + User operator, + IStrategy[] memory strategies, uint[] memory addedShares, string memory err ) internal { @@ -589,8 +589,8 @@ abstract contract IntegrationBase is IntegrationConfig { /// @dev Check that the operator has `removedShares` fewer operator shares /// for each strategy since the last snapshot function assert_Snap_Removed_OperatorShares( - User operator, - IStrategy[] memory strategies, + User operator, + IStrategy[] memory strategies, uint256[] memory removedShares, string memory err ) internal { @@ -607,8 +607,8 @@ abstract contract IntegrationBase is IntegrationConfig { /// @dev Check that the staker has `addedShares` additional delegatable shares /// for each strategy since the last snapshot function assert_Snap_Added_StakerShares( - User staker, - IStrategy[] memory strategies, + User staker, + IStrategy[] memory strategies, uint[] memory addedShares, string memory err ) internal { @@ -625,8 +625,8 @@ abstract contract IntegrationBase is IntegrationConfig { /// @dev Check that the staker has `removedShares` fewer delegatable shares /// for each strategy since the last snapshot function assert_Snap_Removed_StakerShares( - User staker, - IStrategy[] memory strategies, + User staker, + IStrategy[] memory strategies, uint[] memory removedShares, string memory err ) internal { @@ -641,7 +641,7 @@ abstract contract IntegrationBase is IntegrationConfig { } function assert_Snap_Added_QueuedWithdrawals( - User staker, + User staker, IDelegationManager.Withdrawal[] memory withdrawals, string memory err ) internal { @@ -653,7 +653,7 @@ abstract contract IntegrationBase is IntegrationConfig { } function assert_Snap_Added_QueuedWithdrawal( - User staker, + User staker, string memory err ) internal { uint curQueuedWithdrawal = _getCumulativeWithdrawals(staker); @@ -741,7 +741,7 @@ abstract contract IntegrationBase is IntegrationConfig { /// @dev Uses timewarp modifier to get operator shares at the last snapshot function _getPrevOperatorShares( - User operator, + User operator, IStrategy[] memory strategies ) internal timewarp() returns (uint[] memory) { return _getOperatorShares(operator, strategies); @@ -760,7 +760,7 @@ abstract contract IntegrationBase is IntegrationConfig { /// @dev Uses timewarp modifier to get staker shares at the last snapshot function _getPrevStakerShares( - User staker, + User staker, IStrategy[] memory strategies ) internal timewarp() returns (uint[] memory) { return _getStakerShares(staker, strategies); @@ -786,7 +786,7 @@ abstract contract IntegrationBase is IntegrationConfig { function _getCumulativeWithdrawals(User staker) internal view returns (uint) { return delegationManager.cumulativeWithdrawalsQueued(address(staker)); } - + /// RegistryCoordinator: function _getOperatorInfo(User user) internal view returns (IRegistryCoordinator.OperatorInfo memory) { @@ -880,7 +880,7 @@ abstract contract IntegrationBase is IntegrationConfig { for (uint i = 0; i < quorums.length; i++) { stakes[i] = stakeRegistry.getCurrentTotalStake(uint8(quorums[i])); } - + return stakes; } diff --git a/test/integration/IntegrationChecks.t.sol b/test/integration/IntegrationChecks.t.sol index 67ee38f5..0f2de79c 100644 --- a/test/integration/IntegrationChecks.t.sol +++ b/test/integration/IntegrationChecks.t.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "test/integration/IntegrationBase.t.sol"; import "test/integration/User.t.sol"; /// @notice Contract that provides utility functions to reuse common test blocks & checks contract IntegrationChecks is IntegrationBase { - + using BitmapUtils for *; /******************************************************************************* @@ -25,11 +25,11 @@ contract IntegrationChecks is IntegrationBase { "operator already has bits in quorum bitmap"); // BLSApkRegistry - assert_NoRegisteredPubkey(operator, + assert_NoRegisteredPubkey(operator, "operator already has a registered pubkey"); // DelegationManager - assert_NotRegisteredToAVS(operator, + assert_NotRegisteredToAVS(operator, "operator should not be registered to the AVS"); } @@ -44,7 +44,7 @@ contract IntegrationChecks is IntegrationBase { _log("check_Register_State", operator); // RegistryCoordinator - assert_HasOperatorInfoWithId(operator, + assert_HasOperatorInfoWithId(operator, "operatorInfo should have operatorId"); assert_HasRegisteredStatus(operator, "operatorInfo status should be REGISTERED"); @@ -54,11 +54,11 @@ contract IntegrationChecks is IntegrationBase { "operator did not register for all quorums"); // BLSApkRegistry - assert_HasRegisteredPubkey(operator, + assert_HasRegisteredPubkey(operator, "operator should have registered a pubkey"); - assert_Snap_Added_QuorumApk(operator, quorums, + assert_Snap_Added_QuorumApk(operator, quorums, "operator pubkey should have been added to each quorum apk"); - + // StakeRegistry assert_HasAtLeastMinimumStake(operator, quorums, "operator should have at least the minimum stake in each quorum"); @@ -86,14 +86,14 @@ contract IntegrationChecks is IntegrationBase { ) internal { _log("check_Churned_State", incomingOperator); - bytes memory combinedQuorums = + bytes memory combinedQuorums = churnedQuorums .orderedBytesArrayToBitmap() .plus(standardQuorums.orderedBytesArrayToBitmap()) .bitmapToBytesArray(); // RegistryCoordinator - assert_HasOperatorInfoWithId(incomingOperator, + assert_HasOperatorInfoWithId(incomingOperator, "operatorInfo should have operatorId"); assert_HasRegisteredStatus(incomingOperator, "operatorInfo status should be REGISTERED"); @@ -103,13 +103,13 @@ contract IntegrationChecks is IntegrationBase { "operator did not register for all quorums"); // BLSApkRegistry - assert_HasRegisteredPubkey(incomingOperator, + assert_HasRegisteredPubkey(incomingOperator, "operator should have registered a pubkey"); assert_Snap_Added_QuorumApk(incomingOperator, standardQuorums, "operator pubkey should have been added to standardQuorums apks"); assert_Snap_Churned_QuorumApk(incomingOperator, churnedOperators, churnedQuorums, "operator pubkey should have been added and churned operator pubkeys should have been removed from apks"); - + // StakeRegistry assert_HasAtLeastMinimumStake(incomingOperator, combinedQuorums, "operator should have at least the minimum stake in each quorum"); @@ -140,7 +140,7 @@ contract IntegrationChecks is IntegrationBase { churnedQuorum[0] = churnedQuorums[i]; // RegistryCoordinator - assert_HasOperatorInfoWithId(churnedOperator, + assert_HasOperatorInfoWithId(churnedOperator, "churned operatorInfo should still have operatorId"); assert_NotRegisteredForQuorums(churnedOperator, churnedQuorum, "churned operator bitmap should not include churned quorums"); @@ -148,7 +148,7 @@ contract IntegrationChecks is IntegrationBase { "churned operator did not deregister from churned quorum"); // BLSApkRegistry - assert_HasRegisteredPubkey(churnedOperator, + assert_HasRegisteredPubkey(churnedOperator, "churned operator should still have a registered pubkey"); // StakeRegistry @@ -177,7 +177,7 @@ contract IntegrationChecks is IntegrationBase { "operator info should not have changed"); assert_Snap_Unchanged_QuorumBitmap(operator, "operators quorum bitmap should not have changed"); - + // BLSApkRegistry assert_Snap_Unchanged_QuorumApk(quorums, "quorum apks should not have changed"); @@ -185,9 +185,9 @@ contract IntegrationChecks is IntegrationBase { // StakeRegistry assert_Snap_Increased_OperatorWeight(operator, quorums, "operator weight should not have decreased after deposit"); - assert_Snap_Unchanged_OperatorStake(operator, quorums, + assert_Snap_Unchanged_OperatorStake(operator, quorums, "operator stake should be unchanged"); - assert_Snap_Unchanged_TotalStake(quorums, + assert_Snap_Unchanged_TotalStake(quorums, "total stake should be unchanged"); // IndexRegistry @@ -205,8 +205,8 @@ contract IntegrationChecks is IntegrationBase { /// NOTE: This method assumes (and checks) that the operator already /// met the minimum stake before stake was added. function check_DepositUpdate_State( - User operator, - bytes memory quorums, + User operator, + bytes memory quorums, uint96[] memory addedWeights ) internal { _log("check_DepositUpdate_State", operator); @@ -254,7 +254,7 @@ contract IntegrationChecks is IntegrationBase { "operator info should not have changed"); assert_Snap_Unchanged_QuorumBitmap(operator, "operators quorum bitmap should not have changed"); - + // BLSApkRegistry assert_Snap_Unchanged_QuorumApk(quorums, "quorum apks should not have changed"); @@ -262,9 +262,9 @@ contract IntegrationChecks is IntegrationBase { // StakeRegistry assert_Snap_Decreased_OperatorWeight(operator, quorums, "operator weight should not have increased after deposit"); - assert_Snap_Unchanged_OperatorStake(operator, quorums, + assert_Snap_Unchanged_OperatorStake(operator, quorums, "operator stake should be unchanged"); - assert_Snap_Unchanged_TotalStake(quorums, + assert_Snap_Unchanged_TotalStake(quorums, "total stake should be unchanged"); // IndexRegistry @@ -288,7 +288,7 @@ contract IntegrationChecks is IntegrationBase { _log("check_WithdrawUpdate_State", operator); // RegistryCoordinator - assert_HasOperatorInfoWithId(operator, + assert_HasOperatorInfoWithId(operator, "operatorInfo should still have operatorId"); assert_EmptyQuorumBitmap(operator, "operator should not have any bits in bitmap"); @@ -298,9 +298,9 @@ contract IntegrationChecks is IntegrationBase { "operator did not deregister from all quorums"); // BLSApkRegistry - assert_HasRegisteredPubkey(operator, + assert_HasRegisteredPubkey(operator, "operator should still have a registered pubkey"); - assert_Snap_Removed_QuorumApk(operator, quorums, + assert_Snap_Removed_QuorumApk(operator, quorums, "operator pubkey should have been subtracted from each quorum apk"); // StakeRegistry @@ -316,7 +316,7 @@ contract IntegrationChecks is IntegrationBase { "operator list should have one fewer entry"); // AVSDirectory - assert_NotRegisteredToAVS(operator, + assert_NotRegisteredToAVS(operator, "operator should not be registered to the AVS"); } @@ -364,7 +364,7 @@ contract IntegrationChecks is IntegrationBase { _log("check_Deregister_State", operator); // RegistryCoordinator - assert_HasOperatorInfoWithId(operator, + assert_HasOperatorInfoWithId(operator, "operatorInfo should still have operatorId"); assert_NotRegisteredForQuorums(operator, quorums, "current operator bitmap should not include quorums"); @@ -372,9 +372,9 @@ contract IntegrationChecks is IntegrationBase { "operator did not deregister from all quorums"); // BLSApkRegistry - assert_HasRegisteredPubkey(operator, + assert_HasRegisteredPubkey(operator, "operator should still have a registered pubkey"); - assert_Snap_Removed_QuorumApk(operator, quorums, + assert_Snap_Removed_QuorumApk(operator, quorums, "operator pubkey should have been subtracted from each quorum apk"); // StakeRegistry @@ -399,13 +399,13 @@ contract IntegrationChecks is IntegrationBase { // RegistryCoordinator assert_EmptyQuorumBitmap(operator, "operator should not have any bits in bitmap"); - assert_HasOperatorInfoWithId(operator, + assert_HasOperatorInfoWithId(operator, "operatorInfo should still have operatorId"); assert_HasDeregisteredStatus(operator, "operatorInfo status should be DEREGISTERED"); // AVSDirectory - assert_NotRegisteredToAVS(operator, + assert_NotRegisteredToAVS(operator, "operator should not be registered to the AVS"); } diff --git a/test/integration/IntegrationConfig.t.sol b/test/integration/IntegrationConfig.t.sol index e1a341e8..f3231ac3 100644 --- a/test/integration/IntegrationConfig.t.sol +++ b/test/integration/IntegrationConfig.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index db3fb704..414b8fe2 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; diff --git a/test/integration/TimeMachine.t.sol b/test/integration/TimeMachine.t.sol index b1df82d5..b1cffa68 100644 --- a/test/integration/TimeMachine.t.sol +++ b/test/integration/TimeMachine.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; diff --git a/test/integration/User.t.sol b/test/integration/User.t.sol index b98a8cd3..4b58950a 100644 --- a/test/integration/User.t.sol +++ b/test/integration/User.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; diff --git a/test/integration/mocks/BeaconChainOracleMock.t.sol b/test/integration/mocks/BeaconChainOracleMock.t.sol index fcccbbd4..5c2e4b77 100644 --- a/test/integration/mocks/BeaconChainOracleMock.t.sol +++ b/test/integration/mocks/BeaconChainOracleMock.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; // import "eigenlayer-contracts/src/contracts/interfaces/IBeaconChainOracle.sol"; diff --git a/test/integration/tests/Full_Register_Deregister.t.sol b/test/integration/tests/Full_Register_Deregister.t.sol index 48bb150a..2561aa2c 100644 --- a/test/integration/tests/Full_Register_Deregister.t.sol +++ b/test/integration/tests/Full_Register_Deregister.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "test/integration/User.t.sol"; @@ -109,7 +109,7 @@ contract Integration_Full_Register_Deregister is IntegrationChecks { churnTarget.registerOperator(quorum); check_Register_State(churnTarget, quorum); } - + // 4. Original operator re-registers for all quorums by churning old operators again operator.registerOperatorWithChurn(quorums, churnTargets, new bytes(0)); check_Churned_State({ @@ -140,7 +140,7 @@ contract Integration_Full_Register_Deregister is IntegrationChecks { // Select some quorums to register using churn, and the rest without churn bytes memory churnQuorums = _selectRand(quorums); - bytes memory standardQuorums = + bytes memory standardQuorums = quorums .orderedBytesArrayToBitmap() .minus(churnQuorums.orderedBytesArrayToBitmap()) diff --git a/test/integration/tests/NonFull_Register_CoreBalanceChange_Update.t.sol b/test/integration/tests/NonFull_Register_CoreBalanceChange_Update.t.sol index a4ffe3e6..d9b74e8d 100644 --- a/test/integration/tests/NonFull_Register_CoreBalanceChange_Update.t.sol +++ b/test/integration/tests/NonFull_Register_CoreBalanceChange_Update.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "test/integration/User.t.sol"; diff --git a/test/integration/tests/NonFull_Register_Deregister.t.sol b/test/integration/tests/NonFull_Register_Deregister.t.sol index c30c5261..6acf85cb 100644 --- a/test/integration/tests/NonFull_Register_Deregister.t.sol +++ b/test/integration/tests/NonFull_Register_Deregister.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "test/integration/User.t.sol"; diff --git a/test/integration/utils/BitmapStrings.t.sol b/test/integration/utils/BitmapStrings.t.sol index 532f5d8d..2bcec384 100644 --- a/test/integration/utils/BitmapStrings.t.sol +++ b/test/integration/utils/BitmapStrings.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/utils/Strings.sol"; @@ -16,12 +16,12 @@ library BitmapStrings { for (uint i = 0; i < bitmapArr.length; i++) { if (i == bitmapArr.length - 1) { result = string.concat( - result, + result, uint(uint8(bitmapArr[i])).toString() ); } else { result = string.concat( - result, + result, uint(uint8(bitmapArr[i])).toString(), ", " ); diff --git a/test/integration/utils/Sort.t.sol b/test/integration/utils/Sort.t.sol index 46a2fc2b..968400c6 100644 --- a/test/integration/utils/Sort.t.sol +++ b/test/integration/utils/Sort.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; library Sort { /** diff --git a/test/mocks/AVSDirectoryMock.sol b/test/mocks/AVSDirectoryMock.sol index 5e4c6f77..ca3613ef 100644 --- a/test/mocks/AVSDirectoryMock.sol +++ b/test/mocks/AVSDirectoryMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IAVSDirectory } from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; diff --git a/test/mocks/AllocationManagerMock.sol b/test/mocks/AllocationManagerMock.sol index fdb11248..b355af95 100644 --- a/test/mocks/AllocationManagerMock.sol +++ b/test/mocks/AllocationManagerMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IAllocationManager, OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IAVSRegistrar } from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; diff --git a/test/mocks/DelegationMock.sol b/test/mocks/DelegationMock.sol index 23ad0bb5..e3b1ed77 100644 --- a/test/mocks/DelegationMock.sol +++ b/test/mocks/DelegationMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {console2 as console} from "forge-std/Test.sol"; @@ -267,6 +267,6 @@ contract DelegationMock is DelegationIntermediate { return shares; } function minWithdrawalDelayBlocks() external view override returns (uint32){ - return 100; + return 10000; } } \ No newline at end of file diff --git a/test/mocks/ECDSAServiceManagerMock.sol b/test/mocks/ECDSAServiceManagerMock.sol index 2c3c872b..102d076e 100644 --- a/test/mocks/ECDSAServiceManagerMock.sol +++ b/test/mocks/ECDSAServiceManagerMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/unaudited/ECDSAServiceManagerBase.sol"; import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; @@ -28,7 +28,11 @@ contract ECDSAServiceManagerMock is ECDSAServiceManagerBase { __ServiceManagerBase_init(initialOwner, rewardsInitiator); } - function createOperatorSets(uint32[] memory) external {} + function createOperatorSets(IAllocationManager.CreateSetParams[] memory params) external{} + + function addStrategyToOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) external{} + + function removeStrategiesFromOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) external{} function registerOperatorToOperatorSets( address operator, diff --git a/test/mocks/ECDSAStakeRegistryMock.sol b/test/mocks/ECDSAStakeRegistryMock.sol index 7ad6043e..e2b756be 100644 --- a/test/mocks/ECDSAStakeRegistryMock.sol +++ b/test/mocks/ECDSAStakeRegistryMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/unaudited/ECDSAStakeRegistry.sol"; diff --git a/test/mocks/PermissionControllerMock.sol b/test/mocks/PermissionControllerMock.sol index 7501a9fa..9a9eca00 100644 --- a/test/mocks/PermissionControllerMock.sol +++ b/test/mocks/PermissionControllerMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IPermissionController} from "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; diff --git a/test/mocks/RegistryCoordinatorMock.sol b/test/mocks/RegistryCoordinatorMock.sol index 73308f14..165a649d 100644 --- a/test/mocks/RegistryCoordinatorMock.sol +++ b/test/mocks/RegistryCoordinatorMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/interfaces/IRegistryCoordinator.sol"; @@ -9,7 +9,7 @@ contract RegistryCoordinatorMock is IRegistryCoordinator { function blsApkRegistry() external view returns (IBLSApkRegistry) {} function ejectOperator( - address operator, + address operator, bytes calldata quorumNumbers ) external {} @@ -70,4 +70,12 @@ contract RegistryCoordinatorMock is IRegistryCoordinator { function owner() external view returns (address) {} function serviceManager() external view returns (IServiceManager){} + + function isM2Quorum(uint8 quorumNumber) external view returns (bool) { + return false; + } + + function isOperatorSetAVS() external view returns (bool) { + return false; + } } \ No newline at end of file diff --git a/test/mocks/RewardsCoordinatorMock.sol b/test/mocks/RewardsCoordinatorMock.sol index e408c421..9d992962 100644 --- a/test/mocks/RewardsCoordinatorMock.sol +++ b/test/mocks/RewardsCoordinatorMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; diff --git a/test/mocks/ServiceManagerMock.sol b/test/mocks/ServiceManagerMock.sol index a9bb5fff..a60e63c8 100644 --- a/test/mocks/ServiceManagerMock.sol +++ b/test/mocks/ServiceManagerMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/ServiceManagerBase.sol"; diff --git a/test/mocks/StakeRegistryMock.sol b/test/mocks/StakeRegistryMock.sol index 2dcecce3..58f46256 100644 --- a/test/mocks/StakeRegistryMock.sol +++ b/test/mocks/StakeRegistryMock.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/interfaces/IStakeRegistry.sol"; import "../../src/interfaces/IRegistryCoordinator.sol"; diff --git a/test/unit/BLSApkRegistryUnit.t.sol b/test/unit/BLSApkRegistryUnit.t.sol index 2a8be4c7..aacfe9d8 100644 --- a/test/unit/BLSApkRegistryUnit.t.sol +++ b/test/unit/BLSApkRegistryUnit.t.sol @@ -1,5 +1,5 @@ //SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; import "../harnesses/BLSApkRegistryHarness.sol"; diff --git a/test/unit/BLSSignatureCheckerUnit.t.sol b/test/unit/BLSSignatureCheckerUnit.t.sol index 6056b283..74b8f1da 100644 --- a/test/unit/BLSSignatureCheckerUnit.t.sol +++ b/test/unit/BLSSignatureCheckerUnit.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/BLSSignatureChecker.sol"; import "../utils/BLSMockAVSDeployer.sol"; diff --git a/test/unit/BitmapUtils.t.sol b/test/unit/BitmapUtils.t.sol index fd51298d..fcd742b2 100644 --- a/test/unit/BitmapUtils.t.sol +++ b/test/unit/BitmapUtils.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../harnesses/BitmapUtilsWrapper.sol"; // import "../../contracts/libraries/BitmapUtils.sol"; @@ -24,7 +24,7 @@ contract BitmapUtilsUnitTests_bitwiseOperations is BitmapUtilsUnitTests { uint16 numOnes = 0; for (uint256 i = 0; i < 256; ++i) { if ((input >> i) & 1 == 1) { - ++numOnes; + ++numOnes; } } assertEq(libraryOutput, numOnes, "inconsistency in countNumOnes function"); diff --git a/test/unit/ECDSAServiceManager.t.sol b/test/unit/ECDSAServiceManager.t.sol index 4cb283fc..bcd17052 100644 --- a/test/unit/ECDSAServiceManager.t.sol +++ b/test/unit/ECDSAServiceManager.t.sol @@ -1,5 +1,5 @@ // // SPDX-License-Identifier: MIT -// pragma solidity ^0.8.12; +// pragma solidity ^0.8.27; // import {Test, console} from "forge-std/Test.sol"; diff --git a/test/unit/ECDSAStakeRegistryEqualWeightUnit.t.sol b/test/unit/ECDSAStakeRegistryEqualWeightUnit.t.sol index bc6337c5..0008da7f 100644 --- a/test/unit/ECDSAStakeRegistryEqualWeightUnit.t.sol +++ b/test/unit/ECDSAStakeRegistryEqualWeightUnit.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; diff --git a/test/unit/ECDSAStakeRegistryPermissionedUnit.t.sol b/test/unit/ECDSAStakeRegistryPermissionedUnit.t.sol index dffb9174..8205034d 100644 --- a/test/unit/ECDSAStakeRegistryPermissionedUnit.t.sol +++ b/test/unit/ECDSAStakeRegistryPermissionedUnit.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; diff --git a/test/unit/ECDSAStakeRegistryUnit.t.sol b/test/unit/ECDSAStakeRegistryUnit.t.sol index d374144d..e1d7de77 100644 --- a/test/unit/ECDSAStakeRegistryUnit.t.sol +++ b/test/unit/ECDSAStakeRegistryUnit.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {Test, console} from "forge-std/Test.sol"; diff --git a/test/unit/EjectionManagerUnit.t.sol b/test/unit/EjectionManagerUnit.t.sol index 456fe58b..9f01af50 100644 --- a/test/unit/EjectionManagerUnit.t.sol +++ b/test/unit/EjectionManagerUnit.t.sol @@ -1,6 +1,6 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {EjectionManager} from "../../src/EjectionManager.sol"; import {IEjectionManager} from "../../src/interfaces/IEjectionManager.sol"; diff --git a/test/unit/IndexRegistryUnit.t.sol b/test/unit/IndexRegistryUnit.t.sol index fe034c0e..36d7dc69 100644 --- a/test/unit/IndexRegistryUnit.t.sol +++ b/test/unit/IndexRegistryUnit.t.sol @@ -1,5 +1,5 @@ //SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/interfaces/IIndexRegistry.sol"; import "../../src/IndexRegistry.sol"; diff --git a/test/unit/LibMergeSort.t.sol b/test/unit/LibMergeSort.t.sol index f3014d3f..dc2ddf7d 100644 --- a/test/unit/LibMergeSort.t.sol +++ b/test/unit/LibMergeSort.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; import "../../src/libraries/LibMergeSort.sol"; diff --git a/test/unit/OperatorStateRetrieverUnit.t.sol b/test/unit/OperatorStateRetrieverUnit.t.sol index 2fe360ca..e25c8af0 100644 --- a/test/unit/OperatorStateRetrieverUnit.t.sol +++ b/test/unit/OperatorStateRetrieverUnit.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../utils/MockAVSDeployer.sol"; diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index 9fedcd1f..c3c8032d 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../utils/MockAVSDeployer.sol"; +import {IRegistryCoordinatorErrors} from "../../src/interfaces/IRegistryCoordinator.sol"; contract RegistryCoordinatorUnitTests is MockAVSDeployer { using BN254 for BN254.G1Point; @@ -120,7 +121,7 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina ); } - // make sure the contract intializers are disabled + // make sure the contract initializers are disabled cheats.expectRevert(bytes("Initializable: contract is already initialized")); registryCoordinator.initialize( registryCoordinatorOwner, @@ -198,7 +199,7 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina function test_updateSocket_revert_notRegistered() public { cheats.prank(defaultOperator); - cheats.expectRevert("RegistryCoordinator.updateSocket: not registered"); + cheats.expectRevert(bytes4(keccak256("NotRegistered()"))); registryCoordinator.updateSocket("localhost:32004"); } @@ -269,7 +270,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni bytes memory emptyQuorumNumbers = new bytes(0); ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; - cheats.expectRevert("RegistryCoordinator._registerOperator: bitmap empty"); + cheats.expectRevert(bytes4(keccak256("BitmapEmpty()"))); cheats.prank(defaultOperator); registryCoordinator.registerOperator(emptyQuorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); } @@ -483,7 +484,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni _setOperatorWeight(operatorToRegister, defaultQuorumNumber, defaultStake); cheats.prank(operatorToRegister); - cheats.expectRevert("RegistryCoordinator.registerOperator: operator exceeds max"); + cheats.expectRevert(bytes4(keccak256("MaxQuorumsReached()"))); registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); } @@ -503,8 +504,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni cheats.prank(defaultOperator); cheats.roll(nextRegistrationBlockNumber); - cheats.expectRevert("RegistryCoordinator._registerOperator: operator already registered for some quorums being registered for"); - + cheats.expectRevert(bytes4(keccak256("AlreadyRegisteredForQuorums()"))); registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); } @@ -513,7 +513,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni bytes memory emptyQuorumNumbers = new bytes(0); ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; - cheats.expectRevert("RegistryCoordinator._registerOperator: bitmap empty"); + cheats.expectRevert(bytes4(keccak256("BitmapEmpty()"))); registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, emptyQuorumNumbers, defaultSocket, emptySig); } @@ -535,7 +535,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, quorumNumbers, defaultSocket, emptySig); - cheats.expectRevert("RegistryCoordinator._registerOperator: operator already registered for some quorums being registered for"); + cheats.expectRevert(bytes4(keccak256("AlreadyRegisteredForQuorums()"))); registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, quorumNumbers, defaultSocket, emptySig); } @@ -601,7 +601,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); - cheats.expectRevert("RegistryCoordinator._deregisterOperator: not registered"); + cheats.expectRevert(bytes4(keccak256("NotRegistered()"))); cheats.prank(defaultOperator); registryCoordinator.deregisterOperator(quorumNumbers); } @@ -617,7 +617,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist quorumNumbers[0] = bytes1(defaultQuorumNumber + 1); quorumNumbers[1] = bytes1(defaultQuorumNumber + 2); - cheats.expectRevert("RegistryCoordinator._deregisterOperator: not registered for quorum"); + cheats.expectRevert(bytes4(keccak256("NotRegisteredForQuorum()"))); cheats.prank(defaultOperator); registryCoordinator.deregisterOperator(quorumNumbers); } @@ -957,13 +957,13 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist bytes memory emptyQuorumNumbers = new bytes(0); cheats.roll(deregistrationBlockNumber); - cheats.expectRevert("RegistryCoordinator._deregisterOperator: bitmap cannot be 0"); + cheats.expectRevert(bytes4(keccak256("BitmapCannotBeZero()"))); registryCoordinator._deregisterOperatorExternal(defaultOperator, emptyQuorumNumbers); } function test_deregisterOperatorExternal_revert_notRegistered() public { bytes memory emptyQuorumNumbers = new bytes(0); - cheats.expectRevert("RegistryCoordinator._deregisterOperator: not registered"); + cheats.expectRevert(bytes4(keccak256("NotRegistered()"))); registryCoordinator._deregisterOperatorExternal(defaultOperator, emptyQuorumNumbers); } @@ -985,7 +985,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist incorrectQuorum[0] = bytes1(defaultQuorumNumber + 1); cheats.roll(deregistrationBlockNumber); - cheats.expectRevert("RegistryCoordinator._deregisterOperator: not registered for quorum"); + cheats.expectRevert(bytes4(keccak256("NotRegisteredForQuorum()"))); registryCoordinator._deregisterOperatorExternal(defaultOperator, incorrectQuorum); } @@ -1013,7 +1013,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.prank(defaultOperator); cheats.roll(reregistrationBlockNumber); - cheats.expectRevert("RegistryCoordinator._registerOperator: operator cannot reregister yet"); + cheats.expectRevert(bytes4(keccak256("CannotReregisterYet()"))); registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); } @@ -1214,7 +1214,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.prank(defaultOperator); registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); - cheats.expectRevert("RegistryCoordinator.onlyEjector: not ejector"); + cheats.expectRevert(bytes4(keccak256("OnlyEjector()"))); cheats.prank(defaultOperator); registryCoordinator.ejectOperator(defaultOperator, quorumNumbers); } @@ -1463,7 +1463,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ISignatureUtils.SignatureWithSaltAndExpiry memory signatureWithExpiry = _signOperatorChurnApproval(operatorToRegister, operatorToRegisterId, operatorKickParams, defaultSalt, block.timestamp + 10); cheats.prank(operatorToRegister); - cheats.expectRevert("RegistryCoordinator._validateChurn: incoming operator has insufficient stake for churn"); + cheats.expectRevert(bytes4(keccak256("InsufficientStakeForChurn()"))); registryCoordinator.registerOperatorWithChurn( quorumNumbers, defaultSocket, @@ -1495,7 +1495,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ISignatureUtils.SignatureWithSaltAndExpiry memory signatureWithExpiry = _signOperatorChurnApproval(operatorToRegister, operatorToRegisterId, operatorKickParams, defaultSalt, block.timestamp + 10); cheats.prank(operatorToRegister); - cheats.expectRevert("RegistryCoordinator._validateChurn: cannot kick operator with more than kickBIPsOfTotalStake"); + cheats.expectRevert(bytes4(keccak256("CannotKickOperatorAboveThreshold()"))); registryCoordinator.registerOperatorWithChurn( quorumNumbers, defaultSocket, @@ -1557,7 +1557,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ISignatureUtils.SignatureWithSaltAndExpiry memory signatureWithSaltAndExpiry = _signOperatorChurnApproval(operatorToRegister, operatorToRegisterId, operatorKickParams, defaultSalt, block.timestamp - 1); cheats.prank(operatorToRegister); - cheats.expectRevert("RegistryCoordinator._verifyChurnApproverSignature: signature expired"); + cheats.expectRevert(bytes4(keccak256("SignatureExpired()"))); registryCoordinator.registerOperatorWithChurn( quorumNumbers, defaultSocket, @@ -1678,7 +1678,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); - cheats.expectRevert(bytes("RegistryCoordinator.updateOperatorsForQuorum: input length mismatch")); + cheats.expectRevert(bytes4(keccak256("InputLengthMismatch()"))); registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); } @@ -1690,7 +1690,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); - cheats.expectRevert(bytes("RegistryCoordinator.updateOperatorsForQuorum: number of updated operators does not match quorum total")); + cheats.expectRevert(bytes4(keccak256("QuorumOperatorCountMismatch()"))); registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); } @@ -1711,7 +1711,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit operatorArray[0] = _incrementAddress(defaultOperator, 1); operatorsToUpdate[0] = operatorArray; - cheats.expectRevert(bytes("RegistryCoordinator.updateOperatorsForQuorum: operator not in quorum")); + cheats.expectRevert(bytes4(keccak256("NotRegisteredForQuorum()"))); registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); } @@ -1739,7 +1739,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit operatorsToUpdate[0] = operatorArray; // note: there is not an explicit check for duplicates, as checking for explicit ordering covers this - cheats.expectRevert(bytes("RegistryCoordinator.updateOperatorsForQuorum: operators must be sorted")); + cheats.expectRevert(bytes4(keccak256("NotSorted()"))); registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); } @@ -1765,7 +1765,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit operatorArray[1] = defaultOperator; operatorsToUpdate[0] = operatorArray; - cheats.expectRevert(bytes("RegistryCoordinator.updateOperatorsForQuorum: operators must be sorted")); + cheats.expectRevert(bytes4(keccak256("NotSorted()"))); registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); } diff --git a/test/unit/ServiceManagerBase.t.sol b/test/unit/ServiceManagerBase.t.sol index c7ac91e9..8d37f9d6 100644 --- a/test/unit/ServiceManagerBase.t.sol +++ b/test/unit/ServiceManagerBase.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; import { diff --git a/test/unit/ServiceManagerRouter.t.sol b/test/unit/ServiceManagerRouter.t.sol index 6706ade4..5cf1d3b7 100644 --- a/test/unit/ServiceManagerRouter.t.sol +++ b/test/unit/ServiceManagerRouter.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {ServiceManagerRouter} from "../../src/ServiceManagerRouter.sol"; import "../utils/MockAVSDeployer.sol"; diff --git a/test/unit/StakeRegistryUnit.t.sol b/test/unit/StakeRegistryUnit.t.sol index 6fbe8609..a4f58b85 100644 --- a/test/unit/StakeRegistryUnit.t.sol +++ b/test/unit/StakeRegistryUnit.t.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; diff --git a/test/unit/Utils.sol b/test/unit/Utils.sol index c143633d..6e085215 100644 --- a/test/unit/Utils.sol +++ b/test/unit/Utils.sol @@ -1,4 +1,4 @@ -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; diff --git a/test/utils/BLSMockAVSDeployer.sol b/test/utils/BLSMockAVSDeployer.sol index 14339d55..7923fca4 100644 --- a/test/utils/BLSMockAVSDeployer.sol +++ b/test/utils/BLSMockAVSDeployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import {BLSSignatureChecker} from "../../src/BLSSignatureChecker.sol"; import {MockAVSDeployer} from "../utils/MockAVSDeployer.sol"; diff --git a/test/utils/MockAVSDeployer.sol b/test/utils/MockAVSDeployer.sol index 226502ed..800628da 100644 --- a/test/utils/MockAVSDeployer.sol +++ b/test/utils/MockAVSDeployer.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; diff --git a/test/utils/Operators.sol b/test/utils/Operators.sol index 95ab65e9..266ed8d8 100644 --- a/test/utils/Operators.sol +++ b/test/utils/Operators.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/libraries/BN254.sol"; import "forge-std/Test.sol"; @@ -50,12 +50,12 @@ contract Operators is Test { X: [ readUint(operatorConfigJson, index, "PubkeyG2.X.A1"), readUint(operatorConfigJson, index, "PubkeyG2.X.A0") - ], + ], Y: [ readUint(operatorConfigJson, index, "PubkeyG2.Y.A1"), readUint(operatorConfigJson, index, "PubkeyG2.Y.A0") ] - }); + }); return pubkey; } @@ -68,7 +68,7 @@ contract Operators is Test { uint256 result = 0; for (uint256 i = 0; i < b.length; i++) { if (uint256(uint8(b[i])) >= 48 && uint256(uint8(b[i])) <= 57) { - result = result * 10 + (uint256(uint8(b[i])) - 48); + result = result * 10 + (uint256(uint8(b[i])) - 48); } } return result; diff --git a/test/utils/Owners.sol b/test/utils/Owners.sol index edb577d4..cdb3add2 100644 --- a/test/utils/Owners.sol +++ b/test/utils/Owners.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "forge-std/Test.sol"; import "forge-std/Script.sol"; @@ -29,7 +29,7 @@ contract Owners is Test { for (uint256 i = 0; i < getNumOperators(); i++) { addresses.push(getOwnerAddress(i)); } - return addresses; + return addresses; } function getReputedOwnerAddresses() public returns(address[] memory) { @@ -37,11 +37,11 @@ contract Owners is Test { for (uint256 i = 0; i < getNumOperators(); i++) { addresses.push(getOwnerAddress(i)); } - return addresses; + return addresses; } function resetOwnersConfigJson(string memory newConfig) public { ownersConfigJson = vm.readFile(newConfig); } - + } diff --git a/test/utils/ProofParsing.sol b/test/utils/ProofParsing.sol index f331c2a1..14ad89c6 100644 --- a/test/utils/ProofParsing.sol +++ b/test/utils/ProofParsing.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "../../src/libraries/BN254.sol"; import "forge-std/Test.sol"; @@ -83,7 +83,7 @@ contract ProofParsing is Test{ function getExecutionPayloadProof () public returns(bytes32[7] memory) { for (uint i = 0; i < 7; i++) { prefix = string.concat(".ExecutionPayloadProof[", string.concat(vm.toString(i), "]")); - executionPayloadProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); + executionPayloadProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return executionPayloadProof; } @@ -91,7 +91,7 @@ contract ProofParsing is Test{ function getTimestampProof() public returns(bytes32[4] memory) { for (uint i = 0; i < 4; i++) { prefix = string.concat(".TimestampProof[", string.concat(vm.toString(i), "]")); - timestampProofs[i] = (stdJson.readBytes32(proofConfigJson, prefix)); + timestampProofs[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return timestampProofs; } @@ -99,7 +99,7 @@ contract ProofParsing is Test{ function getBlockHeaderProof() public returns(bytes32[18] memory) { for (uint i = 0; i < 18; i++) { prefix = string.concat(".BlockHeaderProof[", string.concat(vm.toString(i), "]")); - blockHeaderProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); + blockHeaderProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return blockHeaderProof; } @@ -107,7 +107,7 @@ contract ProofParsing is Test{ function getSlotProof() public returns(bytes32[3] memory) { for (uint i = 0; i < 3; i++) { prefix = string.concat(".SlotProof[", string.concat(vm.toString(i), "]")); - slotProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); + slotProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return slotProof; } @@ -116,7 +116,7 @@ contract ProofParsing is Test{ bytes32[] memory stateRootProof = new bytes32[](3); for (uint i = 0; i < 3; i++) { prefix = string.concat(".StateRootAgainstLatestBlockHeaderProof[", string.concat(vm.toString(i), "]")); - stateRootProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); + stateRootProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return stateRootProof; } @@ -124,7 +124,7 @@ contract ProofParsing is Test{ function getWithdrawalProof() public returns(bytes32[9] memory) { for (uint i = 0; i < 9; i++) { prefix = string.concat(".WithdrawalProof[", string.concat(vm.toString(i), "]")); - withdrawalProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); + withdrawalProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return withdrawalProof; } @@ -132,7 +132,7 @@ contract ProofParsing is Test{ function getValidatorProof() public returns(bytes32[46] memory) { for (uint i = 0; i < 46; i++) { prefix = string.concat(".ValidatorProof[", string.concat(vm.toString(i), "]")); - validatorProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); + validatorProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return validatorProof; } @@ -140,16 +140,16 @@ contract ProofParsing is Test{ function getHistoricalSummaryProof() public returns(bytes32[44] memory) { for (uint i = 0; i < 44; i++) { prefix = string.concat(".HistoricalSummaryProof[", string.concat(vm.toString(i), "]")); - historicalSummaryProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); + historicalSummaryProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return historicalSummaryProof; } - + function getWithdrawalFields() public returns(bytes32[] memory) { bytes32[] memory withdrawalFields = new bytes32[](4); for (uint i = 0; i < 4; i++) { prefix = string.concat(".WithdrawalFields[", string.concat(vm.toString(i), "]")); - withdrawalFields[i] = (stdJson.readBytes32(proofConfigJson, prefix)); + withdrawalFields[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return withdrawalFields; @@ -159,7 +159,7 @@ contract ProofParsing is Test{ bytes32[] memory validatorFields = new bytes32[](8); for (uint i = 0; i < 8; i++) { prefix = string.concat(".ValidatorFields[", string.concat(vm.toString(i), "]")); - validatorFields[i] = (stdJson.readBytes32(proofConfigJson, prefix)); + validatorFields[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return validatorFields; } @@ -168,7 +168,7 @@ contract ProofParsing is Test{ bytes32[] memory validatorBalanceProof = new bytes32[](44); for (uint i = 0; i < 44; i++) { prefix = string.concat(".ValidatorBalanceProof[", string.concat(vm.toString(i), "]")); - validatorBalanceProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); + validatorBalanceProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return validatorBalanceProof; } @@ -177,7 +177,7 @@ contract ProofParsing is Test{ bytes32[] memory balanceUpdateSlotProof = new bytes32[](5); for (uint i = 0; i < 5; i++) { prefix = string.concat(".slotProof[", string.concat(vm.toString(i), "]")); - balanceUpdateSlotProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); + balanceUpdateSlotProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return balanceUpdateSlotProof; } @@ -186,7 +186,7 @@ contract ProofParsing is Test{ bytes32[] memory withdrawalCredenitalProof = new bytes32[](46); for (uint i = 0; i < 46; i++) { prefix = string.concat(".WithdrawalCredentialProof[", string.concat(vm.toString(i), "]")); - withdrawalCredenitalProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); + withdrawalCredenitalProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return withdrawalCredenitalProof; } @@ -195,7 +195,7 @@ contract ProofParsing is Test{ bytes32[] memory validatorFieldsProof = new bytes32[](46); for (uint i = 0; i < 46; i++) { prefix = string.concat(".ValidatorFieldsProof[", string.concat(vm.toString(i), "]")); - validatorFieldsProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); + validatorFieldsProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return validatorFieldsProof; } diff --git a/test/utils/SignatureCompaction.sol b/test/utils/SignatureCompaction.sol index c10b2db1..0bb98a1c 100644 --- a/test/utils/SignatureCompaction.sol +++ b/test/utils/SignatureCompaction.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.12; +pragma solidity ^0.8.27; import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; From 1cc4983adebafdef3c74a6f491ccb187369cc47b Mon Sep 17 00:00:00 2001 From: steven Date: Mon, 16 Dec 2024 09:58:04 -0500 Subject: [PATCH 32/52] chore: bump core dependency --- lib/eigenlayer-contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/eigenlayer-contracts b/lib/eigenlayer-contracts index 881485b0..85e12bab 160000 --- a/lib/eigenlayer-contracts +++ b/lib/eigenlayer-contracts @@ -1 +1 @@ -Subproject commit 881485b008a61b8512172192214b88b873b9dc61 +Subproject commit 85e12bab5f3d4c6ff21790fe5909755ee7154b07 From 44e1a40b40ebb352a1ce9a9b527fd70d1e2cad83 Mon Sep 17 00:00:00 2001 From: steven Date: Wed, 18 Dec 2024 16:51:18 -0500 Subject: [PATCH 33/52] chore: bump forge-std --- lib/forge-std | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/forge-std b/lib/forge-std index bb4ceea9..1eea5bae 160000 --- a/lib/forge-std +++ b/lib/forge-std @@ -1 +1 @@ -Subproject commit bb4ceea94d6f10eeb5b41dc2391c6c8bf8e734ef +Subproject commit 1eea5bae12ae557d589f9f0f0edae2faa47cb262 From 865b49015652a3dd3ba28b666d15c4a68eb23670 Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Thu, 19 Dec 2024 12:20:45 -0500 Subject: [PATCH 34/52] docs: update readme with note on slashing (#341) --- README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f33b6920..62b879a8 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ EigenLayer is a set of smart contracts deployed on Ethereum that enable restakin ## Branching The main branches we use are: + * [`dev (default)`](https://github.com/Layr-Labs/eigenlayer-middleware/tree/dev): The most up-to-date branch, containing the work-in-progress code for upcoming releases * [`testnet-holesky`](https://github.com/Layr-Labs/eigenlayer-middleware/tree/testnet-holesky): Our current testnet deployment * [`mainnet`](https://github.com/Layr-Labs/eigenlayer-middleware/tree/mainnet): Our current mainnet deployment @@ -24,6 +25,7 @@ The main branches we use are: ### Basics To get a basic understanding of EigenLayer, check out [You Could've Invented EigenLayer](https://www.blog.eigenlayer.xyz/ycie/). Note that some of the document's content describes features that do not exist yet (like the Slasher). To understand more about how restakers and operators interact with EigenLayer, check out these guides: + * [Restaking User Guide](https://docs.eigenlayer.xyz/restaking-guides/restaking-user-guide) * [Operator Guide](https://docs.eigenlayer.xyz/operator-guides/operator-introduction) @@ -32,10 +34,25 @@ Most of this content is intro-level and describes user interactions with the Eig ### Deep Dive For shadowy super-coders: + * The most up-to-date technical documentation can be found in [/docs](/docs). * To get an idea of how users interact with these contracts, check out the integration tests: [/test/integration](./test/integration) * To explore the EigenLayer core contracts, check out the core repo technical docs [here][core-docs-dev]. +### Note On Slashing + +The middleware contracts are available for testnet integration and experimentation. As with the rest of the testnet code, these contracts have not yet been fully audited. Internal security reviews are in progress, and we're preparing to engage external auditors. We're providing these now so AVSs can begin testing slashing conditions, Operator Sets, and related functionality, and so Operators can simulate slashing and test allocations. For more details, see [ELIP-002](https://github.com/eigenfoundation/ELIPs/blob/main/ELIPs/ELIP-002.md). + +For Operators: + +We provide scripts to deploy a mock service manager and allocate some stake to a mock Operator Set in [these scripts](https://github.com/Layr-Labs/eigenlayer-middleware/pull/335). +We've reduced various safety delays on testnet to better simulate operational flows. Additional information on these delays is in [ELIP-002](https://github.com/eigenfoundation/ELIPs/blob/main/ELIPs/ELIP-002.md). +For AVSs: + +We provide a migration path for existing M2 environments (LINK). While this requires understanding the provided script, the Developer Experience will improve before Mainnet launch. Note that this is a gradual migration process to new Operator Sets, not a direct upgrade of existing Operator Sets. +We also provide scripts to spin up new service managers from scratch. +In all cases, you’ll need to register existing Operators or spin up new Operators and allocate funds to them. These testing flows will improve as we refine the scripts and contracts. Stay tuned for updates, and feel free to reach out with any questions. + ## Building and Running Tests This repository uses Foundry. See the [Foundry docs](https://book.getfoundry.sh/) for more info on installation and usage. If you already have foundry, you can build this project and run tests with these commands: @@ -80,4 +97,3 @@ The current testnet deployment is on holesky, is from our M2 beta release. You c [`ServiceManagerRouter`](https://github.com/Layr-Labs/eigenlayer-middleware/blob/testnet-holesky/src/ServiceManagerRouter.sol) | - | [`0x4463...5a37`](https://holesky.etherscan.io/address/0x44632dfBdCb6D3E21EF613B0ca8A6A0c618F5a37#code) | | [`ProxyAdmin`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/ProxyAdmin.sol) | - | [`0xB043...5c15`](https://holesky.etherscan.io/address/0xB043055dd967A382577c2f5261fA6428f2905c15) | | [`eigenda/EigenDAServiceManager`](https://github.com/Layr-Labs/eigenda/blob/a33b41561cc3fb4cd6d50a8738e4c5dca43ec0a5/contracts/src/core/EigenDAServiceManager.sol) | [`0xD4A7E1Bd8015057293f0D0A557088c286942e84b`](https://holesky.etherscan.io/address/0xD4A7E1Bd8015057293f0D0A557088c286942e84b) | [`0xa722...67f3`](https://holesky.etherscan.io/address/0xa7227485e6C693AC4566fe168C5E3647c5c267f3) | Proxy: [`TUP@4.7.1`](https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/proxy/transparent/TransparentUpgradeableProxy.sol) | - From d54835c0694c6453e25f05b469486785381c049f Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Wed, 8 Jan 2025 08:15:49 -0500 Subject: [PATCH 35/52] chore: bump core fix iface changes (#352) * chore: bump dep * fix: iface changes and param names --- lib/eigenlayer-contracts | 2 +- test/integration/User.t.sol | 2 +- test/mocks/DelegationMock.sol | 39 +++++++++++++++++++++++++----- test/mocks/EigenPodManagerMock.sol | 6 +++++ 4 files changed, 41 insertions(+), 8 deletions(-) diff --git a/lib/eigenlayer-contracts b/lib/eigenlayer-contracts index 85e12bab..22de8094 160000 --- a/lib/eigenlayer-contracts +++ b/lib/eigenlayer-contracts @@ -1 +1 @@ -Subproject commit 85e12bab5f3d4c6ff21790fe5909755ee7154b07 +Subproject commit 22de809403924707ccce6998e62b868bfae0fc58 diff --git a/test/integration/User.t.sol b/test/integration/User.t.sol index 4b58950a..23e9ffcc 100644 --- a/test/integration/User.t.sol +++ b/test/integration/User.t.sol @@ -271,7 +271,7 @@ contract User is Test { params[0] = IDelegationManagerTypes.QueuedWithdrawalParams({ strategies: strategies, depositShares: shares, - withdrawer: address(this) + __deprecated_withdrawer: address(this) }); delegationManager.queueWithdrawals(params); diff --git a/test/mocks/DelegationMock.sol b/test/mocks/DelegationMock.sol index e3b1ed77..36f973da 100644 --- a/test/mocks/DelegationMock.sol +++ b/test/mocks/DelegationMock.sol @@ -232,13 +232,40 @@ contract DelegationIntermediate is IDelegationManager { uint256 wadSlashed ) external virtual {} - function decreaseDelegatedShares( - address staker, - uint256 curDepositShares, - uint64 beaconChainSlashingFactorDecrease - ) external virtual {} + function decreaseDelegatedShares( + address staker, + uint256 curDepositShares, + uint64 beaconChainSlashingFactorDecrease + ) external virtual {} + + function minWithdrawalDelayBlocks() + external + view + virtual + override + returns (uint32) + {} - function minWithdrawalDelayBlocks() external view virtual override returns (uint32) {} + function slashOperatorShares( + address operator, + IStrategy strategy, + uint64 prevMaxMagnitude, + uint64 newMaxMagnitude + ) external override {} + + function getQueuedWithdrawal( + bytes32 withdrawalRoot + ) external view override returns (Withdrawal memory) {} + + function getQueuedWithdrawalRoots( + address staker + ) external view override returns (bytes32[] memory) {} + + function convertToDepositShares( + address staker, + IStrategy[] memory strategies, + uint256[] memory withdrawableShares + ) external view override returns (uint256[] memory) {} } contract DelegationMock is DelegationIntermediate { diff --git a/test/mocks/EigenPodManagerMock.sol b/test/mocks/EigenPodManagerMock.sol index cefd5b7a..700d1840 100644 --- a/test/mocks/EigenPodManagerMock.sol +++ b/test/mocks/EigenPodManagerMock.sol @@ -94,4 +94,10 @@ contract EigenPodManagerMock is Test, Pausable, IEigenPodManager { int256 balanceDeltaWei ) external { } + + function burnableETHShares() external view returns (uint256) { + } + + function increaseBurnableShares(IStrategy strategy, uint256 addedSharesToBurn) external { + } } \ No newline at end of file From cbcc0a4a18b36ccd861d5901f2026a7aa2a29b3c Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Wed, 8 Jan 2025 15:08:42 -0500 Subject: [PATCH 36/52] feat: ci storage reports (#347) * feat: storage reports * fix: storage report * fix: storage report * fix: ci * fix: ci * fix: ci * fix: ci * fix: ci --- .github/bin/storage-report.sh | 45 +++++++++++++++++ .github/workflows/storage-report.yml | 48 ++++++++++++++++++ Makefile | 2 + bin/storage-report.sh | 45 +++++++++++++++++ docs/storage-report/AVSRegistrar.md | 6 +++ docs/storage-report/BLSApkRegistry.md | 21 ++++++++ docs/storage-report/BLSApkRegistryStorage.md | 21 ++++++++ docs/storage-report/BLSSignatureChecker.md | 9 ++++ .../storage-report/ECDSAServiceManagerBase.md | 19 +++++++ docs/storage-report/ECDSAStakeRegistry.md | 37 ++++++++++++++ .../ECDSAStakeRegistryEqualWeight.md | 39 +++++++++++++++ .../ECDSAStakeRegistryPermissioned.md | 39 +++++++++++++++ .../ECDSAStakeRegistryStorage.md | 27 ++++++++++ docs/storage-report/EjectionManager.md | 21 ++++++++ docs/storage-report/IndexRegistry.md | 17 +++++++ docs/storage-report/IndexRegistryStorage.md | 17 +++++++ docs/storage-report/InstantSlasher.md | 17 +++++++ docs/storage-report/OperatorStateRetriever.md | 6 +++ docs/storage-report/RegistryCoordinator.md | 49 +++++++++++++++++++ .../RegistryCoordinatorStorage.md | 33 +++++++++++++ docs/storage-report/ServiceManagerBase.md | 27 ++++++++++ .../ServiceManagerBaseStorage.md | 27 ++++++++++ docs/storage-report/ServiceManagerRouter.md | 6 +++ docs/storage-report/SlasherBase.md | 17 +++++++ docs/storage-report/SlasherStorage.md | 13 +++++ docs/storage-report/StakeRegistry.md | 21 ++++++++ docs/storage-report/StakeRegistryStorage.md | 21 ++++++++ docs/storage-report/VetoableSlasher.md | 0 28 files changed, 650 insertions(+) create mode 100644 .github/bin/storage-report.sh create mode 100644 .github/workflows/storage-report.yml create mode 100644 Makefile create mode 100644 bin/storage-report.sh create mode 100644 docs/storage-report/AVSRegistrar.md create mode 100644 docs/storage-report/BLSApkRegistry.md create mode 100644 docs/storage-report/BLSApkRegistryStorage.md create mode 100644 docs/storage-report/BLSSignatureChecker.md create mode 100644 docs/storage-report/ECDSAServiceManagerBase.md create mode 100644 docs/storage-report/ECDSAStakeRegistry.md create mode 100644 docs/storage-report/ECDSAStakeRegistryEqualWeight.md create mode 100644 docs/storage-report/ECDSAStakeRegistryPermissioned.md create mode 100644 docs/storage-report/ECDSAStakeRegistryStorage.md create mode 100644 docs/storage-report/EjectionManager.md create mode 100644 docs/storage-report/IndexRegistry.md create mode 100644 docs/storage-report/IndexRegistryStorage.md create mode 100644 docs/storage-report/InstantSlasher.md create mode 100644 docs/storage-report/OperatorStateRetriever.md create mode 100644 docs/storage-report/RegistryCoordinator.md create mode 100644 docs/storage-report/RegistryCoordinatorStorage.md create mode 100644 docs/storage-report/ServiceManagerBase.md create mode 100644 docs/storage-report/ServiceManagerBaseStorage.md create mode 100644 docs/storage-report/ServiceManagerRouter.md create mode 100644 docs/storage-report/SlasherBase.md create mode 100644 docs/storage-report/SlasherStorage.md create mode 100644 docs/storage-report/StakeRegistry.md create mode 100644 docs/storage-report/StakeRegistryStorage.md create mode 100644 docs/storage-report/VetoableSlasher.md diff --git a/.github/bin/storage-report.sh b/.github/bin/storage-report.sh new file mode 100644 index 00000000..71fbd9a0 --- /dev/null +++ b/.github/bin/storage-report.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +# Default output directory +OUTPUT_DIR=${1:-docs/storage-report} + +# Function to print messages +log() { + echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] $1" +} + +# Function to print error messages +error() { + echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $1" >&2 +} + +log "Starting the storage report generation." + +# Create the output directory if it doesn't exist +if ! mkdir -p "$OUTPUT_DIR"; then + error "Failed to create output directory: $OUTPUT_DIR" + exit 1 +fi + +log "Output directory is set to: $OUTPUT_DIR" + +# Loop through Solidity files and generate storage report +# NOTE: Ignores `src/interfaces` & `src/libraries` since they "should" not contain storage logic. +for file in $(find src/ -name "*.sol" ! -path "*/interfaces/*" ! -path "*/libraries/*"); do + contract_name=$(basename "$file" .sol) + + # Check if the file exists and is readable + if [ ! -r "$file" ]; then + error "Cannot read file: $file" + continue + fi + + log "Processing contract: $contract_name" + + # Run forge inspect and capture errors + if ! forge inspect "$contract_name" storage --pretty > "$OUTPUT_DIR/$contract_name.md"; then + error "Failed to generate storage report for contract: $contract_name" + else + log "Storage report generated for contract: $contract_name" + fi +done \ No newline at end of file diff --git a/.github/workflows/storage-report.yml b/.github/workflows/storage-report.yml new file mode 100644 index 00000000..5d7f50d3 --- /dev/null +++ b/.github/workflows/storage-report.yml @@ -0,0 +1,48 @@ +name: Storage Layout + +on: + push: + branches: + - master + - mainnet + - testnet-goerli + - dev + pull_request: + +jobs: + check_storage: + name: CI + runs-on: "ubuntu-latest" + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: "Generate and prepare the storage reports for current branch" + run: | + bash .github/bin/storage-report.sh pr + + - name: Checkout dev + env: + TARGET: ${{ github.event.pull_request.base.sha }} + run: | + git fetch origin $TARGET + git checkout $TARGET + + - name: "Generate and prepare the storage reports for target branch" + run: | + bash .github/bin/storage-report.sh target + + - name: Compare outputs + run: | + if diff --unified pr target; then + echo "No differences found" + else + echo "::error::Differences found between PR and target branch storage layouts" + exit 1 + fi \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..db84aea5 --- /dev/null +++ b/Makefile @@ -0,0 +1,2 @@ +storage-report: + bash ".github/bin/storage-report.sh" "docs/storage-report/" \ No newline at end of file diff --git a/bin/storage-report.sh b/bin/storage-report.sh new file mode 100644 index 00000000..71fbd9a0 --- /dev/null +++ b/bin/storage-report.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +# Default output directory +OUTPUT_DIR=${1:-docs/storage-report} + +# Function to print messages +log() { + echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] $1" +} + +# Function to print error messages +error() { + echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $1" >&2 +} + +log "Starting the storage report generation." + +# Create the output directory if it doesn't exist +if ! mkdir -p "$OUTPUT_DIR"; then + error "Failed to create output directory: $OUTPUT_DIR" + exit 1 +fi + +log "Output directory is set to: $OUTPUT_DIR" + +# Loop through Solidity files and generate storage report +# NOTE: Ignores `src/interfaces` & `src/libraries` since they "should" not contain storage logic. +for file in $(find src/ -name "*.sol" ! -path "*/interfaces/*" ! -path "*/libraries/*"); do + contract_name=$(basename "$file" .sol) + + # Check if the file exists and is readable + if [ ! -r "$file" ]; then + error "Cannot read file: $file" + continue + fi + + log "Processing contract: $contract_name" + + # Run forge inspect and capture errors + if ! forge inspect "$contract_name" storage --pretty > "$OUTPUT_DIR/$contract_name.md"; then + error "Failed to generate storage report for contract: $contract_name" + else + log "Storage report generated for contract: $contract_name" + fi +done \ No newline at end of file diff --git a/docs/storage-report/AVSRegistrar.md b/docs/storage-report/AVSRegistrar.md new file mode 100644 index 00000000..1ec5dc07 --- /dev/null +++ b/docs/storage-report/AVSRegistrar.md @@ -0,0 +1,6 @@ + +╭------+------+------+--------+-------+----------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++================================================+ +╰------+------+------+--------+-------+----------╯ + diff --git a/docs/storage-report/BLSApkRegistry.md b/docs/storage-report/BLSApkRegistry.md new file mode 100644 index 00000000..69239c7c --- /dev/null +++ b/docs/storage-report/BLSApkRegistry.md @@ -0,0 +1,21 @@ + +╭----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++=============================================================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/BLSApkRegistry.sol:BLSApkRegistry | +|----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/BLSApkRegistry.sol:BLSApkRegistry | +|----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------| +| operatorToPubkeyHash | mapping(address => bytes32) | 1 | 0 | 32 | src/BLSApkRegistry.sol:BLSApkRegistry | +|----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------| +| pubkeyHashToOperator | mapping(bytes32 => address) | 2 | 0 | 32 | src/BLSApkRegistry.sol:BLSApkRegistry | +|----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------| +| operatorToPubkey | mapping(address => struct BN254.G1Point) | 3 | 0 | 32 | src/BLSApkRegistry.sol:BLSApkRegistry | +|----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------| +| apkHistory | mapping(uint8 => struct IBLSApkRegistry.ApkUpdate[]) | 4 | 0 | 32 | src/BLSApkRegistry.sol:BLSApkRegistry | +|----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------| +| currentApk | mapping(uint8 => struct BN254.G1Point) | 5 | 0 | 32 | src/BLSApkRegistry.sol:BLSApkRegistry | +|----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------| +| __GAP | uint256[45] | 6 | 0 | 1440 | src/BLSApkRegistry.sol:BLSApkRegistry | +╰----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------╯ + diff --git a/docs/storage-report/BLSApkRegistryStorage.md b/docs/storage-report/BLSApkRegistryStorage.md new file mode 100644 index 00000000..3b5b9e61 --- /dev/null +++ b/docs/storage-report/BLSApkRegistryStorage.md @@ -0,0 +1,21 @@ + +╭----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++===========================================================================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | +|----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | +|----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------| +| operatorToPubkeyHash | mapping(address => bytes32) | 1 | 0 | 32 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | +|----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------| +| pubkeyHashToOperator | mapping(bytes32 => address) | 2 | 0 | 32 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | +|----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------| +| operatorToPubkey | mapping(address => struct BN254.G1Point) | 3 | 0 | 32 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | +|----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------| +| apkHistory | mapping(uint8 => struct IBLSApkRegistry.ApkUpdate[]) | 4 | 0 | 32 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | +|----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------| +| currentApk | mapping(uint8 => struct BN254.G1Point) | 5 | 0 | 32 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | +|----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------| +| __GAP | uint256[45] | 6 | 0 | 1440 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | +╰----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------╯ + diff --git a/docs/storage-report/BLSSignatureChecker.md b/docs/storage-report/BLSSignatureChecker.md new file mode 100644 index 00000000..19b3473b --- /dev/null +++ b/docs/storage-report/BLSSignatureChecker.md @@ -0,0 +1,9 @@ + +╭----------------------+-------------+------+--------+-------+-------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++==============================================================================================================+ +| staleStakesForbidden | bool | 0 | 0 | 1 | src/BLSSignatureChecker.sol:BLSSignatureChecker | +|----------------------+-------------+------+--------+-------+-------------------------------------------------| +| __GAP | uint256[49] | 1 | 0 | 1568 | src/BLSSignatureChecker.sol:BLSSignatureChecker | +╰----------------------+-------------+------+--------+-------+-------------------------------------------------╯ + diff --git a/docs/storage-report/ECDSAServiceManagerBase.md b/docs/storage-report/ECDSAServiceManagerBase.md new file mode 100644 index 00000000..2251f673 --- /dev/null +++ b/docs/storage-report/ECDSAServiceManagerBase.md @@ -0,0 +1,19 @@ + +╭------------------+-------------+------+--------+-------+-------------------------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++============================================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/unaudited/ECDSAServiceManagerBase.sol:ECDSAServiceManagerBase | +|------------------+-------------+------+--------+-------+-------------------------------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/unaudited/ECDSAServiceManagerBase.sol:ECDSAServiceManagerBase | +|------------------+-------------+------+--------+-------+-------------------------------------------------------------------| +| __gap | uint256[50] | 1 | 0 | 1600 | src/unaudited/ECDSAServiceManagerBase.sol:ECDSAServiceManagerBase | +|------------------+-------------+------+--------+-------+-------------------------------------------------------------------| +| _owner | address | 51 | 0 | 20 | src/unaudited/ECDSAServiceManagerBase.sol:ECDSAServiceManagerBase | +|------------------+-------------+------+--------+-------+-------------------------------------------------------------------| +| __gap | uint256[49] | 52 | 0 | 1568 | src/unaudited/ECDSAServiceManagerBase.sol:ECDSAServiceManagerBase | +|------------------+-------------+------+--------+-------+-------------------------------------------------------------------| +| rewardsInitiator | address | 101 | 0 | 20 | src/unaudited/ECDSAServiceManagerBase.sol:ECDSAServiceManagerBase | +|------------------+-------------+------+--------+-------+-------------------------------------------------------------------| +| __GAP | uint256[49] | 102 | 0 | 1568 | src/unaudited/ECDSAServiceManagerBase.sol:ECDSAServiceManagerBase | +╰------------------+-------------+------+--------+-------+-------------------------------------------------------------------╯ + diff --git a/docs/storage-report/ECDSAStakeRegistry.md b/docs/storage-report/ECDSAStakeRegistry.md new file mode 100644 index 00000000..df768c27 --- /dev/null +++ b/docs/storage-report/ECDSAStakeRegistry.md @@ -0,0 +1,37 @@ + +╭----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++==========================================================================================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| __gap | uint256[50] | 1 | 0 | 1600 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| _owner | address | 51 | 0 | 20 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| __gap | uint256[49] | 52 | 0 | 1568 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| _totalOperators | uint256 | 101 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| _quorum | struct Quorum | 102 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| _minimumWeight | uint256 | 103 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| _serviceManager | address | 104 | 0 | 20 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| _stakeExpiry | uint256 | 105 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| _operatorSigningKeyHistory | mapping(address => struct CheckpointsUpgradeable.History) | 106 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| _totalWeightHistory | struct CheckpointsUpgradeable.History | 107 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| _thresholdWeightHistory | struct CheckpointsUpgradeable.History | 108 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| _operatorWeightHistory | mapping(address => struct CheckpointsUpgradeable.History) | 109 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| _operatorRegistered | mapping(address => bool) | 110 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| +| __gap | uint256[40] | 111 | 0 | 1280 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | +╰----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------╯ + diff --git a/docs/storage-report/ECDSAStakeRegistryEqualWeight.md b/docs/storage-report/ECDSAStakeRegistryEqualWeight.md new file mode 100644 index 00000000..e1e1c166 --- /dev/null +++ b/docs/storage-report/ECDSAStakeRegistryEqualWeight.md @@ -0,0 +1,39 @@ + +╭----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++=========================================================================================================================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| __gap | uint256[50] | 1 | 0 | 1600 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| _owner | address | 51 | 0 | 20 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| __gap | uint256[49] | 52 | 0 | 1568 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| _totalOperators | uint256 | 101 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| _quorum | struct Quorum | 102 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| _minimumWeight | uint256 | 103 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| _serviceManager | address | 104 | 0 | 20 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| _stakeExpiry | uint256 | 105 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| _operatorSigningKeyHistory | mapping(address => struct CheckpointsUpgradeable.History) | 106 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| _totalWeightHistory | struct CheckpointsUpgradeable.History | 107 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| _thresholdWeightHistory | struct CheckpointsUpgradeable.History | 108 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| _operatorWeightHistory | mapping(address => struct CheckpointsUpgradeable.History) | 109 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| _operatorRegistered | mapping(address => bool) | 110 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| __gap | uint256[40] | 111 | 0 | 1280 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| +| allowlistedOperators | mapping(address => bool) | 151 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | +╰----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------╯ + diff --git a/docs/storage-report/ECDSAStakeRegistryPermissioned.md b/docs/storage-report/ECDSAStakeRegistryPermissioned.md new file mode 100644 index 00000000..bdc5b32e --- /dev/null +++ b/docs/storage-report/ECDSAStakeRegistryPermissioned.md @@ -0,0 +1,39 @@ + +╭----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++===========================================================================================================================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| __gap | uint256[50] | 1 | 0 | 1600 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| _owner | address | 51 | 0 | 20 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| __gap | uint256[49] | 52 | 0 | 1568 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| _totalOperators | uint256 | 101 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| _quorum | struct Quorum | 102 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| _minimumWeight | uint256 | 103 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| _serviceManager | address | 104 | 0 | 20 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| _stakeExpiry | uint256 | 105 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| _operatorSigningKeyHistory | mapping(address => struct CheckpointsUpgradeable.History) | 106 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| _totalWeightHistory | struct CheckpointsUpgradeable.History | 107 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| _thresholdWeightHistory | struct CheckpointsUpgradeable.History | 108 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| _operatorWeightHistory | mapping(address => struct CheckpointsUpgradeable.History) | 109 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| _operatorRegistered | mapping(address => bool) | 110 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| __gap | uint256[40] | 111 | 0 | 1280 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| +| allowlistedOperators | mapping(address => bool) | 151 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | +╰----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------╯ + diff --git a/docs/storage-report/ECDSAStakeRegistryStorage.md b/docs/storage-report/ECDSAStakeRegistryStorage.md new file mode 100644 index 00000000..69ef3d05 --- /dev/null +++ b/docs/storage-report/ECDSAStakeRegistryStorage.md @@ -0,0 +1,27 @@ + +╭----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++========================================================================================================================================================================================+ +| _totalOperators | uint256 | 0 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | +|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| +| _quorum | struct Quorum | 1 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | +|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| +| _minimumWeight | uint256 | 2 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | +|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| +| _serviceManager | address | 3 | 0 | 20 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | +|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| +| _stakeExpiry | uint256 | 4 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | +|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| +| _operatorSigningKeyHistory | mapping(address => struct CheckpointsUpgradeable.History) | 5 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | +|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| +| _totalWeightHistory | struct CheckpointsUpgradeable.History | 6 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | +|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| +| _thresholdWeightHistory | struct CheckpointsUpgradeable.History | 7 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | +|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| +| _operatorWeightHistory | mapping(address => struct CheckpointsUpgradeable.History) | 8 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | +|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| +| _operatorRegistered | mapping(address => bool) | 9 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | +|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| +| __gap | uint256[40] | 10 | 0 | 1280 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | +╰----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------╯ + diff --git a/docs/storage-report/EjectionManager.md b/docs/storage-report/EjectionManager.md new file mode 100644 index 00000000..55e2a2df --- /dev/null +++ b/docs/storage-report/EjectionManager.md @@ -0,0 +1,21 @@ + +╭-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++==========================================================================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/EjectionManager.sol:EjectionManager | +|-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/EjectionManager.sol:EjectionManager | +|-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------| +| __gap | uint256[50] | 1 | 0 | 1600 | src/EjectionManager.sol:EjectionManager | +|-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------| +| _owner | address | 51 | 0 | 20 | src/EjectionManager.sol:EjectionManager | +|-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------| +| __gap | uint256[49] | 52 | 0 | 1568 | src/EjectionManager.sol:EjectionManager | +|-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------| +| isEjector | mapping(address => bool) | 101 | 0 | 32 | src/EjectionManager.sol:EjectionManager | +|-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------| +| stakeEjectedForQuorum | mapping(uint8 => struct IEjectionManager.StakeEjection[]) | 102 | 0 | 32 | src/EjectionManager.sol:EjectionManager | +|-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------| +| quorumEjectionParams | mapping(uint8 => struct IEjectionManager.QuorumEjectionParams) | 103 | 0 | 32 | src/EjectionManager.sol:EjectionManager | +╰-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------╯ + diff --git a/docs/storage-report/IndexRegistry.md b/docs/storage-report/IndexRegistry.md new file mode 100644 index 00000000..3415bdcd --- /dev/null +++ b/docs/storage-report/IndexRegistry.md @@ -0,0 +1,17 @@ + +╭-----------------------+-----------------------------------------------------------------------------+------+--------+-------+-------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++===================================================================================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/IndexRegistry.sol:IndexRegistry | +|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+-------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/IndexRegistry.sol:IndexRegistry | +|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+-------------------------------------| +| currentOperatorIndex | mapping(uint8 => mapping(bytes32 => uint32)) | 1 | 0 | 32 | src/IndexRegistry.sol:IndexRegistry | +|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+-------------------------------------| +| _operatorIndexHistory | mapping(uint8 => mapping(uint32 => struct IIndexRegistry.OperatorUpdate[])) | 2 | 0 | 32 | src/IndexRegistry.sol:IndexRegistry | +|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+-------------------------------------| +| _operatorCountHistory | mapping(uint8 => struct IIndexRegistry.QuorumUpdate[]) | 3 | 0 | 32 | src/IndexRegistry.sol:IndexRegistry | +|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+-------------------------------------| +| __GAP | uint256[47] | 4 | 0 | 1504 | src/IndexRegistry.sol:IndexRegistry | +╰-----------------------+-----------------------------------------------------------------------------+------+--------+-------+-------------------------------------╯ + diff --git a/docs/storage-report/IndexRegistryStorage.md b/docs/storage-report/IndexRegistryStorage.md new file mode 100644 index 00000000..9581f514 --- /dev/null +++ b/docs/storage-report/IndexRegistryStorage.md @@ -0,0 +1,17 @@ + +╭-----------------------+-----------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++=================================================================================================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/IndexRegistryStorage.sol:IndexRegistryStorage | +|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/IndexRegistryStorage.sol:IndexRegistryStorage | +|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| +| currentOperatorIndex | mapping(uint8 => mapping(bytes32 => uint32)) | 1 | 0 | 32 | src/IndexRegistryStorage.sol:IndexRegistryStorage | +|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| +| _operatorIndexHistory | mapping(uint8 => mapping(uint32 => struct IIndexRegistry.OperatorUpdate[])) | 2 | 0 | 32 | src/IndexRegistryStorage.sol:IndexRegistryStorage | +|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| +| _operatorCountHistory | mapping(uint8 => struct IIndexRegistry.QuorumUpdate[]) | 3 | 0 | 32 | src/IndexRegistryStorage.sol:IndexRegistryStorage | +|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| +| __GAP | uint256[47] | 4 | 0 | 1504 | src/IndexRegistryStorage.sol:IndexRegistryStorage | +╰-----------------------+-----------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------╯ + diff --git a/docs/storage-report/InstantSlasher.md b/docs/storage-report/InstantSlasher.md new file mode 100644 index 00000000..1eafc2b8 --- /dev/null +++ b/docs/storage-report/InstantSlasher.md @@ -0,0 +1,17 @@ + +╭----------------+-------------+------+--------+-------+------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++=======================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/slashers/InstantSlasher.sol:InstantSlasher | +|----------------+-------------+------+--------+-------+------------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/slashers/InstantSlasher.sol:InstantSlasher | +|----------------+-------------+------+--------+-------+------------------------------------------------| +| serviceManager | address | 0 | 2 | 20 | src/slashers/InstantSlasher.sol:InstantSlasher | +|----------------+-------------+------+--------+-------+------------------------------------------------| +| slasher | address | 1 | 0 | 20 | src/slashers/InstantSlasher.sol:InstantSlasher | +|----------------+-------------+------+--------+-------+------------------------------------------------| +| nextRequestId | uint256 | 2 | 0 | 32 | src/slashers/InstantSlasher.sol:InstantSlasher | +|----------------+-------------+------+--------+-------+------------------------------------------------| +| __gap | uint256[47] | 3 | 0 | 1504 | src/slashers/InstantSlasher.sol:InstantSlasher | +╰----------------+-------------+------+--------+-------+------------------------------------------------╯ + diff --git a/docs/storage-report/OperatorStateRetriever.md b/docs/storage-report/OperatorStateRetriever.md new file mode 100644 index 00000000..1ec5dc07 --- /dev/null +++ b/docs/storage-report/OperatorStateRetriever.md @@ -0,0 +1,6 @@ + +╭------+------+------+--------+-------+----------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++================================================+ +╰------+------+------+--------+-------+----------╯ + diff --git a/docs/storage-report/RegistryCoordinator.md b/docs/storage-report/RegistryCoordinator.md new file mode 100644 index 00000000..1adff5f4 --- /dev/null +++ b/docs/storage-report/RegistryCoordinator.md @@ -0,0 +1,49 @@ + +╭-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++==============================================================================================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| __deprecated_pauserRegistry | contract IPauserRegistry | 0 | 2 | 20 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| _paused | uint256 | 1 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| __gap | uint256[48] | 2 | 0 | 1536 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| __gap | uint256[50] | 50 | 0 | 1600 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| _owner | address | 100 | 0 | 20 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| __gap | uint256[49] | 101 | 0 | 1568 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| quorumCount | uint8 | 150 | 0 | 1 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| _quorumParams | mapping(uint8 => struct IRegistryCoordinator.OperatorSetParam) | 151 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| _operatorBitmapHistory | mapping(bytes32 => struct IRegistryCoordinator.QuorumBitmapUpdate[]) | 152 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| _operatorInfo | mapping(address => struct IRegistryCoordinator.OperatorInfo) | 153 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| isChurnApproverSaltUsed | mapping(bytes32 => bool) | 154 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| quorumUpdateBlockNumber | mapping(uint8 => uint256) | 155 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| registries | address[] | 156 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| churnApprover | address | 157 | 0 | 20 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| ejector | address | 158 | 0 | 20 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| lastEjectionTimestamp | mapping(address => uint256) | 159 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| ejectionCooldown | uint256 | 160 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| isOperatorSetAVS | bool | 161 | 0 | 1 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| isM2Quorum | mapping(uint8 => bool) | 162 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | +|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| +| __GAP | uint256[37] | 163 | 0 | 1184 | src/RegistryCoordinator.sol:RegistryCoordinator | +╰-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------╯ + diff --git a/docs/storage-report/RegistryCoordinatorStorage.md b/docs/storage-report/RegistryCoordinatorStorage.md new file mode 100644 index 00000000..1e9fc25d --- /dev/null +++ b/docs/storage-report/RegistryCoordinatorStorage.md @@ -0,0 +1,33 @@ + +╭-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++========================================================================================================================================================================================+ +| quorumCount | uint8 | 0 | 0 | 1 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| _quorumParams | mapping(uint8 => struct IRegistryCoordinator.OperatorSetParam) | 1 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| _operatorBitmapHistory | mapping(bytes32 => struct IRegistryCoordinator.QuorumBitmapUpdate[]) | 2 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| _operatorInfo | mapping(address => struct IRegistryCoordinator.OperatorInfo) | 3 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| isChurnApproverSaltUsed | mapping(bytes32 => bool) | 4 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| quorumUpdateBlockNumber | mapping(uint8 => uint256) | 5 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| registries | address[] | 6 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| churnApprover | address | 7 | 0 | 20 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| ejector | address | 8 | 0 | 20 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| lastEjectionTimestamp | mapping(address => uint256) | 9 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| ejectionCooldown | uint256 | 10 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| isOperatorSetAVS | bool | 11 | 0 | 1 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| isM2Quorum | mapping(uint8 => bool) | 12 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| __GAP | uint256[37] | 13 | 0 | 1184 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +╰-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------╯ + diff --git a/docs/storage-report/ServiceManagerBase.md b/docs/storage-report/ServiceManagerBase.md new file mode 100644 index 00000000..61ef533a --- /dev/null +++ b/docs/storage-report/ServiceManagerBase.md @@ -0,0 +1,27 @@ + +╭--------------------------+-------------+------+--------+-------+-----------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++================================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/ServiceManagerBase.sol:ServiceManagerBase | +|--------------------------+-------------+------+--------+-------+-----------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/ServiceManagerBase.sol:ServiceManagerBase | +|--------------------------+-------------+------+--------+-------+-----------------------------------------------| +| __gap | uint256[50] | 1 | 0 | 1600 | src/ServiceManagerBase.sol:ServiceManagerBase | +|--------------------------+-------------+------+--------+-------+-----------------------------------------------| +| _owner | address | 51 | 0 | 20 | src/ServiceManagerBase.sol:ServiceManagerBase | +|--------------------------+-------------+------+--------+-------+-----------------------------------------------| +| __gap | uint256[49] | 52 | 0 | 1568 | src/ServiceManagerBase.sol:ServiceManagerBase | +|--------------------------+-------------+------+--------+-------+-----------------------------------------------| +| rewardsInitiator | address | 101 | 0 | 20 | src/ServiceManagerBase.sol:ServiceManagerBase | +|--------------------------+-------------+------+--------+-------+-----------------------------------------------| +| slasher | address | 102 | 0 | 20 | src/ServiceManagerBase.sol:ServiceManagerBase | +|--------------------------+-------------+------+--------+-------+-----------------------------------------------| +| proposedSlasher | address | 103 | 0 | 20 | src/ServiceManagerBase.sol:ServiceManagerBase | +|--------------------------+-------------+------+--------+-------+-----------------------------------------------| +| slasherProposalTimestamp | uint256 | 104 | 0 | 32 | src/ServiceManagerBase.sol:ServiceManagerBase | +|--------------------------+-------------+------+--------+-------+-----------------------------------------------| +| migrationFinalized | bool | 105 | 0 | 1 | src/ServiceManagerBase.sol:ServiceManagerBase | +|--------------------------+-------------+------+--------+-------+-----------------------------------------------| +| __GAP | uint256[45] | 106 | 0 | 1440 | src/ServiceManagerBase.sol:ServiceManagerBase | +╰--------------------------+-------------+------+--------+-------+-----------------------------------------------╯ + diff --git a/docs/storage-report/ServiceManagerBaseStorage.md b/docs/storage-report/ServiceManagerBaseStorage.md new file mode 100644 index 00000000..baa458fa --- /dev/null +++ b/docs/storage-report/ServiceManagerBaseStorage.md @@ -0,0 +1,27 @@ + +╭--------------------------+-------------+------+--------+-------+-------------------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++==============================================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| __gap | uint256[50] | 1 | 0 | 1600 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| _owner | address | 51 | 0 | 20 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| __gap | uint256[49] | 52 | 0 | 1568 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| rewardsInitiator | address | 101 | 0 | 20 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| slasher | address | 102 | 0 | 20 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| proposedSlasher | address | 103 | 0 | 20 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| slasherProposalTimestamp | uint256 | 104 | 0 | 32 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| migrationFinalized | bool | 105 | 0 | 1 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| __GAP | uint256[45] | 106 | 0 | 1440 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +╰--------------------------+-------------+------+--------+-------+-------------------------------------------------------------╯ + diff --git a/docs/storage-report/ServiceManagerRouter.md b/docs/storage-report/ServiceManagerRouter.md new file mode 100644 index 00000000..1ec5dc07 --- /dev/null +++ b/docs/storage-report/ServiceManagerRouter.md @@ -0,0 +1,6 @@ + +╭------+------+------+--------+-------+----------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++================================================+ +╰------+------+------+--------+-------+----------╯ + diff --git a/docs/storage-report/SlasherBase.md b/docs/storage-report/SlasherBase.md new file mode 100644 index 00000000..2e210170 --- /dev/null +++ b/docs/storage-report/SlasherBase.md @@ -0,0 +1,17 @@ + +╭----------------+-------------+------+--------+-------+-----------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++======================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/slashers/base/SlasherBase.sol:SlasherBase | +|----------------+-------------+------+--------+-------+-----------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/slashers/base/SlasherBase.sol:SlasherBase | +|----------------+-------------+------+--------+-------+-----------------------------------------------| +| serviceManager | address | 0 | 2 | 20 | src/slashers/base/SlasherBase.sol:SlasherBase | +|----------------+-------------+------+--------+-------+-----------------------------------------------| +| slasher | address | 1 | 0 | 20 | src/slashers/base/SlasherBase.sol:SlasherBase | +|----------------+-------------+------+--------+-------+-----------------------------------------------| +| nextRequestId | uint256 | 2 | 0 | 32 | src/slashers/base/SlasherBase.sol:SlasherBase | +|----------------+-------------+------+--------+-------+-----------------------------------------------| +| __gap | uint256[47] | 3 | 0 | 1504 | src/slashers/base/SlasherBase.sol:SlasherBase | +╰----------------+-------------+------+--------+-------+-----------------------------------------------╯ + diff --git a/docs/storage-report/SlasherStorage.md b/docs/storage-report/SlasherStorage.md new file mode 100644 index 00000000..6a5ec3aa --- /dev/null +++ b/docs/storage-report/SlasherStorage.md @@ -0,0 +1,13 @@ + +╭----------------+-------------+------+--------+-------+-----------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++============================================================================================================+ +| serviceManager | address | 0 | 0 | 20 | src/slashers/base/SlasherStorage.sol:SlasherStorage | +|----------------+-------------+------+--------+-------+-----------------------------------------------------| +| slasher | address | 1 | 0 | 20 | src/slashers/base/SlasherStorage.sol:SlasherStorage | +|----------------+-------------+------+--------+-------+-----------------------------------------------------| +| nextRequestId | uint256 | 2 | 0 | 32 | src/slashers/base/SlasherStorage.sol:SlasherStorage | +|----------------+-------------+------+--------+-------+-----------------------------------------------------| +| __gap | uint256[47] | 3 | 0 | 1504 | src/slashers/base/SlasherStorage.sol:SlasherStorage | +╰----------------+-------------+------+--------+-------+-----------------------------------------------------╯ + diff --git a/docs/storage-report/StakeRegistry.md b/docs/storage-report/StakeRegistry.md new file mode 100644 index 00000000..820aaba6 --- /dev/null +++ b/docs/storage-report/StakeRegistry.md @@ -0,0 +1,21 @@ + +╭----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++============================================================================================================================================================================+ +| minimumStakeForQuorum | mapping(uint8 => uint96) | 0 | 0 | 32 | src/StakeRegistry.sol:StakeRegistry | +|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------| +| _totalStakeHistory | mapping(uint8 => struct IStakeRegistry.StakeUpdate[]) | 1 | 0 | 32 | src/StakeRegistry.sol:StakeRegistry | +|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------| +| operatorStakeHistory | mapping(bytes32 => mapping(uint8 => struct IStakeRegistry.StakeUpdate[])) | 2 | 0 | 32 | src/StakeRegistry.sol:StakeRegistry | +|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------| +| strategyParams | mapping(uint8 => struct IStakeRegistry.StrategyParams[]) | 3 | 0 | 32 | src/StakeRegistry.sol:StakeRegistry | +|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------| +| strategiesPerQuorum | mapping(uint8 => contract IStrategy[]) | 4 | 0 | 32 | src/StakeRegistry.sol:StakeRegistry | +|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------| +| stakeTypePerQuorum | mapping(uint8 => enum StakeType) | 5 | 0 | 32 | src/StakeRegistry.sol:StakeRegistry | +|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------| +| slashableStakeLookAheadPerQuorum | mapping(uint8 => uint32) | 6 | 0 | 32 | src/StakeRegistry.sol:StakeRegistry | +|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------| +| __GAP | uint256[43] | 7 | 0 | 1376 | src/StakeRegistry.sol:StakeRegistry | +╰----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------╯ + diff --git a/docs/storage-report/StakeRegistryStorage.md b/docs/storage-report/StakeRegistryStorage.md new file mode 100644 index 00000000..4a545513 --- /dev/null +++ b/docs/storage-report/StakeRegistryStorage.md @@ -0,0 +1,21 @@ + +╭----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++==========================================================================================================================================================================================+ +| minimumStakeForQuorum | mapping(uint8 => uint96) | 0 | 0 | 32 | src/StakeRegistryStorage.sol:StakeRegistryStorage | +|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| +| _totalStakeHistory | mapping(uint8 => struct IStakeRegistry.StakeUpdate[]) | 1 | 0 | 32 | src/StakeRegistryStorage.sol:StakeRegistryStorage | +|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| +| operatorStakeHistory | mapping(bytes32 => mapping(uint8 => struct IStakeRegistry.StakeUpdate[])) | 2 | 0 | 32 | src/StakeRegistryStorage.sol:StakeRegistryStorage | +|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| +| strategyParams | mapping(uint8 => struct IStakeRegistry.StrategyParams[]) | 3 | 0 | 32 | src/StakeRegistryStorage.sol:StakeRegistryStorage | +|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| +| strategiesPerQuorum | mapping(uint8 => contract IStrategy[]) | 4 | 0 | 32 | src/StakeRegistryStorage.sol:StakeRegistryStorage | +|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| +| stakeTypePerQuorum | mapping(uint8 => enum StakeType) | 5 | 0 | 32 | src/StakeRegistryStorage.sol:StakeRegistryStorage | +|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| +| slashableStakeLookAheadPerQuorum | mapping(uint8 => uint32) | 6 | 0 | 32 | src/StakeRegistryStorage.sol:StakeRegistryStorage | +|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| +| __GAP | uint256[43] | 7 | 0 | 1376 | src/StakeRegistryStorage.sol:StakeRegistryStorage | +╰----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------╯ + diff --git a/docs/storage-report/VetoableSlasher.md b/docs/storage-report/VetoableSlasher.md new file mode 100644 index 00000000..e69de29b From 42fa63ea0af581bca011db93c450f41b6a469ad9 Mon Sep 17 00:00:00 2001 From: steven Date: Thu, 9 Jan 2025 10:43:08 -0500 Subject: [PATCH 37/52] fix: prevent calling enable operator sets twice and use internal function for checkALM --- src/RegistryCoordinator.sol | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 99073714..e6e1d659 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -278,6 +278,7 @@ contract RegistryCoordinator is } function enableOperatorSets() external onlyOwner { + require(!isOperatorSetAVS, OperatorSetsEnabled()); /// Triggers the updates to use operator sets ie setsAVSRegistrar /// Opens up the AVS Registrar Hooks on this contract to be callable by the ALM /// Allows creation of quorums with slashable and total delegated stake for operator sets @@ -304,7 +305,7 @@ contract RegistryCoordinator is for (uint256 i = 0; i < operatorSetIds.length; i++) { require(!isM2Quorum[uint8(operatorSetIds[i])], OperatorSetsNotSupported()); } - require(msg.sender == address(serviceManager.allocationManager()), OnlyAllocationManager()); + _checkAllocationManager(); // Decode registration data from bytes ( @@ -336,7 +337,7 @@ contract RegistryCoordinator is for (uint256 i = 0; i < operatorSetIds.length; i++) { require(!isM2Quorum[uint8(operatorSetIds[i])], OperatorSetsNotSupported()); } - require(msg.sender == address(serviceManager.allocationManager()), OnlyAllocationManager()); + _checkAllocationManager(); bytes memory quorumNumbers = new bytes(operatorSetIds.length); for (uint256 i = 0; i < operatorSetIds.length; i++) { quorumNumbers[i] = bytes1(uint8(operatorSetIds[i])); From 45eb220a2f9e96d34e2503cd103a86175fbe699c Mon Sep 17 00:00:00 2001 From: steven Date: Thu, 9 Jan 2025 17:00:38 -0500 Subject: [PATCH 38/52] chore: address review comments --- src/RegistryCoordinator.sol | 3 +-- src/RegistryCoordinatorStorage.sol | 9 ++++++--- test/harnesses/RegistryCoordinatorHarness.t.sol | 3 +-- test/integration/CoreRegistration.t.sol | 1 - test/integration/IntegrationDeployer.t.sol | 2 +- test/unit/StakeRegistryUnit.t.sol | 1 - test/utils/MockAVSDeployer.sol | 2 +- 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index e6e1d659..bde1eafa 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -65,10 +65,9 @@ contract RegistryCoordinator is IStakeRegistry _stakeRegistry, IBLSApkRegistry _blsApkRegistry, IIndexRegistry _indexRegistry, - IAVSDirectory _avsDirectory, IPauserRegistry _pauserRegistry ) - RegistryCoordinatorStorage(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry, _avsDirectory) + RegistryCoordinatorStorage(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry) EIP712("AVSRegistryCoordinator", "v0.0.1") Pausable(_pauserRegistry) { diff --git a/src/RegistryCoordinatorStorage.sol b/src/RegistryCoordinatorStorage.sol index 8e343fbd..4911da4b 100644 --- a/src/RegistryCoordinatorStorage.sol +++ b/src/RegistryCoordinatorStorage.sol @@ -72,21 +72,24 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { /// @notice the delay in seconds before an operator can reregister after being ejected uint256 public ejectionCooldown; + /// @notice Whether this AVS uses operator sets for registration + /// @dev If true, operators must register to operator sets via the AllocationManager bool public isOperatorSetAVS; + + /// @notice Mapping from quorum number to whether the quorum is an M2 quorum + /// @dev M2 quorums are pre-operator sets and track total delegated stake only mapping(uint8 => bool) public isM2Quorum; constructor( IServiceManager _serviceManager, IStakeRegistry _stakeRegistry, IBLSApkRegistry _blsApkRegistry, - IIndexRegistry _indexRegistry, - IAVSDirectory _avsDirectory + IIndexRegistry _indexRegistry ) { serviceManager = _serviceManager; stakeRegistry = _stakeRegistry; blsApkRegistry = _blsApkRegistry; indexRegistry = _indexRegistry; - avsDirectory = _avsDirectory; } // storage gap for upgradeability diff --git a/test/harnesses/RegistryCoordinatorHarness.t.sol b/test/harnesses/RegistryCoordinatorHarness.t.sol index 8110fb13..860e70dc 100644 --- a/test/harnesses/RegistryCoordinatorHarness.t.sol +++ b/test/harnesses/RegistryCoordinatorHarness.t.sol @@ -12,9 +12,8 @@ contract RegistryCoordinatorHarness is RegistryCoordinator, Test { IStakeRegistry _stakeRegistry, IBLSApkRegistry _blsApkRegistry, IIndexRegistry _indexRegistry, - IAVSDirectory _avsDirectory, IPauserRegistry _pauserRegistry - ) RegistryCoordinator(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry, _avsDirectory, _pauserRegistry) { + ) RegistryCoordinator(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry, _pauserRegistry) { _transferOwnership(msg.sender); } diff --git a/test/integration/CoreRegistration.t.sol b/test/integration/CoreRegistration.t.sol index 5d875e3e..4fbfc3ad 100644 --- a/test/integration/CoreRegistration.t.sol +++ b/test/integration/CoreRegistration.t.sol @@ -91,7 +91,6 @@ contract Test_CoreRegistration is MockAVSDeployer { stakeRegistry, blsApkRegistry, indexRegistry, - avsDirectory, pauserRegistry ); diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index 414b8fe2..dda8ce58 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -376,7 +376,7 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { uint32[] memory slashableStakeQuorumLookAheadPeriods = new uint32[](0); RegistryCoordinator registryCoordinatorImplementation = - new RegistryCoordinator(serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, avsDirectory, pauserRegistry); + new RegistryCoordinator(serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, pauserRegistry); proxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(registryCoordinator))), address(registryCoordinatorImplementation), diff --git a/test/unit/StakeRegistryUnit.t.sol b/test/unit/StakeRegistryUnit.t.sol index a4f58b85..7e8f483e 100644 --- a/test/unit/StakeRegistryUnit.t.sol +++ b/test/unit/StakeRegistryUnit.t.sol @@ -49,7 +49,6 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { stakeRegistry, IBLSApkRegistry(blsApkRegistry), IIndexRegistry(indexRegistry), - IAVSDirectory(avsDirectory), pauserRegistry ); diff --git a/test/utils/MockAVSDeployer.sol b/test/utils/MockAVSDeployer.sol index 800628da..3a14c824 100644 --- a/test/utils/MockAVSDeployer.sol +++ b/test/utils/MockAVSDeployer.sol @@ -274,7 +274,7 @@ contract MockAVSDeployer is Test { } registryCoordinatorImplementation = new RegistryCoordinatorHarness( - serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, avsDirectory, pauserRegistry + serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, pauserRegistry ); { delete operatorSetParams; From 8778517518eee0965c3abf247c9e062c67648262 Mon Sep 17 00:00:00 2001 From: Michael Sun <35479365+8sunyuan@users.noreply.github.com> Date: Fri, 10 Jan 2025 13:11:19 -0500 Subject: [PATCH 39/52] refactor: custom errors in middleware (#355) * refactor: custom errors * fix: unit tests --- src/BLSApkRegistry.sol | 34 ++++------- src/BLSSignatureChecker.sol | 35 ++++------- src/EjectionManager.sol | 4 +- src/IndexRegistry.sol | 10 ++-- src/OperatorStateRetriever.sol | 4 +- src/ServiceManagerBase.sol | 23 ++----- src/StakeRegistry.sol | 44 +++++--------- src/interfaces/IBLSApkRegistry.sol | 25 +++++++- src/interfaces/IBLSSignatureChecker.sol | 25 +++++++- src/interfaces/IEjectionManager.sol | 9 ++- src/interfaces/IIndexRegistry.sol | 11 +++- src/interfaces/IServiceManager.sol | 14 ++++- src/interfaces/ISlasher.sol | 17 +++++- src/interfaces/IStakeRegistry.sol | 28 ++++++++- src/libraries/BN254.sol | 21 +++++-- src/libraries/BitmapUtils.sol | 16 +++-- src/libraries/QuorumBitmapHistoryLib.sol | 10 +++- src/slashers/VetoableSlasher.sol | 13 ++-- src/slashers/base/SlasherBase.sol | 2 +- src/unaudited/ECDSAServiceManagerBase.sol | 10 +--- test/unit/BLSApkRegistryUnit.t.sol | 61 +++++-------------- test/unit/BLSSignatureCheckerUnit.t.sol | 38 ++++++------ test/unit/BitmapUtils.t.sol | 2 +- test/unit/EjectionManagerUnit.t.sol | 4 +- test/unit/IndexRegistryUnit.t.sol | 9 +-- test/unit/OperatorStateRetrieverUnit.t.sol | 11 ++-- test/unit/RegistryCoordinatorUnit.t.sol | 16 ++--- test/unit/ServiceManagerBase.t.sol | 5 +- test/unit/StakeRegistryUnit.t.sol | 70 ++++++++-------------- 29 files changed, 300 insertions(+), 271 deletions(-) diff --git a/src/BLSApkRegistry.sol b/src/BLSApkRegistry.sol index ec445d3e..189716a6 100644 --- a/src/BLSApkRegistry.sol +++ b/src/BLSApkRegistry.sol @@ -79,7 +79,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage { * @param quorumNumber The number of the new quorum */ function initializeQuorum(uint8 quorumNumber) public virtual onlyRegistryCoordinator { - require(apkHistory[quorumNumber].length == 0, "BLSApkRegistry.initializeQuorum: quorum already exists"); + require(apkHistory[quorumNumber].length == 0, QuorumAlreadyExists()); apkHistory[quorumNumber].push(ApkUpdate({ apkHash: bytes24(0), @@ -100,17 +100,9 @@ contract BLSApkRegistry is BLSApkRegistryStorage { BN254.G1Point calldata pubkeyRegistrationMessageHash ) external onlyRegistryCoordinator returns (bytes32 operatorId) { bytes32 pubkeyHash = BN254.hashG1Point(params.pubkeyG1); - require( - pubkeyHash != ZERO_PK_HASH, "BLSApkRegistry.registerBLSPublicKey: cannot register zero pubkey" - ); - require( - operatorToPubkeyHash[operator] == bytes32(0), - "BLSApkRegistry.registerBLSPublicKey: operator already registered pubkey" - ); - require( - pubkeyHashToOperator[pubkeyHash] == address(0), - "BLSApkRegistry.registerBLSPublicKey: public key already registered" - ); + require(pubkeyHash != ZERO_PK_HASH, ZeroPubKey()); + require(operatorToPubkeyHash[operator] == bytes32(0), OperatorAlreadyRegistered()); + require(pubkeyHashToOperator[pubkeyHash] == address(0), BLSPubkeyAlreadyRegistered()); // gamma = h(sigma, P, P', H(m)) uint256 gamma = uint256(keccak256(abi.encodePacked( @@ -130,7 +122,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage { BN254.negGeneratorG2(), pubkeyRegistrationMessageHash.plus(BN254.generatorG1().scalar_mul(gamma)), params.pubkeyG2 - ), "BLSApkRegistry.registerBLSPublicKey: either the G1 signature is wrong, or G1 and G2 private key do not match"); + ), InvalidBLSSignatureOrPrivateKey()); operatorToPubkey[operator] = params.pubkeyG1; operatorToPubkeyHash[operator] = pubkeyHash; @@ -151,7 +143,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage { // Validate quorum exists and get history length uint8 quorumNumber = uint8(quorumNumbers[i]); uint256 historyLength = apkHistory[quorumNumber].length; - require(historyLength != 0, "BLSApkRegistry._processQuorumApkUpdate: quorum does not exist"); + require(historyLength != 0, QuorumDoesNotExist()); // Update aggregate public key for this quorum newApk = currentApk[quorumNumber].plus(point); @@ -185,10 +177,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage { BN254.G1Point memory pubkey = operatorToPubkey[operator]; bytes32 pubkeyHash = operatorToPubkeyHash[operator]; - require( - pubkeyHash != bytes32(0), - "BLSApkRegistry.getRegisteredPubkey: operator is not registered" - ); + require(pubkeyHash != bytes32(0), OperatorNotRegistered()); return (pubkey, pubkeyHash); } @@ -253,11 +242,11 @@ contract BLSApkRegistry is BLSApkRegistryStorage { */ require( blockNumber >= quorumApkUpdate.updateBlockNumber, - "BLSApkRegistry.getApkHashAtBlockNumberAndIndex: index too recent" + BlockNumberTooRecent() ); require( quorumApkUpdate.nextUpdateBlockNumber == 0 || blockNumber < quorumApkUpdate.nextUpdateBlockNumber, - "BLSApkRegistry.getApkHashAtBlockNumberAndIndex: not latest apk update" + BlockNumberNotLatest() ); return quorumApkUpdate.apkHash; @@ -280,9 +269,6 @@ contract BLSApkRegistry is BLSApkRegistryStorage { } function _checkRegistryCoordinator() internal view { - require( - msg.sender == address(registryCoordinator), - "BLSApkRegistry._checkRegistryCoordinator: caller is not the registry coordinator" - ); + require(msg.sender == address(registryCoordinator), OnlyRegistryCoordinatorOwner()); } } diff --git a/src/BLSSignatureChecker.sol b/src/BLSSignatureChecker.sol index 77d6fbe6..944ed4f7 100644 --- a/src/BLSSignatureChecker.sol +++ b/src/BLSSignatureChecker.sol @@ -31,10 +31,7 @@ contract BLSSignatureChecker is IBLSSignatureChecker { bool public staleStakesForbidden; modifier onlyCoordinatorOwner() { - require( - msg.sender == registryCoordinator.owner(), - "BLSSignatureChecker.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator" - ); + require(msg.sender == registryCoordinator.owner(), OnlyRegistryCoordinatorOwner()); _; } @@ -91,29 +88,23 @@ contract BLSSignatureChecker is IBLSSignatureChecker { uint32 referenceBlockNumber, NonSignerStakesAndSignature memory params ) public view returns (QuorumStakeTotals memory, bytes32) { - require( - quorumNumbers.length != 0, - "BLSSignatureChecker.checkSignatures: empty quorum input" - ); + require(quorumNumbers.length != 0, InputEmptyQuorumNumbers()); require( (quorumNumbers.length == params.quorumApks.length) && (quorumNumbers.length == params.quorumApkIndices.length) && (quorumNumbers.length == params.totalStakeIndices.length) && (quorumNumbers.length == params.nonSignerStakeIndices.length), - "BLSSignatureChecker.checkSignatures: input quorum length mismatch" + InputArrayLengthMismatch() ); require( params.nonSignerPubkeys.length == params.nonSignerQuorumBitmapIndices.length, - "BLSSignatureChecker.checkSignatures: input nonsigner length mismatch" + InputNonSignerLengthMismatch() ); - require( - referenceBlockNumber < uint32(block.number), - "BLSSignatureChecker.checkSignatures: invalid reference block" - ); + require(referenceBlockNumber < uint32(block.number), InvalidReferenceBlocknumber()); // This method needs to calculate the aggregate pubkey for all signing operators across // all signing quorums. To do that, we can query the aggregate pubkey for each quorum @@ -155,7 +146,7 @@ contract BLSSignatureChecker is IBLSSignatureChecker { require( uint256(nonSigners.pubkeyHashes[j]) > uint256(nonSigners.pubkeyHashes[j - 1]), - "BLSSignatureChecker.checkSignatures: nonSignerPubkeys not sorted" + NonSignerPubkeysNotSorted() ); } @@ -207,7 +198,7 @@ contract BLSSignatureChecker is IBLSSignatureChecker { ) + withdrawalDelayBlocks > referenceBlockNumber, - "BLSSignatureChecker.checkSignatures: StakeRegistry updates must be within withdrawalDelayBlocks window" + StaleStakesForbidden() ); } @@ -220,7 +211,7 @@ contract BLSSignatureChecker is IBLSSignatureChecker { blockNumber: referenceBlockNumber, index: params.quorumApkIndices[i] }), - "BLSSignatureChecker.checkSignatures: quorumApk hash in storage does not match provided quorum apk" + InvalidQuorumApkHash() ); apk = apk.plus(params.quorumApks[i]); @@ -274,14 +265,8 @@ contract BLSSignatureChecker is IBLSSignatureChecker { params.apkG2, params.sigma ); - require( - pairingSuccessful, - "BLSSignatureChecker.checkSignatures: pairing precompile call failed" - ); - require( - signatureIsValid, - "BLSSignatureChecker.checkSignatures: signature is invalid" - ); + require(pairingSuccessful, InvalidBLSPairingKey()); + require(signatureIsValid, InvalidBLSSignature()); } // set signatoryRecordHash variable used for fraudproofs bytes32 signatoryRecordHash = keccak256( diff --git a/src/EjectionManager.sol b/src/EjectionManager.sol index 81860fc0..8ebf6002 100644 --- a/src/EjectionManager.sol +++ b/src/EjectionManager.sol @@ -67,7 +67,7 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { * @dev The owner can eject operators without recording of stake ejection */ function ejectOperators(bytes32[][] memory _operatorIds) external { - require(isEjector[msg.sender] || msg.sender == owner(), "EjectionManager.ejectOperators: Only owner or ejector can eject"); + require(isEjector[msg.sender] || msg.sender == owner(), OnlyOwnerOrEjector()); for(uint i = 0; i < _operatorIds.length; ++i) { uint8 quorumNumber = uint8(i); @@ -137,7 +137,7 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { ///@dev internal function to set the quorum ejection params function _setQuorumEjectionParams(uint8 _quorumNumber, QuorumEjectionParams memory _quorumEjectionParams) internal { - require(_quorumNumber < MAX_QUORUM_COUNT, "EjectionManager._setQuorumEjectionParams: Quorum number exceeds MAX_QUORUM_COUNT"); + require(_quorumNumber < MAX_QUORUM_COUNT, MaxQuorumCount()); quorumEjectionParams[_quorumNumber] = _quorumEjectionParams; emit QuorumEjectionParamsSet(_quorumNumber, _quorumEjectionParams.rateLimitWindow, _quorumEjectionParams.ejectableStakePercent); } diff --git a/src/IndexRegistry.sol b/src/IndexRegistry.sol index ce432d64..cab62a17 100644 --- a/src/IndexRegistry.sol +++ b/src/IndexRegistry.sol @@ -47,7 +47,7 @@ contract IndexRegistry is IndexRegistryStorage { // Validate quorum exists and get current operator count uint8 quorumNumber = uint8(quorumNumbers[i]); uint256 historyLength = _operatorCountHistory[quorumNumber].length; - require(historyLength != 0, "IndexRegistry.registerOperator: quorum does not exist"); + require(historyLength != 0, QuorumDoesNotExist()); /** * Increase the number of operators currently active for this quorum, @@ -87,7 +87,7 @@ contract IndexRegistry is IndexRegistryStorage { // Validate quorum exists and get the operatorIndex of the operator being deregistered uint8 quorumNumber = uint8(quorumNumbers[i]); uint256 historyLength = _operatorCountHistory[quorumNumber].length; - require(historyLength != 0, "IndexRegistry.registerOperator: quorum does not exist"); + require(historyLength != 0, QuorumDoesNotExist()); uint32 operatorIndexToRemove = currentOperatorIndex[quorumNumber][operatorId]; /** @@ -113,7 +113,7 @@ contract IndexRegistry is IndexRegistryStorage { * @param quorumNumber The number of the new quorum */ function initializeQuorum(uint8 quorumNumber) public virtual onlyRegistryCoordinator { - require(_operatorCountHistory[quorumNumber].length == 0, "IndexRegistry.createQuorum: quorum already exists"); + require(_operatorCountHistory[quorumNumber].length == 0, QuorumDoesNotExist()); _operatorCountHistory[quorumNumber].push(QuorumUpdate({ numOperators: 0, @@ -329,7 +329,7 @@ contract IndexRegistry is IndexRegistryStorage { operatorList[i] = _operatorIdForIndexAtBlockNumber(quorumNumber, uint32(i), blockNumber); require( operatorList[i] != OPERATOR_DOES_NOT_EXIST_ID, - "IndexRegistry.getOperatorListAtBlockNumber: operator does not exist at the given block number" + OperatorIdDoesNotExist() ); } return operatorList; @@ -342,6 +342,6 @@ contract IndexRegistry is IndexRegistryStorage { } function _checkRegistryCoordinator() internal view { - require(msg.sender == address(registryCoordinator), "IndexRegistry._checkRegistryCoordinator: caller is not the registry coordinator"); + require(msg.sender == address(registryCoordinator), OnlyRegistryCoordinator()); } } diff --git a/src/OperatorStateRetriever.sol b/src/OperatorStateRetriever.sol index 2af9e527..87672b66 100644 --- a/src/OperatorStateRetriever.sol +++ b/src/OperatorStateRetriever.sol @@ -26,6 +26,8 @@ contract OperatorStateRetriever { uint32[][] nonSignerStakeIndices; // nonSignerStakeIndices[quorumNumberIndex][nonSignerIndex] } + error OperatorNotRegistered(); + /** * @notice This function is intended to to be called by AVS operators every time a new task is created (i.e.) * the AVS coordinator makes a request to AVS operators. Since all of the crucial information is kept onchain, @@ -131,7 +133,7 @@ contract OperatorStateRetriever { checkSignaturesIndices.nonSignerQuorumBitmapIndices[i] ); - require(nonSignerQuorumBitmap != 0, "OperatorStateRetriever.getCheckSignaturesIndices: operator must be registered at blocknumber"); + require(nonSignerQuorumBitmap != 0, OperatorNotRegistered()); // if the operator was a part of the quorum and the quorum is a part of the provided quorumNumbers if ((nonSignerQuorumBitmap >> uint8(quorumNumbers[quorumNumberIndex])) & 1 == 1) { diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index 86c1e937..b7a07df8 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -30,10 +30,7 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { /// @notice when applied to a function, only allows the RegistryCoordinator to call it modifier onlyRegistryCoordinator() { - require( - msg.sender == address(_registryCoordinator), - "ServiceManagerBase.onlyRegistryCoordinator: caller is not the registry coordinator" - ); + require(msg.sender == address(_registryCoordinator), OnlyRegistryCoordinator()); _; } @@ -209,7 +206,7 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { function acceptProposedSlasher() external onlyOwner { require( block.timestamp >= slasherProposalTimestamp + SLASHER_PROPOSAL_DELAY, - "ServiceManager: Slasher proposal delay not met" + DelayPeriodNotPassed() ); _setSlasher(proposedSlasher); delete proposedSlasher; @@ -314,24 +311,14 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { } function _checkRewardsInitiator() internal view { - require( - msg.sender == rewardsInitiator, - "ServiceManagerBase.onlyRewardsInitiator: caller is not the rewards initiator" - ); + require(msg.sender == rewardsInitiator, OnlyRewardsInitiator()); } function _checkStakeRegistry() internal view { - require( - msg.sender == address(_stakeRegistry), - "ServiceManagerBase.onlyStakeRegistry: caller is not the stake registry" - ); + require(msg.sender == address(_stakeRegistry), OnlyStakeRegistry()); } - function _checkSlasher() internal view { - require( - msg.sender == slasher, - "ServiceManagerBase.onlySlasher: caller is not the slasher" - ); + require(msg.sender == slasher, OnlySlasher()); } } diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index fe861b7b..3d2b5089 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -82,10 +82,7 @@ contract StakeRegistry is StakeRegistryStorage { // Retrieve the operator's current weighted stake for the quorum, reverting if they have not met // the minimum. (uint96 currentStake, bool hasMinimumStake) = _weightOfOperatorForQuorum(quorumNumber, operator); - require( - hasMinimumStake, - "StakeRegistry.registerOperator: Operator does not meet minimum stake requirement for quorum" - ); + require(hasMinimumStake, BelowMinimumStakeRequirement()); // Update the operator's stake int256 stakeDelta = _recordOperatorStakeUpdate({ @@ -197,7 +194,7 @@ contract StakeRegistry is StakeRegistryStorage { uint96 minimumStake, StrategyParams[] memory _strategyParams ) public virtual onlyRegistryCoordinator { - require(!_quorumExists(quorumNumber), "StakeRegistry.initializeQuorum: quorum already exists"); + require(!_quorumExists(quorumNumber), QuorumAlreadyExists()); _addStrategyParams(quorumNumber, _strategyParams); _setMinimumStakeForQuorum(quorumNumber, minimumStake); _setStakeType(quorumNumber, StakeType.TOTAL_DELEGATED); @@ -217,7 +214,7 @@ contract StakeRegistry is StakeRegistryStorage { uint32 lookAheadPeriod, StrategyParams[] memory _strategyParams ) public virtual onlyRegistryCoordinator { - require(!_quorumExists(quorumNumber), "StakeRegistry.initializeQuorum: quorum already exists"); + require(!_quorumExists(quorumNumber), QuorumAlreadyExists()); _addStrategyParams(quorumNumber, _strategyParams); _setMinimumStakeForQuorum(quorumNumber, minimumStake); _setStakeType(quorumNumber, StakeType.TOTAL_SLASHABLE); @@ -278,7 +275,7 @@ contract StakeRegistry is StakeRegistryStorage { uint256[] memory indicesToRemove ) public virtual onlyCoordinatorOwner quorumExists(quorumNumber) { uint256 toRemoveLength = indicesToRemove.length; - require(toRemoveLength > 0, "StakeRegistry.removeStrategies: no indices to remove provided"); + require(toRemoveLength > 0, InputArrayLengthZero()); StrategyParams[] storage _strategyParams = strategyParams[quorumNumber]; IStrategy[] storage _strategiesPerQuorum = strategiesPerQuorum[quorumNumber]; @@ -307,8 +304,8 @@ contract StakeRegistry is StakeRegistryStorage { uint96[] calldata newMultipliers ) public virtual onlyCoordinatorOwner quorumExists(quorumNumber) { uint256 numStrats = strategyIndices.length; - require(numStrats > 0, "StakeRegistry.modifyStrategyParams: no strategy indices provided"); - require(newMultipliers.length == numStrats, "StakeRegistry.modifyStrategyParams: input length mismatch"); + require(numStrats > 0, InputArrayLengthZero()); + require(newMultipliers.length == numStrats, InputArrayLengthMismatch()); StrategyParams[] storage _strategyParams = strategyParams[quorumNumber]; @@ -442,25 +439,22 @@ contract StakeRegistry is StakeRegistryStorage { uint8 quorumNumber, StrategyParams[] memory _strategyParams ) internal { - require(_strategyParams.length > 0, "StakeRegistry._addStrategyParams: no strategies provided"); + require(_strategyParams.length > 0, InputArrayLengthZero()); uint256 numStratsToAdd = _strategyParams.length; uint256 numStratsExisting = strategyParams[quorumNumber].length; require( numStratsExisting + numStratsToAdd <= MAX_WEIGHING_FUNCTION_LENGTH, - "StakeRegistry._addStrategyParams: exceed MAX_WEIGHING_FUNCTION_LENGTH" + InputArrayLengthMismatch() ); for (uint256 i = 0; i < numStratsToAdd; i++) { // fairly gas-expensive internal loop to make sure that the *same* strategy cannot be added multiple times for (uint256 j = 0; j < (numStratsExisting + i); j++) { require( strategyParams[quorumNumber][j].strategy != _strategyParams[i].strategy, - "StakeRegistry._addStrategyParams: cannot add same strategy 2x" + InputDuplicateStrategy() ); } - require( - _strategyParams[i].multiplier > 0, - "StakeRegistry._addStrategyParams: cannot add strategy with zero weight" - ); + require(_strategyParams[i].multiplier > 0, InputMultiplierZero()); strategyParams[quorumNumber].push(_strategyParams[i]); strategiesPerQuorum[quorumNumber].push(_strategyParams[i].strategy); emit StrategyAddedToQuorum(quorumNumber, _strategyParams[i].strategy); @@ -496,13 +490,10 @@ contract StakeRegistry is StakeRegistryStorage { * - blockNumber should be >= the update block number * - the next update block number should be either 0 or strictly greater than blockNumber */ - require( - blockNumber >= stakeUpdate.updateBlockNumber, - "StakeRegistry._validateStakeUpdateAtBlockNumber: stakeUpdate is from after blockNumber" - ); + require(blockNumber >= stakeUpdate.updateBlockNumber, InvalidBlockNumber()); require( stakeUpdate.nextUpdateBlockNumber == 0 || blockNumber < stakeUpdate.nextUpdateBlockNumber, - "StakeRegistry._validateStakeUpdateAtBlockNumber: there is a newer stakeUpdate available before blockNumber" + InvalidBlockNumber() ); } @@ -785,7 +776,7 @@ contract StakeRegistry is StakeRegistryStorage { _checkQuorumExists(quorumNumber); require( _totalStakeHistory[quorumNumber][0].updateBlockNumber <= blockNumber, - "StakeRegistry.getTotalStakeIndicesAtBlockNumber: quorum has no stake history at blockNumber" + EmptyStakeHistory() ); uint256 length = _totalStakeHistory[quorumNumber].length; for (uint256 j = 0; j < length; j++) { @@ -821,17 +812,14 @@ contract StakeRegistry is StakeRegistryStorage { function _checkRegistryCoordinator() internal view { - require( - msg.sender == address(registryCoordinator), - "StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator" - ); + require(msg.sender == address(registryCoordinator), OnlyRegistryCoordinator()); } function _checkRegistryCoordinatorOwner() internal view { - require(msg.sender == IRegistryCoordinator(registryCoordinator).owner(), "StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator"); + require(msg.sender == IRegistryCoordinator(registryCoordinator).owner(), OnlyRegistryCoordinatorOwner()); } function _checkQuorumExists(uint8 quorumNumber) internal view { - require(_quorumExists(quorumNumber), "StakeRegistry.quorumExists: quorum does not exist"); + require(_quorumExists(quorumNumber), QuorumDoesNotExist()); } } diff --git a/src/interfaces/IBLSApkRegistry.sol b/src/interfaces/IBLSApkRegistry.sol index ced99f6c..a93d4d53 100644 --- a/src/interfaces/IBLSApkRegistry.sol +++ b/src/interfaces/IBLSApkRegistry.sol @@ -5,11 +5,34 @@ import {IRegistry} from "./IRegistry.sol"; import {BN254} from "../libraries/BN254.sol"; +interface IBLSApkRegistryErrors { + /// @dev Thrown when the caller is not the owner of the registry coordinator. + error OnlyRegistryCoordinatorOwner(); + /// @dev Thrown when a quorum being created already exists. + error QuorumAlreadyExists(); + /// @dev Thrown when a quorum does not exist. + error QuorumDoesNotExist(); + /// @dev Thrown when a BLS pubkey provided is zero pubkey + error ZeroPubKey(); + /// @dev Thrown when an operator has already registered a BLS pubkey. + error OperatorAlreadyRegistered(); + /// @dev Thrown when the operator is not registered. + error OperatorNotRegistered(); + /// @dev Thrown when a BLS pubkey has already been registered for an operator. + error BLSPubkeyAlreadyRegistered(); + /// @dev Thrown when either the G1 signature is wrong, or G1 and G2 private key do not match. + error InvalidBLSSignatureOrPrivateKey(); + /// @dev Thrown when the quorum apk update block number is too recent. + error BlockNumberTooRecent(); + /// @dev Thrown when blocknumber and index provided is not the latest apk update. + error BlockNumberNotLatest(); +} + /** * @title Minimal interface for a registry that keeps track of aggregate operator public keys across many quorums. * @author Layr Labs, Inc. */ -interface IBLSApkRegistry is IRegistry { +interface IBLSApkRegistry is IRegistry, IBLSApkRegistryErrors { // STRUCTS /// @notice Data structure used to track the history of the Aggregate Public Key of all operators struct ApkUpdate { diff --git a/src/interfaces/IBLSSignatureChecker.sol b/src/interfaces/IBLSSignatureChecker.sol index aa92e56f..4ab73f4c 100644 --- a/src/interfaces/IBLSSignatureChecker.sol +++ b/src/interfaces/IBLSSignatureChecker.sol @@ -7,13 +7,36 @@ import {IStakeRegistry, IDelegationManager} from "./IStakeRegistry.sol"; import {BN254} from "../libraries/BN254.sol"; +interface IBLSSignatureCheckerErrors { + /// @dev Thrown when the caller is not the registry coordinator owner. + error OnlyRegistryCoordinatorOwner(); + /// @dev Thrown when the quorum numbers input in is empty. + error InputEmptyQuorumNumbers(); + /// @dev Thrown when two array parameters have mismatching lengths. + error InputArrayLengthMismatch(); + /// @dev Thrown when the non-signer pubkey length does not match non-signer bitmap indices length. + error InputNonSignerLengthMismatch(); + /// @dev Thrown when the reference block number is invalid. + error InvalidReferenceBlocknumber(); + /// @dev Thrown when the non signer pubkeys are not sorted. + error NonSignerPubkeysNotSorted(); + /// @dev Thrown when StakeRegistry updates have not been updated within withdrawalDelayBlocks window + error StaleStakesForbidden(); + /// @dev Thrown when the quorum apk hash in storage does not match provided quorum apk. + error InvalidQuorumApkHash(); + /// @dev Thrown when BLS pairing precompile call fails. + error InvalidBLSPairingKey(); + /// @dev Thrown when BLS signature is invalid. + error InvalidBLSSignature(); +} + /** * @title Used for checking BLS aggregate signatures from the operators of a EigenLayer AVS with the RegistryCoordinator/BLSApkRegistry/StakeRegistry architechture. * @author Layr Labs, Inc. * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service * @notice This is the contract for checking the validity of aggregate operator signatures. */ -interface IBLSSignatureChecker { +interface IBLSSignatureChecker is IBLSSignatureCheckerErrors { // DATA STRUCTURES struct NonSignerStakesAndSignature { diff --git a/src/interfaces/IEjectionManager.sol b/src/interfaces/IEjectionManager.sol index 545e0a7c..478e21d8 100644 --- a/src/interfaces/IEjectionManager.sol +++ b/src/interfaces/IEjectionManager.sol @@ -1,11 +1,18 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; +interface IEjectionManagerErrors { + /// @dev Thrown when the caller is not the owner or ejector. + error OnlyOwnerOrEjector(); + /// @dev Thrown when quorum number exceeds MAX_QUORUM_COUNT. + error MaxQuorumCount(); +} + /** * @title Interface for a contract that ejects operators from an AVSs RegistryCoordinator * @author Layr Labs, Inc. */ -interface IEjectionManager { +interface IEjectionManager is IEjectionManagerErrors { /// @notice A quorum's ratelimit parameters struct QuorumEjectionParams { diff --git a/src/interfaces/IIndexRegistry.sol b/src/interfaces/IIndexRegistry.sol index 579fb23b..df1e0e73 100644 --- a/src/interfaces/IIndexRegistry.sol +++ b/src/interfaces/IIndexRegistry.sol @@ -3,11 +3,20 @@ pragma solidity ^0.8.27; import {IRegistry} from "./IRegistry.sol"; +interface IIndexRegistryErrors { + /// @dev Thrown when a function is called by an address that is not the RegistryCoordinator + error OnlyRegistryCoordinator(); + /// @dev Thrown when a quorum has 0 length history and thus does not exist + error QuorumDoesNotExist(); + /// @dev Thrown when an operatorId is not found in the registry at a given block number + error OperatorIdDoesNotExist(); +} + /** * @title Interface for a `Registry`-type contract that keeps track of an ordered list of operators for up to 256 quorums. * @author Layr Labs, Inc. */ -interface IIndexRegistry is IRegistry { +interface IIndexRegistry is IRegistry, IIndexRegistryErrors { // EVENTS // emitted when an operator's index in the ordered operator list for the quorum with number `quorumNumber` is updated diff --git a/src/interfaces/IServiceManager.sol b/src/interfaces/IServiceManager.sol index 133c3789..ccc0603f 100644 --- a/src/interfaces/IServiceManager.sol +++ b/src/interfaces/IServiceManager.sol @@ -9,12 +9,24 @@ import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/ import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; +interface IServiceManagerErrors { + /// @dev Thrown when a function is called by an address that is not the RegistryCoordinator + error OnlyRegistryCoordinator(); + /// @dev Thrown when a function is called by an address that is not the RewardsInitiator + error OnlyRewardsInitiator(); + /// @dev Thrown when a function is called by an address that is not the Slasher + error OnlyStakeRegistry(); + /// @dev Thrown when a function is called by an address that is not the Slasher + error OnlySlasher(); + /// @dev Thrown when a slashing proposal delay has not been met yet. + error DelayPeriodNotPassed(); +} /** * @title Minimal interface for a ServiceManager-type contract that forms the single point for an AVS to push updates to EigenLayer * @author Layr Labs, Inc. */ -interface IServiceManager is IServiceManagerUI { +interface IServiceManager is IServiceManagerUI, IServiceManagerErrors { /** * @notice Creates a new rewards submission to the EigenLayer RewardsCoordinator contract, to be split amongst the * set of stakers delegated to operators who are registered to this `avs` diff --git a/src/interfaces/ISlasher.sol b/src/interfaces/ISlasher.sol index a150bc94..44222150 100644 --- a/src/interfaces/ISlasher.sol +++ b/src/interfaces/ISlasher.sol @@ -25,6 +25,21 @@ interface ISlasherEvents { ); } +interface ISlasherErrors { + /// @dev Thrown when the caller is not the veto committee + error OnlyVetoCommittee(); + /// @dev Thrown when the caller is not the slasher + error OnlySlasher(); + /// @dev Thrown when the veto period has passed + error VetoPeriodPassed(); + /// @dev Thrown when the veto period has not passed + error VetoPeriodNotPassed(); + /// @dev Thrown when the slashing request is cancelled + error SlashingRequestIsCancelled(); + /// @dev Thrown when the slashing request was not already requested + error SlashingRequestNotRequested(); +} + interface ISlasherTypes { enum SlashingStatus { Null, @@ -41,4 +56,4 @@ interface ISlasherTypes { } -interface ISlasher is ISlasherEvents, ISlasherTypes{} +interface ISlasher is ISlasherEvents, ISlasherTypes, ISlasherErrors {} diff --git a/src/interfaces/IStakeRegistry.sol b/src/interfaces/IStakeRegistry.sol index 3b82fefb..d56c01c1 100644 --- a/src/interfaces/IStakeRegistry.sol +++ b/src/interfaces/IStakeRegistry.sol @@ -11,11 +11,37 @@ enum StakeType { TOTAL_SLASHABLE } +interface IStakeRegistryErrors { + /// @dev Thrown when the caller is not the registry coordinator + error OnlyRegistryCoordinator(); + /// @dev Thrown when the caller is not the owner of the registry coordinator + error OnlyRegistryCoordinatorOwner(); + /// @dev Thrown when the stake is below the minimum required for a quorum + error BelowMinimumStakeRequirement(); + /// @dev Thrown when a quorum being created already exists. + error QuorumAlreadyExists(); + /// @dev Thrown when a quorum does not exist. + error QuorumDoesNotExist(); + /// @dev Thrown when two array parameters have mismatching lengths. + error InputArrayLengthMismatch(); + /// @dev Thrown when input arrays length is zero. + error InputArrayLengthZero(); + /// @dev Thrown when a duplicate strategy is provided in input array. + error InputDuplicateStrategy(); + /// @dev Thrown when multiplier input is zero. + error InputMultiplierZero(); + /// @dev Thrown when the blocknumber provided is not >= the provided StakeUpdate's updateBlockNumber + /// or if the blocknumber provided is not the nextUpdateBlockNumber + error InvalidBlockNumber(); + /// @dev Thrown when the quorum has no stake history at block number provided. + error EmptyStakeHistory(); +} + /** * @title Interface for a `Registry` that keeps track of stakes of operators for up to 256 quorums. * @author Layr Labs, Inc. */ -interface IStakeRegistry is IRegistry { +interface IStakeRegistry is IRegistry, IStakeRegistryErrors { // DATA STRUCTURES /// @notice struct used to store the stakes of an individual operator or the sum of all operators' stakes, for storage diff --git a/src/libraries/BN254.sol b/src/libraries/BN254.sol index 61a20929..dcda7a31 100644 --- a/src/libraries/BN254.sol +++ b/src/libraries/BN254.sol @@ -46,6 +46,17 @@ library BN254 { uint256[2] Y; } + /// @dev Thrown when the sum of two points of G1 fails + error ECAddFailed(); + /// @dev Thrown when the scalar multiplication of a point of G1 fails + error ECMulFailed(); + /// @dev Thrown when the scalar is too large. + error ScalarTooLarge(); + /// @dev Thrown when the pairing check fails + error ECPairingFailed(); + /// @dev Thrown when the exponentiation mod fails + error ExpModFailed(); + function generatorG1() internal pure returns (G1Point memory) { return G1Point(1, 2); } @@ -114,7 +125,7 @@ library BN254 { } } - require(success, "ec-add-failed"); + require(success, ECAddFailed()); } /** @@ -124,7 +135,7 @@ library BN254 { * @dev this function is only safe to use if the scalar is 9 bits or less */ function scalar_mul_tiny(BN254.G1Point memory p, uint16 s) internal view returns (BN254.G1Point memory) { - require(s < 2**9, "scalar-too-large"); + require(s < 2**9, ScalarTooLarge()); // if s is 1 return p if(s == 1) { @@ -180,7 +191,7 @@ library BN254 { invalid() } } - require(success, "ec-mul-failed"); + require(success, ECMulFailed()); } /** @@ -223,7 +234,7 @@ library BN254 { } } - require(success, "pairing-opcode-failed"); + require(success, ECPairingFailed()); return out[0] != 0; } @@ -344,7 +355,7 @@ library BN254 { invalid() } } - require(success, "BN254.expMod: call failure"); + require(success, ExpModFailed()); return output[0]; } } diff --git a/src/libraries/BitmapUtils.sol b/src/libraries/BitmapUtils.sol index 9c53aadd..3930209a 100644 --- a/src/libraries/BitmapUtils.sol +++ b/src/libraries/BitmapUtils.sol @@ -7,6 +7,13 @@ pragma solidity ^0.8.27; * @author Layr Labs, Inc. */ library BitmapUtils { + /// @dev Thrown when the input byte array is too long to be converted to a bitmap + error BytesArrayLengthTooLong(); + /// @dev Thrown when the input byte array is not strictly ordered + error BytesArrayNotOrdered(); + /// @dev Thrown when the bitmap value is too large + error BitmapValueTooLarge(); + /** * @notice Byte arrays are meant to contain unique bytes. * If the array length exceeds 256, then it's impossible for all entries to be unique. @@ -24,8 +31,7 @@ library BitmapUtils { */ function orderedBytesArrayToBitmap(bytes memory orderedBytesArray) internal pure returns (uint256) { // sanity-check on input. a too-long input would fail later on due to having duplicate entry(s) - require(orderedBytesArray.length <= MAX_BYTE_ARRAY_LENGTH, - "BitmapUtils.orderedBytesArrayToBitmap: orderedBytesArray is too long"); + require(orderedBytesArray.length <= MAX_BYTE_ARRAY_LENGTH, BytesArrayLengthTooLong()); // return empty bitmap early if length of array is 0 if (orderedBytesArray.length == 0) { @@ -46,7 +52,7 @@ library BitmapUtils { // construct a single-bit mask from the numerical value of the next byte of the array bitMask = uint256(1 << uint8(orderedBytesArray[i])); // check strictly ascending array ordering by comparing the mask to the bitmap so far (revert if mask isn't greater than bitmap) - require(bitMask > bitmap, "BitmapUtils.orderedBytesArrayToBitmap: orderedBytesArray is not ordered"); + require(bitMask > bitmap, BytesArrayNotOrdered()); // add the entry to the bitmap bitmap = (bitmap | bitMask); } @@ -62,9 +68,7 @@ library BitmapUtils { function orderedBytesArrayToBitmap(bytes memory orderedBytesArray, uint8 bitUpperBound) internal pure returns (uint256) { uint256 bitmap = orderedBytesArrayToBitmap(orderedBytesArray); - require((1 << bitUpperBound) > bitmap, - "BitmapUtils.orderedBytesArrayToBitmap: bitmap exceeds max value" - ); + require((1 << bitUpperBound) > bitmap, BitmapValueTooLarge()); return bitmap; } diff --git a/src/libraries/QuorumBitmapHistoryLib.sol b/src/libraries/QuorumBitmapHistoryLib.sol index 72cbf114..50f6880b 100644 --- a/src/libraries/QuorumBitmapHistoryLib.sol +++ b/src/libraries/QuorumBitmapHistoryLib.sol @@ -6,6 +6,12 @@ import {IRegistryCoordinator} from "../interfaces/IRegistryCoordinator.sol"; /// @title QuorumBitmapHistoryLib /// @notice This library operates on the _operatorBitmapHistory in the RegistryCoordinator library QuorumBitmapHistoryLib { + /// @dev Thrown when the quorum bitmap update is not found + error BitmapUpdateNotFound(); + /// @dev Thrown when quorum bitmap update is after the block number + error BitmapUpdateIsAfterBlockNumber(); + /// @dev Thrown when the next update block number is not 0 and strictly greater than blockNumber + error NextBitmapUpdateIsBeforeBlockNumber(); /// @notice Retrieves the index of the quorum bitmap update at or before the specified block number /// @param self The mapping of operator IDs to their quorum bitmap update history @@ -88,12 +94,12 @@ library QuorumBitmapHistoryLib { */ require( blockNumber >= quorumBitmapUpdate.updateBlockNumber, - "RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from after blockNumber" + BitmapUpdateIsAfterBlockNumber() ); require( quorumBitmapUpdate.nextUpdateBlockNumber == 0 || blockNumber < quorumBitmapUpdate.nextUpdateBlockNumber, - "RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from before blockNumber" + NextBitmapUpdateIsBeforeBlockNumber() ); return quorumBitmapUpdate.quorumBitmap; diff --git a/src/slashers/VetoableSlasher.sol b/src/slashers/VetoableSlasher.sol index 0f9c623f..880b481f 100644 --- a/src/slashers/VetoableSlasher.sol +++ b/src/slashers/VetoableSlasher.sol @@ -32,20 +32,17 @@ contract VetoableSlashing is SlasherBase { function cancelSlashingRequest(uint256 requestId) external virtual onlyVetoCommittee { require( block.timestamp < slashingRequests[requestId].requestTimestamp + VETO_PERIOD, - "VetoableSlashing.cancelSlashingRequest: veto period has passed" + VetoPeriodPassed() ); - require(slashingRequests[requestId].status == SlashingStatus.Requested, "VetoableSlashing.cancelSlashingRequest: request is not in Requested status"); + require(slashingRequests[requestId].status == SlashingStatus.Requested, SlashingRequestNotRequested()); _cancelSlashingRequest(requestId); } function fulfillSlashingRequest(uint256 requestId) external virtual onlySlasher { SlashingRequest storage request = slashingRequests[requestId]; - require( - block.timestamp >= request.requestTimestamp + VETO_PERIOD, - "VetoableSlashing.fulfillSlashingRequest: veto period has not passed" - ); - require(request.status == SlashingStatus.Requested, "VetoableSlashing.fulfillSlashingRequest: request has been cancelled"); + require(block.timestamp >= request.requestTimestamp + VETO_PERIOD, VetoPeriodNotPassed()); + require(request.status == SlashingStatus.Requested, SlashingRequestIsCancelled()); request.status = SlashingStatus.Completed; @@ -72,6 +69,6 @@ contract VetoableSlashing is SlasherBase { } function _checkVetoCommittee(address account) internal view virtual { - require(account == vetoCommittee, "VetoableSlashing._checkVetoCommittee: caller is not the veto committee"); + require(account == vetoCommittee, OnlyVetoCommittee()); } } diff --git a/src/slashers/base/SlasherBase.sol b/src/slashers/base/SlasherBase.sol index 283a764c..f1d46870 100644 --- a/src/slashers/base/SlasherBase.sol +++ b/src/slashers/base/SlasherBase.sol @@ -28,7 +28,7 @@ abstract contract SlasherBase is Initializable, SlasherStorage { } function _checkSlasher(address account) internal view virtual { - require(account == slasher, "SlasherBase._checkSlasher: caller is not the slasher"); + require(account == slasher, OnlySlasher()); } } diff --git a/src/unaudited/ECDSAServiceManagerBase.sol b/src/unaudited/ECDSAServiceManagerBase.sol index 805a961a..e9fd55a3 100644 --- a/src/unaudited/ECDSAServiceManagerBase.sol +++ b/src/unaudited/ECDSAServiceManagerBase.sol @@ -44,10 +44,7 @@ abstract contract ECDSAServiceManagerBase is * This is used to restrict certain registration and deregistration functionality to the `stakeRegistry` */ modifier onlyStakeRegistry() { - require( - msg.sender == stakeRegistry, - "ECDSAServiceManagerBase.onlyStakeRegistry: caller is not the stakeRegistry" - ); + require(msg.sender == stakeRegistry, OnlyStakeRegistry()); _; } @@ -60,10 +57,7 @@ abstract contract ECDSAServiceManagerBase is } function _checkRewardsInitiator() internal view { - require( - msg.sender == rewardsInitiator, - "ECDSAServiceManagerBase.onlyRewardsInitiator: caller is not the rewards initiator" - ); + require(msg.sender == rewardsInitiator, OnlyRewardsInitiator()); } /** diff --git a/test/unit/BLSApkRegistryUnit.t.sol b/test/unit/BLSApkRegistryUnit.t.sol index aacfe9d8..fa644cae 100644 --- a/test/unit/BLSApkRegistryUnit.t.sol +++ b/test/unit/BLSApkRegistryUnit.t.sol @@ -8,6 +8,7 @@ import "../harnesses/BitmapUtilsWrapper.sol"; import "../utils/BLSMockAVSDeployer.sol"; import {IBLSApkRegistryEvents} from "../events/IBLSApkRegistryEvents.sol"; +import {IBLSApkRegistryErrors} from "../../src/interfaces/IBLSApkRegistry.sol"; contract BLSApkRegistryUnitTests is BLSMockAVSDeployer, IBLSApkRegistryEvents { using BitmapUtils for uint192; @@ -309,9 +310,7 @@ contract BLSApkRegistryUnitTests_configAndGetters is BLSApkRegistryUnitTests { cheats.assume(nonCoordinatorAddress != address(registryCoordinator)); cheats.prank(address(nonCoordinatorAddress)); - cheats.expectRevert( - "BLSApkRegistry._checkRegistryCoordinator: caller is not the registry coordinator" - ); + cheats.expectRevert(IBLSApkRegistryErrors.OnlyRegistryCoordinatorOwner.selector); blsApkRegistry.initializeQuorum(defaultQuorumNumber); } } @@ -334,9 +333,7 @@ contract BLSApkRegistryUnitTests_registerBLSPublicKey is .pubkeyRegistrationMessageHash(defaultOperator); cheats.prank(address(nonCoordinatorAddress)); - cheats.expectRevert( - "BLSApkRegistry._checkRegistryCoordinator: caller is not the registry coordinator" - ); + cheats.expectRevert(IBLSApkRegistryErrors.OnlyRegistryCoordinatorOwner.selector); blsApkRegistry.registerBLSPublicKey( defaultOperator, pubkeyRegistrationParams, @@ -353,9 +350,7 @@ contract BLSApkRegistryUnitTests_registerBLSPublicKey is .pubkeyRegistrationMessageHash(operator); cheats.prank(address(registryCoordinator)); - cheats.expectRevert( - "BLSApkRegistry.registerBLSPublicKey: cannot register zero pubkey" - ); + cheats.expectRevert(IBLSApkRegistryErrors.ZeroPubKey.selector); blsApkRegistry.registerBLSPublicKey( operator, pubkeyRegistrationParams, @@ -379,9 +374,7 @@ contract BLSApkRegistryUnitTests_registerBLSPublicKey is messageHash ); - cheats.expectRevert( - "BLSApkRegistry.registerBLSPublicKey: operator already registered pubkey" - ); + cheats.expectRevert(IBLSApkRegistryErrors.OperatorAlreadyRegistered.selector); blsApkRegistry.registerBLSPublicKey( operator, pubkeyRegistrationParams, @@ -412,9 +405,7 @@ contract BLSApkRegistryUnitTests_registerBLSPublicKey is messageHash ); - cheats.expectRevert( - "BLSApkRegistry.registerBLSPublicKey: public key already registered" - ); + cheats.expectRevert(IBLSApkRegistryErrors.BLSPubkeyAlreadyRegistered.selector); blsApkRegistry.registerBLSPublicKey( operator2, pubkeyRegistrationParams, @@ -442,9 +433,7 @@ contract BLSApkRegistryUnitTests_registerBLSPublicKey is pubkeyRegistrationParams.pubkeyRegistrationSignature = invalidSignature; cheats.startPrank(address(registryCoordinator)); - cheats.expectRevert( - "BLSApkRegistry.registerBLSPublicKey: either the G1 signature is wrong, or G1 and G2 private key do not match" - ); + cheats.expectRevert(IBLSApkRegistryErrors.InvalidBLSSignatureOrPrivateKey.selector); blsApkRegistry.registerBLSPublicKey( operator, pubkeyRegistrationParams, @@ -468,9 +457,7 @@ contract BLSApkRegistryUnitTests_registerBLSPublicKey is BN254.G1Point memory messageHash = registryCoordinator .pubkeyRegistrationMessageHash(operator); cheats.prank(address(registryCoordinator)); - cheats.expectRevert( - "BLSApkRegistry.registerBLSPublicKey: either the G1 signature is wrong, or G1 and G2 private key do not match" - ); + cheats.expectRevert(IBLSApkRegistryErrors.InvalidBLSSignatureOrPrivateKey.selector); blsApkRegistry.registerBLSPublicKey( operator, pubkeyRegistrationParams, @@ -544,9 +531,7 @@ contract BLSApkRegistryUnitTests_registerOperator is BLSApkRegistryUnitTests { cheats.assume(nonCoordinatorAddress != address(registryCoordinator)); cheats.prank(nonCoordinatorAddress); - cheats.expectRevert( - "BLSApkRegistry._checkRegistryCoordinator: caller is not the registry coordinator" - ); + cheats.expectRevert(IBLSApkRegistryErrors.OnlyRegistryCoordinatorOwner.selector); blsApkRegistry.registerOperator(nonCoordinatorAddress, new bytes(0)); } @@ -554,9 +539,7 @@ contract BLSApkRegistryUnitTests_registerOperator is BLSApkRegistryUnitTests { address operator ) public filterFuzzedAddressInputs(operator) { cheats.prank(address(registryCoordinator)); - cheats.expectRevert( - "BLSApkRegistry.getRegisteredPubkey: operator is not registered" - ); + cheats.expectRevert(IBLSApkRegistryErrors.OperatorNotRegistered.selector); blsApkRegistry.registerOperator(operator, new bytes(1)); } @@ -577,9 +560,7 @@ contract BLSApkRegistryUnitTests_registerOperator is BLSApkRegistryUnitTests { _registerDefaultBLSPubkey(operator); cheats.prank(address(registryCoordinator)); - cheats.expectRevert( - "BLSApkRegistry._processQuorumApkUpdate: quorum does not exist" - ); + cheats.expectRevert(IBLSApkRegistryErrors.QuorumDoesNotExist.selector); blsApkRegistry.registerOperator(operator, quorumNumbers); } @@ -672,9 +653,7 @@ contract BLSApkRegistryUnitTests_deregisterOperator is BLSApkRegistryUnitTests { cheats.assume(nonCoordinatorAddress != address(registryCoordinator)); cheats.prank(nonCoordinatorAddress); - cheats.expectRevert( - "BLSApkRegistry._checkRegistryCoordinator: caller is not the registry coordinator" - ); + cheats.expectRevert(IBLSApkRegistryErrors.OnlyRegistryCoordinatorOwner.selector); blsApkRegistry.deregisterOperator(nonCoordinatorAddress, new bytes(0)); } @@ -682,9 +661,7 @@ contract BLSApkRegistryUnitTests_deregisterOperator is BLSApkRegistryUnitTests { address operator ) public filterFuzzedAddressInputs(operator) { cheats.prank(address(registryCoordinator)); - cheats.expectRevert( - "BLSApkRegistry.getRegisteredPubkey: operator is not registered" - ); + cheats.expectRevert(IBLSApkRegistryErrors.OperatorNotRegistered.selector); blsApkRegistry.registerOperator(operator, new bytes(1)); } @@ -708,9 +685,7 @@ contract BLSApkRegistryUnitTests_deregisterOperator is BLSApkRegistryUnitTests { _registerOperator(operator, validQuorumNumbers); cheats.prank(address(registryCoordinator)); - cheats.expectRevert( - "BLSApkRegistry._processQuorumApkUpdate: quorum does not exist" - ); + cheats.expectRevert(IBLSApkRegistryErrors.QuorumDoesNotExist.selector); blsApkRegistry.deregisterOperator(operator, invalidQuorumNumbers); } @@ -1080,9 +1055,7 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { } if (wrongBlockNumber < startingBlockNumber + indexToCheck * 100) { emit log_named_uint("index too recent: ", indexToCheck); - cheats.expectRevert( - "BLSApkRegistry.getApkHashAtBlockNumberAndIndex: index too recent" - ); + cheats.expectRevert(IBLSApkRegistryErrors.BlockNumberTooRecent.selector); blsApkRegistry.getApkHashAtBlockNumberAndIndex( defaultQuorumNumber, wrongBlockNumber, @@ -1093,9 +1066,7 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { wrongBlockNumber >= startingBlockNumber + (indexToCheck + 1) * 100 ) { emit log_named_uint("index not latest: ", indexToCheck); - cheats.expectRevert( - "BLSApkRegistry.getApkHashAtBlockNumberAndIndex: not latest apk update" - ); + cheats.expectRevert(IBLSApkRegistryErrors.BlockNumberNotLatest.selector); blsApkRegistry.getApkHashAtBlockNumberAndIndex( defaultQuorumNumber, wrongBlockNumber, diff --git a/test/unit/BLSSignatureCheckerUnit.t.sol b/test/unit/BLSSignatureCheckerUnit.t.sol index 74b8f1da..d1d0ac7f 100644 --- a/test/unit/BLSSignatureCheckerUnit.t.sol +++ b/test/unit/BLSSignatureCheckerUnit.t.sol @@ -3,6 +3,10 @@ pragma solidity ^0.8.27; import "../../src/BLSSignatureChecker.sol"; import "../utils/BLSMockAVSDeployer.sol"; +import {IBLSSignatureCheckerErrors} from "../../src/interfaces/IBLSSignatureChecker.sol"; +import {IBLSApkRegistryErrors} from "../../src/interfaces/IBLSApkRegistry.sol"; +import {QuorumBitmapHistoryLib} from "../../src/libraries/QuorumBitmapHistoryLib.sol"; +import {IStakeRegistryErrors} from "../../src/interfaces/IStakeRegistry.sol"; contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { using BN254 for BN254.G1Point; @@ -18,7 +22,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { } function test_setStaleStakesForbidden_revert_notRegCoordOwner() public { - cheats.expectRevert("BLSSignatureChecker.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator"); + cheats.expectRevert(IBLSSignatureCheckerErrors.OnlyRegistryCoordinatorOwner.selector); blsSignatureChecker.setStaleStakesForbidden(true); } @@ -166,7 +170,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // make one part of the input incorrect length incorrectLengthInputs.quorumApks = new BN254.G1Point[](5); - cheats.expectRevert("BLSSignatureChecker.checkSignatures: input quorum length mismatch"); + cheats.expectRevert(IBLSSignatureCheckerErrors.InputArrayLengthMismatch.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -178,7 +182,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { incorrectLengthInputs.quorumApks = nonSignerStakesAndSignature.quorumApks; // make one part of the input incorrect length incorrectLengthInputs.quorumApkIndices = new uint32[](5); - cheats.expectRevert("BLSSignatureChecker.checkSignatures: input quorum length mismatch"); + cheats.expectRevert(IBLSSignatureCheckerErrors.InputArrayLengthMismatch.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -190,7 +194,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { incorrectLengthInputs.quorumApkIndices = nonSignerStakesAndSignature.quorumApkIndices; // make one part of the input incorrect length incorrectLengthInputs.totalStakeIndices = new uint32[](5); - cheats.expectRevert("BLSSignatureChecker.checkSignatures: input quorum length mismatch"); + cheats.expectRevert(IBLSSignatureCheckerErrors.InputArrayLengthMismatch.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -202,7 +206,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { incorrectLengthInputs.totalStakeIndices = nonSignerStakesAndSignature.totalStakeIndices; // make one part of the input incorrect length incorrectLengthInputs.nonSignerStakeIndices = new uint32[][](5); - cheats.expectRevert("BLSSignatureChecker.checkSignatures: input quorum length mismatch"); + cheats.expectRevert(IBLSSignatureCheckerErrors.InputArrayLengthMismatch.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -214,7 +218,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { incorrectLengthInputs.nonSignerStakeIndices = nonSignerStakesAndSignature.nonSignerStakeIndices; // make one part of the input incorrect length incorrectLengthInputs.nonSignerQuorumBitmapIndices = new uint32[](nonSignerStakesAndSignature.nonSignerPubkeys.length + 1); - cheats.expectRevert("BLSSignatureChecker.checkSignatures: input nonsigner length mismatch"); + cheats.expectRevert(IBLSSignatureCheckerErrors.InputNonSignerLengthMismatch.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -243,7 +247,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // Create an invalid reference block: any block number >= the current block uint32 invalidReferenceBlock = uint32(block.number + (pseudoRandomNumber % 20)); - cheats.expectRevert("BLSSignatureChecker.checkSignatures: invalid reference block"); + cheats.expectRevert(IBLSSignatureCheckerErrors.InvalidReferenceBlocknumber.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -263,7 +267,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // swap out a pubkey to make sure there is a duplicate nonSignerStakesAndSignature.nonSignerPubkeys[1] = nonSignerStakesAndSignature.nonSignerPubkeys[0]; - cheats.expectRevert("BLSSignatureChecker.checkSignatures: nonSignerPubkeys not sorted"); + cheats.expectRevert(IBLSSignatureCheckerErrors.NonSignerPubkeysNotSorted.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -284,7 +288,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // swap two pubkeys to ensure ordering is wrong (nonSignerStakesAndSignature.nonSignerPubkeys[0], nonSignerStakesAndSignature.nonSignerPubkeys[1]) = (nonSignerStakesAndSignature.nonSignerPubkeys[1], nonSignerStakesAndSignature.nonSignerPubkeys[0]); - cheats.expectRevert("BLSSignatureChecker.checkSignatures: nonSignerPubkeys not sorted"); + cheats.expectRevert(IBLSSignatureCheckerErrors.NonSignerPubkeysNotSorted.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -330,7 +334,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { referenceBlockNumber += 1; // roll forward to reference + 1 to ensure the referenceBlockNumber is still valid cheats.roll(referenceBlockNumber + 1); - cheats.expectRevert("BLSSignatureChecker.checkSignatures: StakeRegistry updates must be within withdrawalDelayBlocks window"); + cheats.expectRevert(IBLSSignatureCheckerErrors.StaleStakesForbidden.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -353,7 +357,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // set the nonSignerQuorumBitmapIndices to a different value nonSignerStakesAndSignature.nonSignerQuorumBitmapIndices[0] = 1; - cheats.expectRevert("RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from after blockNumber"); + cheats.expectRevert(QuorumBitmapHistoryLib.BitmapUpdateIsAfterBlockNumber.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -373,7 +377,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // set the totalStakeIndices to a different value nonSignerStakesAndSignature.totalStakeIndices[0] = 0; - cheats.expectRevert("StakeRegistry._validateStakeUpdateAtBlockNumber: there is a newer stakeUpdate available before blockNumber"); + cheats.expectRevert(IStakeRegistryErrors.InvalidBlockNumber.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -402,7 +406,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // set the nonSignerStakeIndices to a different value nonSignerStakesAndSignature.nonSignerStakeIndices[0][0] = 1; - cheats.expectRevert("StakeRegistry._validateStakeUpdateAtBlockNumber: stakeUpdate is from after blockNumber"); + cheats.expectRevert(IStakeRegistryErrors.InvalidBlockNumber.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -423,7 +427,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // set the quorumApkIndices to a different value nonSignerStakesAndSignature.quorumApkIndices[0] = 0; - cheats.expectRevert("BLSApkRegistry.getApkHashAtBlockNumberAndIndex: not latest apk update"); + cheats.expectRevert(IBLSApkRegistryErrors.BlockNumberNotLatest.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -443,7 +447,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // set the quorumApk to a different value nonSignerStakesAndSignature.quorumApks[0] = nonSignerStakesAndSignature.quorumApks[0].negate(); - cheats.expectRevert("BLSSignatureChecker.checkSignatures: quorumApk hash in storage does not match provided quorum apk"); + cheats.expectRevert(IBLSSignatureCheckerErrors.InvalidQuorumApkHash.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -463,7 +467,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // set the sigma to a different value nonSignerStakesAndSignature.sigma = nonSignerStakesAndSignature.sigma.negate(); - cheats.expectRevert("BLSSignatureChecker.checkSignatures: signature is invalid"); + cheats.expectRevert(IBLSSignatureCheckerErrors.InvalidBLSSignature.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, @@ -505,7 +509,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(0); // expect a non-specific low-level revert, since this call will ultimately fail as part of the precompile call - cheats.expectRevert("BLSSignatureChecker.checkSignatures: empty quorum input"); + cheats.expectRevert(IBLSSignatureCheckerErrors.InputEmptyQuorumNumbers.selector); blsSignatureChecker.checkSignatures( msgHash, quorumNumbers, diff --git a/test/unit/BitmapUtils.t.sol b/test/unit/BitmapUtils.t.sol index fcd742b2..a998dbe3 100644 --- a/test/unit/BitmapUtils.t.sol +++ b/test/unit/BitmapUtils.t.sol @@ -185,7 +185,7 @@ contract BitmapUtilsUnitTests_bytesArrayToBitmap is BitmapUtilsUnitTests { /// when calling orderedBytesArrayToBitmap function testFuzz_OrderedBytesArrayToBitmap_Revert_WhenNotOrdered(bytes memory originalBytesArray) public { cheats.assume(!bitmapUtilsWrapper.isArrayStrictlyAscendingOrdered(originalBytesArray)); - cheats.expectRevert("BitmapUtils.orderedBytesArrayToBitmap: orderedBytesArray is not ordered"); + cheats.expectRevert(BitmapUtils.BytesArrayNotOrdered.selector); bitmapUtilsWrapper.orderedBytesArrayToBitmap(originalBytesArray); } diff --git a/test/unit/EjectionManagerUnit.t.sol b/test/unit/EjectionManagerUnit.t.sol index 9f01af50..a95366f7 100644 --- a/test/unit/EjectionManagerUnit.t.sol +++ b/test/unit/EjectionManagerUnit.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.27; import {EjectionManager} from "../../src/EjectionManager.sol"; -import {IEjectionManager} from "../../src/interfaces/IEjectionManager.sol"; +import {IEjectionManager, IEjectionManagerErrors} from "../../src/interfaces/IEjectionManager.sol"; import "../utils/MockAVSDeployer.sol"; @@ -366,7 +366,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { function test_Revert_NotPermissioned() public { bytes32[][] memory operatorIds; - cheats.expectRevert("EjectionManager.ejectOperators: Only owner or ejector can eject"); + cheats.expectRevert(IEjectionManagerErrors.OnlyOwnerOrEjector.selector); ejectionManager.ejectOperators(operatorIds); EjectionManager.QuorumEjectionParams memory _quorumEjectionParams; diff --git a/test/unit/IndexRegistryUnit.t.sol b/test/unit/IndexRegistryUnit.t.sol index 36d7dc69..79d74e91 100644 --- a/test/unit/IndexRegistryUnit.t.sol +++ b/test/unit/IndexRegistryUnit.t.sol @@ -293,6 +293,7 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { // should revert with startBlocknumber cheats.expectRevert("IndexRegistry._operatorCountAtBlockNumber: quorum did not exist at given block number"); + indexRegistry.getOperatorListAtBlockNumber( quorumNumber, startBlockNumber @@ -418,7 +419,7 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { bytes memory quorumNumbers = new bytes(defaultQuorumNumber); cheats.prank(nonRegistryCoordinator); - cheats.expectRevert("IndexRegistry._checkRegistryCoordinator: caller is not the registry coordinator"); + cheats.expectRevert(IIndexRegistryErrors.OnlyRegistryCoordinator.selector); indexRegistry.registerOperator(bytes32(0), quorumNumbers); } @@ -439,7 +440,7 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { // Register for invalid quorums, should revert bytes memory invalidQuorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray(invalidBitmap); cheats.prank(address(registryCoordinator)); - cheats.expectRevert("IndexRegistry.registerOperator: quorum does not exist"); + cheats.expectRevert(IIndexRegistryErrors.QuorumDoesNotExist.selector); indexRegistry.registerOperator(operatorId1, invalidQuorumNumbers); } @@ -699,7 +700,7 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { bytes memory quorumNumbers = new bytes(defaultQuorumNumber); cheats.prank(nonRegistryCoordinator); - cheats.expectRevert("IndexRegistry._checkRegistryCoordinator: caller is not the registry coordinator"); + cheats.expectRevert(IIndexRegistryErrors.OnlyRegistryCoordinator.selector); indexRegistry.deregisterOperator(bytes32(0), quorumNumbers); } @@ -724,7 +725,7 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { // Deregister for invalid quorums, should revert cheats.prank(address(registryCoordinator)); - cheats.expectRevert("IndexRegistry.registerOperator: quorum does not exist"); + cheats.expectRevert(IIndexRegistryErrors.QuorumDoesNotExist.selector); indexRegistry.deregisterOperator(operatorId1, invalidQuorumNumbers); } diff --git a/test/unit/OperatorStateRetrieverUnit.t.sol b/test/unit/OperatorStateRetrieverUnit.t.sol index e25c8af0..55f6aabd 100644 --- a/test/unit/OperatorStateRetrieverUnit.t.sol +++ b/test/unit/OperatorStateRetrieverUnit.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.27; import "../utils/MockAVSDeployer.sol"; +import {IStakeRegistryErrors} from "../../src/interfaces/IStakeRegistry.sol"; contract OperatorStateRetrieverUnitTests is MockAVSDeployer { using BN254 for BN254.G1Point; @@ -186,9 +187,7 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { registryCoordinator.deregisterOperator(BitmapUtils.bitmapToBytesArray(1)); // should revert because the operator was registered for the first time after the reference block number - cheats.expectRevert( - "OperatorStateRetriever.getCheckSignaturesIndices: operator must be registered at blocknumber" - ); + cheats.expectRevert(OperatorStateRetriever.OperatorNotRegistered.selector); operatorStateRetriever.getCheckSignaturesIndices( registryCoordinator, uint32(block.number), @@ -203,7 +202,7 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { _registerOperatorWithCoordinator(defaultOperator, 1, defaultPubKey); - cheats.expectRevert("StakeRegistry.quorumExists: quorum does not exist"); + cheats.expectRevert(IStakeRegistryErrors.QuorumDoesNotExist.selector); operatorStateRetriever.getCheckSignaturesIndices( registryCoordinator, uint32(block.number), @@ -237,9 +236,7 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { cheats.prank(registryCoordinator.owner()); registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, minimumStake, strategyParams); - cheats.expectRevert( - "StakeRegistry.getTotalStakeIndicesAtBlockNumber: quorum has no stake history at blockNumber" - ); + cheats.expectRevert(IStakeRegistryErrors.EmptyStakeHistory.selector); operatorStateRetriever.getCheckSignaturesIndices( registryCoordinator, registrationBlockNumber + 5, diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index c3c8032d..72207dcc 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -3,6 +3,8 @@ pragma solidity ^0.8.27; import "../utils/MockAVSDeployer.sol"; import {IRegistryCoordinatorErrors} from "../../src/interfaces/IRegistryCoordinator.sol"; +import {QuorumBitmapHistoryLib} from "../../src/libraries/QuorumBitmapHistoryLib.sol"; +import {BitmapUtils} from "../../src/libraries/BitmapUtils.sol"; contract RegistryCoordinatorUnitTests is MockAVSDeployer { using BN254 for BN254.G1Point; @@ -281,7 +283,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni quorumNumbersTooLarge[0] = 0xC0; - cheats.expectRevert("BitmapUtils.orderedBytesArrayToBitmap: bitmap exceeds max value"); + cheats.expectRevert(BitmapUtils.BitmapValueTooLarge.selector); cheats.prank(defaultOperator); registryCoordinator.registerOperator(quorumNumbersTooLarge, defaultSocket, pubkeyRegistrationParams, emptySig); } @@ -294,7 +296,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni quorumNumbersNotCreated[0] = 0x0B; cheats.prank(defaultOperator); - cheats.expectRevert("BitmapUtils.orderedBytesArrayToBitmap: bitmap exceeds max value"); + cheats.expectRevert(BitmapUtils.BitmapValueTooLarge.selector); registryCoordinator.registerOperator(quorumNumbersNotCreated, defaultSocket, pubkeyRegistrationParams, emptySig); } @@ -523,7 +525,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni quorumNumbersTooLarge[0] = 0xC0; - cheats.expectRevert("BitmapUtils.orderedBytesArrayToBitmap: bitmap exceeds max value"); + cheats.expectRevert(BitmapUtils.BitmapValueTooLarge.selector); registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, quorumNumbersTooLarge, defaultSocket, emptySig); } @@ -1298,7 +1300,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist uint192 emptyBitmap = 0; // try an incorrect blockNumber input and confirm reversion - cheats.expectRevert("RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from after blockNumber"); + cheats.expectRevert(QuorumBitmapHistoryLib.BitmapUpdateIsAfterBlockNumber.selector); uint192 returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); blockNumber = registrationBlockNumber; @@ -1311,7 +1313,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // try an incorrect index input and confirm reversion index = 1; - cheats.expectRevert("RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from after blockNumber"); + cheats.expectRevert(QuorumBitmapHistoryLib.BitmapUpdateIsAfterBlockNumber.selector); returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); blockNumber = deregistrationBlockNumber; @@ -1324,7 +1326,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // try an incorrect index input and confirm reversion index = 0; - cheats.expectRevert("RegistryCoordinator.getQuorumBitmapAtBlockNumberByIndex: quorumBitmapUpdate is from before blockNumber"); + cheats.expectRevert(QuorumBitmapHistoryLib.NextBitmapUpdateIsBeforeBlockNumber.selector); returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); } } @@ -1669,7 +1671,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit address[][] memory operatorsToUpdate = new address[][](1); cheats.prank(defaultOperator); - cheats.expectRevert("BitmapUtils.orderedBytesArrayToBitmap: bitmap exceeds max value"); + cheats.expectRevert(BitmapUtils.BitmapValueTooLarge.selector); registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbersNotCreated); } diff --git a/test/unit/ServiceManagerBase.t.sol b/test/unit/ServiceManagerBase.t.sol index 8d37f9d6..ca3d0e9f 100644 --- a/test/unit/ServiceManagerBase.t.sol +++ b/test/unit/ServiceManagerBase.t.sol @@ -12,6 +12,7 @@ import {PermissionController} from "eigenlayer-contracts/src/contracts/permissio import {StrategyBase} from "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; import {IServiceManagerBaseEvents} from "../events/IServiceManagerBaseEvents.sol"; +import {IServiceManagerErrors} from "../../src/interfaces/IServiceManager.sol"; import "../utils/MockAVSDeployer.sol"; @@ -225,9 +226,7 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions; cheats.prank(caller); - cheats.expectRevert( - "ServiceManagerBase.onlyRewardsInitiator: caller is not the rewards initiator" - ); + cheats.expectRevert(IServiceManagerErrors.OnlyRewardsInitiator.selector); serviceManager.createAVSRewardsSubmission(rewardsSubmissions); } diff --git a/test/unit/StakeRegistryUnit.t.sol b/test/unit/StakeRegistryUnit.t.sol index 7e8f483e..a21a8c39 100644 --- a/test/unit/StakeRegistryUnit.t.sol +++ b/test/unit/StakeRegistryUnit.t.sol @@ -6,7 +6,7 @@ import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.so import "test/utils/MockAVSDeployer.sol"; import {StakeRegistry} from "src/StakeRegistry.sol"; -import {IStakeRegistry} from "src/interfaces/IStakeRegistry.sol"; +import {IStakeRegistry, IStakeRegistryErrors} from "src/interfaces/IStakeRegistry.sol"; import {IStakeRegistryEvents} from "test/events/IStakeRegistryEvents.sol"; import "../utils/MockAVSDeployer.sol"; @@ -580,9 +580,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint96 minimumStake, IStakeRegistry.StrategyParams[] memory strategyParams ) public { - cheats.expectRevert( - "StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator" - ); + cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinator.selector); stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); } @@ -591,7 +589,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint96 minimumStake, IStakeRegistry.StrategyParams[] memory strategyParams ) public fuzzOnlyInitializedQuorums(quorumNumber) { - cheats.expectRevert("StakeRegistry.initializeQuorum: quorum already exists"); + cheats.expectRevert(IStakeRegistryErrors.QuorumAlreadyExists.selector); cheats.prank(address(registryCoordinator)); stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); } @@ -603,7 +601,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { cheats.assume(quorumNumber >= nextQuorum); IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](0); - cheats.expectRevert("StakeRegistry._addStrategyParams: no strategies provided"); + cheats.expectRevert(IStakeRegistryErrors.InputArrayLengthZero.selector); cheats.prank(address(registryCoordinator)); stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); @@ -613,7 +611,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(i)))))), uint96(1) ); } - cheats.expectRevert("StakeRegistry._addStrategyParams: exceed MAX_WEIGHING_FUNCTION_LENGTH"); + cheats.expectRevert(IStakeRegistryErrors.InputArrayLengthMismatch.selector); cheats.prank(address(registryCoordinator)); stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); } @@ -731,9 +729,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint8 quorumNumber, uint96 minimumStakeForQuorum ) public fuzzOnlyInitializedQuorums(quorumNumber) { - cheats.expectRevert( - "StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator" - ); + cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinatorOwner.selector); stakeRegistry.setMinimumStakeForQuorum(quorumNumber, minimumStakeForQuorum); } @@ -743,7 +739,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { ) public { // quorums [0,nextQuorum) are initialized, so use an invalid quorumNumber cheats.assume(quorumNumber >= nextQuorum); - cheats.expectRevert("StakeRegistry.quorumExists: quorum does not exist"); + cheats.expectRevert(IStakeRegistryErrors.QuorumDoesNotExist.selector); cheats.prank(registryCoordinatorOwner); stakeRegistry.setMinimumStakeForQuorum(quorumNumber, minimumStakeForQuorum); } @@ -771,9 +767,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint8 quorumNumber, IStakeRegistry.StrategyParams[] memory strategyParams ) public fuzzOnlyInitializedQuorums(quorumNumber) { - cheats.expectRevert( - "StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator" - ); + cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinatorOwner.selector); stakeRegistry.addStrategies(quorumNumber, strategyParams); } @@ -783,7 +777,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { ) public { // quorums [0,nextQuorum) are initialized, so use an invalid quorumNumber cheats.assume(quorumNumber >= nextQuorum); - cheats.expectRevert("StakeRegistry.quorumExists: quorum does not exist"); + cheats.expectRevert(IStakeRegistryErrors.QuorumDoesNotExist.selector); cheats.prank(registryCoordinatorOwner); stakeRegistry.addStrategies(quorumNumber, strategyParams); } @@ -798,7 +792,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { strategyParams[0] = IStakeRegistry.StrategyParams(strat, uint96(WEIGHTING_DIVISOR)); strategyParams[1] = IStakeRegistry.StrategyParams(strat, uint96(WEIGHTING_DIVISOR)); - cheats.expectRevert("StakeRegistry._addStrategyParams: cannot add same strategy 2x"); + cheats.expectRevert(IStakeRegistryErrors.InputDuplicateStrategy.selector); cheats.prank(registryCoordinatorOwner); stakeRegistry.addStrategies(quorumNumber, strategyParams); } @@ -812,9 +806,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { new IStakeRegistry.StrategyParams[](2); strategyParams[0] = IStakeRegistry.StrategyParams(strat, 0); - cheats.expectRevert( - "StakeRegistry._addStrategyParams: cannot add strategy with zero weight" - ); + cheats.expectRevert(IStakeRegistryErrors.InputMultiplierZero.selector); cheats.prank(registryCoordinatorOwner); stakeRegistry.addStrategies(quorumNumber, strategyParams); } @@ -874,9 +866,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint8 quorumNumber, uint256[] memory indicesToRemove ) public fuzzOnlyInitializedQuorums(quorumNumber) { - cheats.expectRevert( - "StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator" - ); + cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinatorOwner.selector); stakeRegistry.removeStrategies(quorumNumber, indicesToRemove); } @@ -886,7 +876,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { ) public { // quorums [0,nextQuorum) are initialized, so use an invalid quorumNumber cheats.assume(quorumNumber >= nextQuorum); - cheats.expectRevert("StakeRegistry.quorumExists: quorum does not exist"); + cheats.expectRevert(IStakeRegistryErrors.QuorumDoesNotExist.selector); cheats.prank(registryCoordinatorOwner); stakeRegistry.removeStrategies(quorumNumber, indicesToRemove); } @@ -916,7 +906,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint8 quorumNumber = _initializeQuorum(minimumStake, numStrategiesToAdd); uint256[] memory indicesToRemove = new uint256[](0); - cheats.expectRevert("StakeRegistry.removeStrategies: no indices to remove provided"); + cheats.expectRevert(IStakeRegistryErrors.InputArrayLengthZero.selector); cheats.prank(registryCoordinatorOwner); stakeRegistry.removeStrategies(quorumNumber, indicesToRemove); } @@ -977,9 +967,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint256[] calldata strategyIndices, uint96[] calldata newMultipliers ) public fuzzOnlyInitializedQuorums(quorumNumber) { - cheats.expectRevert( - "StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator" - ); + cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinatorOwner.selector); stakeRegistry.modifyStrategyParams(quorumNumber, strategyIndices, newMultipliers); } @@ -990,7 +978,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { ) public { // quorums [0,nextQuorum) are initialized, so use an invalid quorumNumber cheats.assume(quorumNumber >= nextQuorum); - cheats.expectRevert("StakeRegistry.quorumExists: quorum does not exist"); + cheats.expectRevert(IStakeRegistryErrors.QuorumDoesNotExist.selector); cheats.prank(registryCoordinatorOwner); stakeRegistry.modifyStrategyParams(quorumNumber, strategyIndices, newMultipliers); } @@ -1001,7 +989,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { { uint256[] memory strategyIndices = new uint256[](0); uint96[] memory newMultipliers = new uint96[](0); - cheats.expectRevert("StakeRegistry.modifyStrategyParams: no strategy indices provided"); + cheats.expectRevert(IStakeRegistryErrors.InputArrayLengthZero.selector); cheats.prank(registryCoordinatorOwner); stakeRegistry.modifyStrategyParams(quorumNumber, strategyIndices, newMultipliers); } @@ -1013,7 +1001,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { ) public fuzzOnlyInitializedQuorums(quorumNumber) { cheats.assume(strategyIndices.length != newMultipliers.length); cheats.assume(strategyIndices.length > 0); - cheats.expectRevert("StakeRegistry.modifyStrategyParams: input length mismatch"); + cheats.expectRevert(IStakeRegistryErrors.InputArrayLengthMismatch.selector); cheats.prank(registryCoordinatorOwner); stakeRegistry.modifyStrategyParams(quorumNumber, strategyIndices, newMultipliers); } @@ -1072,9 +1060,7 @@ contract StakeRegistryUnitTests_Register is StakeRegistryUnitTests { function test_registerOperator_Revert_WhenNotRegistryCoordinator() public { (address operator, bytes32 operatorId) = _selectNewOperator(); - cheats.expectRevert( - "StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator" - ); + cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinator.selector); stakeRegistry.registerOperator(operator, operatorId, initializedQuorumBytes); } @@ -1084,7 +1070,7 @@ contract StakeRegistryUnitTests_Register is StakeRegistryUnitTests { // Get a list of valid quorums ending in an invalid quorum number bytes memory invalidQuorums = _fuzz_getInvalidQuorums(rand); - cheats.expectRevert("StakeRegistry.quorumExists: quorum does not exist"); + cheats.expectRevert(IStakeRegistryErrors.QuorumDoesNotExist.selector); cheats.prank(address(registryCoordinator)); stakeRegistry.registerOperator(setup.operator, setup.operatorId, invalidQuorums); } @@ -1118,9 +1104,7 @@ contract StakeRegistryUnitTests_Register is StakeRegistryUnitTests { } // Attempt to register - cheats.expectRevert( - "StakeRegistry.registerOperator: Operator does not meet minimum stake requirement for quorum" - ); + cheats.expectRevert(IStakeRegistryErrors.BelowMinimumStakeRequirement.selector); cheats.prank(address(registryCoordinator)); stakeRegistry.registerOperator(operator, operatorId, quorumNumbers); } @@ -1426,9 +1410,7 @@ contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { fuzzy_addtlStake: 0 }); - cheats.expectRevert( - "StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator" - ); + cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinator.selector); stakeRegistry.deregisterOperator(setup.operatorId, setup.quorumsToRemove); } @@ -1443,7 +1425,7 @@ contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { // Get a list of valid quorums ending in an invalid quorum number bytes memory invalidQuorums = _fuzz_getInvalidQuorums(rand); - cheats.expectRevert("StakeRegistry.quorumExists: quorum does not exist"); + cheats.expectRevert(IStakeRegistryErrors.QuorumDoesNotExist.selector); cheats.prank(address(registryCoordinator)); stakeRegistry.registerOperator(setup.operator, setup.operatorId, invalidQuorums); } @@ -1790,9 +1772,7 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { UpdateSetup memory setup = _fuzz_setupUpdateOperatorStake({registeredFor: initializedQuorumBitmap, fuzzy_Delta: 0}); - cheats.expectRevert( - "StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator" - ); + cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinator.selector); stakeRegistry.updateOperatorStake(setup.operator, setup.operatorId, setup.quorumNumbers); } @@ -1804,7 +1784,7 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { // Get a list of valid quorums ending in an invalid quorum number bytes memory invalidQuorums = _fuzz_getInvalidQuorums(rand); - cheats.expectRevert("StakeRegistry.quorumExists: quorum does not exist"); + cheats.expectRevert(IStakeRegistryErrors.QuorumDoesNotExist.selector); cheats.prank(address(registryCoordinator)); stakeRegistry.updateOperatorStake(setup.operator, setup.operatorId, invalidQuorums); } From 34456b31e21d57120c31ec14db215317f7b7c119 Mon Sep 17 00:00:00 2001 From: steven Date: Fri, 10 Jan 2025 16:38:42 -0500 Subject: [PATCH 40/52] chore: review remove setStakeType --- src/StakeRegistry.sol | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index 3d2b5089..4896ec7c 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -234,15 +234,6 @@ contract StakeRegistry is StakeRegistryStorage { _setMinimumStakeForQuorum(quorumNumber, minimumStake); } - /** - * @notice Sets the stake type for the registry for a specific quorum - * @param quorumNumber The quorum number to set the stake type for - * @param _stakeType The type of stake to track (TOTAL_DELEGATED, TOTAL_SLASHABLE, or BOTH) - */ - function setStakeType(uint8 quorumNumber, StakeType _stakeType) external onlyCoordinatorOwner quorumExists(quorumNumber) { - _setStakeType(quorumNumber, _stakeType); - } - /** * @notice Sets the look ahead time for checking operator shares for a specific quorum * @param quorumNumber The quorum number to set the look ahead period for From 2246b7d35a74192aa5351d58eef911abf8726847 Mon Sep 17 00:00:00 2001 From: steven Date: Fri, 10 Jan 2025 17:07:44 -0500 Subject: [PATCH 41/52] fix: wire up stake registry to call add and rm strategies for op set --- src/StakeRegistry.sol | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index 4896ec7c..162a9149 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -254,6 +254,16 @@ contract StakeRegistry is StakeRegistryStorage { StrategyParams[] memory _strategyParams ) public virtual onlyCoordinatorOwner quorumExists(quorumNumber) { _addStrategyParams(quorumNumber, _strategyParams); + + uint256 numStratsToAdd = _strategyParams.length; + + if (isOperatorSetQuorum(quorumNumber)){ + IStrategy[] memory strategiesToAdd = new IStrategy[](numStratsToAdd); + for (uint256 i = 0; i < numStratsToAdd; i++) { + strategiesToAdd[i] = _strategyParams[i].strategy; + } + serviceManager.addStrategyToOperatorSet(quorumNumber, strategiesToAdd); + } } /** @@ -270,17 +280,25 @@ contract StakeRegistry is StakeRegistryStorage { StrategyParams[] storage _strategyParams = strategyParams[quorumNumber]; IStrategy[] storage _strategiesPerQuorum = strategiesPerQuorum[quorumNumber]; + IStrategy[] memory _strategiesToRemove = new IStrategy[](toRemoveLength); for (uint256 i = 0; i < toRemoveLength; i++) { + _strategiesToRemove[i]=_strategyParams[indicesToRemove[i]].strategy; emit StrategyRemovedFromQuorum(quorumNumber, _strategyParams[indicesToRemove[i]].strategy); emit StrategyMultiplierUpdated(quorumNumber, _strategyParams[indicesToRemove[i]].strategy, 0); + + // Replace index to remove with the last item in the list, then pop the last item _strategyParams[indicesToRemove[i]] = _strategyParams[_strategyParams.length - 1]; _strategyParams.pop(); _strategiesPerQuorum[indicesToRemove[i]] = _strategiesPerQuorum[_strategiesPerQuorum.length - 1]; _strategiesPerQuorum.pop(); } + + if (isOperatorSetQuorum(quorumNumber)){ + serviceManager.removeStrategiesFromOperatorSet(quorumNumber, _strategiesToRemove); + } } /** @@ -560,7 +578,7 @@ contract StakeRegistry is StakeRegistryStorage { * @param quorumNumber The quorum number to check * @return True if the quorum is an operator set quorum */ - function isOperatorSetQuorum(uint8 quorumNumber) external view returns (bool) { + function isOperatorSetQuorum(uint8 quorumNumber) public view returns (bool) { bool isM2 = IRegistryCoordinator(registryCoordinator).isM2Quorum(quorumNumber); bool isOperatorSet = IRegistryCoordinator(registryCoordinator).isOperatorSetAVS(); return isOperatorSet && !isM2; From 3b8d801c4ea65b0f9db67b9095765ba18537c9fe Mon Sep 17 00:00:00 2001 From: Michael Sun <35479365+8sunyuan@users.noreply.github.com> Date: Fri, 17 Jan 2025 15:11:22 -0500 Subject: [PATCH 42/52] refactor: slashing UAM (#357) * refactor: uam * feat: add uam interfaces * fix: lookahead period to blocks * fix: tests * chore: storage report --- docs/storage-report/InstantSlasher.md | 28 ++- docs/storage-report/SlasherBase.md | 28 ++- docs/storage-report/SlasherStorage.md | 20 +-- docs/storage-report/VetoableSlasher.md | 19 +++ src/RegistryCoordinator.sol | 30 ++-- src/RegistryCoordinatorStorage.sol | 11 +- src/ServiceManagerBase.sol | 161 ++++++------------ src/ServiceManagerBaseStorage.sol | 7 +- src/StakeRegistry.sol | 49 +++--- src/StakeRegistryStorage.sol | 20 ++- src/interfaces/IServiceManager.sol | 67 ++++++-- src/interfaces/IServiceManagerUI.sol | 3 - src/interfaces/IStakeRegistry.sol | 4 +- src/slashers/InstantSlasher.sol | 13 +- src/slashers/VetoableSlasher.sol | 15 +- src/slashers/base/SlasherBase.sol | 19 ++- src/slashers/base/SlasherStorage.sol | 25 ++- .../RegistryCoordinatorHarness.t.sol | 3 +- test/harnesses/StakeRegistryHarness.sol | 3 +- test/integration/CoreRegistration.t.sol | 3 +- test/integration/IntegrationDeployer.t.sol | 9 +- test/mocks/ECDSAServiceManagerMock.sol | 24 +-- test/mocks/ServiceManagerMock.sol | 9 +- test/unit/RegistryCoordinatorUnit.t.sol | 20 +-- test/unit/ServiceManagerBase.t.sol | 2 +- test/unit/ServiceManagerRouter.t.sol | 2 +- test/unit/StakeRegistryUnit.t.sol | 3 +- test/utils/MockAVSDeployer.sol | 9 +- 28 files changed, 331 insertions(+), 275 deletions(-) diff --git a/docs/storage-report/InstantSlasher.md b/docs/storage-report/InstantSlasher.md index 1eafc2b8..7fb6cd76 100644 --- a/docs/storage-report/InstantSlasher.md +++ b/docs/storage-report/InstantSlasher.md @@ -1,17 +1,15 @@ -╭----------------+-------------+------+--------+-------+------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+=======================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/slashers/InstantSlasher.sol:InstantSlasher | -|----------------+-------------+------+--------+-------+------------------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/slashers/InstantSlasher.sol:InstantSlasher | -|----------------+-------------+------+--------+-------+------------------------------------------------| -| serviceManager | address | 0 | 2 | 20 | src/slashers/InstantSlasher.sol:InstantSlasher | -|----------------+-------------+------+--------+-------+------------------------------------------------| -| slasher | address | 1 | 0 | 20 | src/slashers/InstantSlasher.sol:InstantSlasher | -|----------------+-------------+------+--------+-------+------------------------------------------------| -| nextRequestId | uint256 | 2 | 0 | 32 | src/slashers/InstantSlasher.sol:InstantSlasher | -|----------------+-------------+------+--------+-------+------------------------------------------------| -| __gap | uint256[47] | 3 | 0 | 1504 | src/slashers/InstantSlasher.sol:InstantSlasher | -╰----------------+-------------+------+--------+-------+------------------------------------------------╯ +╭---------------+-------------+------+--------+-------+------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++======================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/slashers/InstantSlasher.sol:InstantSlasher | +|---------------+-------------+------+--------+-------+------------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/slashers/InstantSlasher.sol:InstantSlasher | +|---------------+-------------+------+--------+-------+------------------------------------------------| +| slasher | address | 0 | 2 | 20 | src/slashers/InstantSlasher.sol:InstantSlasher | +|---------------+-------------+------+--------+-------+------------------------------------------------| +| nextRequestId | uint256 | 1 | 0 | 32 | src/slashers/InstantSlasher.sol:InstantSlasher | +|---------------+-------------+------+--------+-------+------------------------------------------------| +| __gap | uint256[48] | 2 | 0 | 1536 | src/slashers/InstantSlasher.sol:InstantSlasher | +╰---------------+-------------+------+--------+-------+------------------------------------------------╯ diff --git a/docs/storage-report/SlasherBase.md b/docs/storage-report/SlasherBase.md index 2e210170..2e2c0eb9 100644 --- a/docs/storage-report/SlasherBase.md +++ b/docs/storage-report/SlasherBase.md @@ -1,17 +1,15 @@ -╭----------------+-------------+------+--------+-------+-----------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+======================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/slashers/base/SlasherBase.sol:SlasherBase | -|----------------+-------------+------+--------+-------+-----------------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/slashers/base/SlasherBase.sol:SlasherBase | -|----------------+-------------+------+--------+-------+-----------------------------------------------| -| serviceManager | address | 0 | 2 | 20 | src/slashers/base/SlasherBase.sol:SlasherBase | -|----------------+-------------+------+--------+-------+-----------------------------------------------| -| slasher | address | 1 | 0 | 20 | src/slashers/base/SlasherBase.sol:SlasherBase | -|----------------+-------------+------+--------+-------+-----------------------------------------------| -| nextRequestId | uint256 | 2 | 0 | 32 | src/slashers/base/SlasherBase.sol:SlasherBase | -|----------------+-------------+------+--------+-------+-----------------------------------------------| -| __gap | uint256[47] | 3 | 0 | 1504 | src/slashers/base/SlasherBase.sol:SlasherBase | -╰----------------+-------------+------+--------+-------+-----------------------------------------------╯ +╭---------------+-------------+------+--------+-------+-----------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++=====================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/slashers/base/SlasherBase.sol:SlasherBase | +|---------------+-------------+------+--------+-------+-----------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/slashers/base/SlasherBase.sol:SlasherBase | +|---------------+-------------+------+--------+-------+-----------------------------------------------| +| slasher | address | 0 | 2 | 20 | src/slashers/base/SlasherBase.sol:SlasherBase | +|---------------+-------------+------+--------+-------+-----------------------------------------------| +| nextRequestId | uint256 | 1 | 0 | 32 | src/slashers/base/SlasherBase.sol:SlasherBase | +|---------------+-------------+------+--------+-------+-----------------------------------------------| +| __gap | uint256[48] | 2 | 0 | 1536 | src/slashers/base/SlasherBase.sol:SlasherBase | +╰---------------+-------------+------+--------+-------+-----------------------------------------------╯ diff --git a/docs/storage-report/SlasherStorage.md b/docs/storage-report/SlasherStorage.md index 6a5ec3aa..6c947c7b 100644 --- a/docs/storage-report/SlasherStorage.md +++ b/docs/storage-report/SlasherStorage.md @@ -1,13 +1,11 @@ -╭----------------+-------------+------+--------+-------+-----------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+============================================================================================================+ -| serviceManager | address | 0 | 0 | 20 | src/slashers/base/SlasherStorage.sol:SlasherStorage | -|----------------+-------------+------+--------+-------+-----------------------------------------------------| -| slasher | address | 1 | 0 | 20 | src/slashers/base/SlasherStorage.sol:SlasherStorage | -|----------------+-------------+------+--------+-------+-----------------------------------------------------| -| nextRequestId | uint256 | 2 | 0 | 32 | src/slashers/base/SlasherStorage.sol:SlasherStorage | -|----------------+-------------+------+--------+-------+-----------------------------------------------------| -| __gap | uint256[47] | 3 | 0 | 1504 | src/slashers/base/SlasherStorage.sol:SlasherStorage | -╰----------------+-------------+------+--------+-------+-----------------------------------------------------╯ +╭---------------+-------------+------+--------+-------+-----------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++===========================================================================================================+ +| slasher | address | 0 | 0 | 20 | src/slashers/base/SlasherStorage.sol:SlasherStorage | +|---------------+-------------+------+--------+-------+-----------------------------------------------------| +| nextRequestId | uint256 | 1 | 0 | 32 | src/slashers/base/SlasherStorage.sol:SlasherStorage | +|---------------+-------------+------+--------+-------+-----------------------------------------------------| +| __gap | uint256[48] | 2 | 0 | 1536 | src/slashers/base/SlasherStorage.sol:SlasherStorage | +╰---------------+-------------+------+--------+-------+-----------------------------------------------------╯ diff --git a/docs/storage-report/VetoableSlasher.md b/docs/storage-report/VetoableSlasher.md index e69de29b..4d316b89 100644 --- a/docs/storage-report/VetoableSlasher.md +++ b/docs/storage-report/VetoableSlasher.md @@ -0,0 +1,19 @@ + +╭------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++========================================================================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/slashers/VetoableSlasher.sol:VetoableSlasher | +|------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/slashers/VetoableSlasher.sol:VetoableSlasher | +|------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------| +| slasher | address | 0 | 2 | 20 | src/slashers/VetoableSlasher.sol:VetoableSlasher | +|------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------| +| nextRequestId | uint256 | 1 | 0 | 32 | src/slashers/VetoableSlasher.sol:VetoableSlasher | +|------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------| +| __gap | uint256[48] | 2 | 0 | 1536 | src/slashers/VetoableSlasher.sol:VetoableSlasher | +|------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------| +| vetoCommittee | address | 50 | 0 | 20 | src/slashers/VetoableSlasher.sol:VetoableSlasher | +|------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------| +| slashingRequests | mapping(uint256 => struct ISlasherTypes.SlashingRequest) | 51 | 0 | 32 | src/slashers/VetoableSlasher.sol:VetoableSlasher | +╰------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------╯ + diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index bde1eafa..9a55ffc5 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -3,9 +3,8 @@ pragma solidity ^0.8.27; import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; -import {IAVSDirectory } from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {IStrategy } from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; -import { IAllocationManager, OperatorSet, IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManager, OperatorSet, IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {ISocketUpdater} from "./interfaces/ISocketUpdater.sol"; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; @@ -65,9 +64,16 @@ contract RegistryCoordinator is IStakeRegistry _stakeRegistry, IBLSApkRegistry _blsApkRegistry, IIndexRegistry _indexRegistry, + IAllocationManager _allocationManager, IPauserRegistry _pauserRegistry ) - RegistryCoordinatorStorage(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry) + RegistryCoordinatorStorage( + _serviceManager, + _stakeRegistry, + _blsApkRegistry, + _indexRegistry, + _allocationManager + ) EIP712("AVSRegistryCoordinator", "v0.0.1") Pausable(_pauserRegistry) { @@ -278,13 +284,6 @@ contract RegistryCoordinator is function enableOperatorSets() external onlyOwner { require(!isOperatorSetAVS, OperatorSetsEnabled()); - /// Triggers the updates to use operator sets ie setsAVSRegistrar - /// Opens up the AVS Registrar Hooks on this contract to be callable by the ALM - /// Allows creation of quorums with slashable and total delegated stake for operator sets - /// Sets all quorums created before this call as m2 quorums in a mapping so that we can gate function calls to deregister - /// M2 Registrations turn off once migrated. M2 deregistration remain open for only m2 quorums - // Set this contract as the AVS registrar in the service manager - serviceManager.setAVSRegistrar(IAVSRegistrar(address(this))); // Set all existing quorums as m2 quorums for (uint8 i = 0; i < quorumCount; i++) { @@ -389,8 +388,7 @@ contract RegistryCoordinator is // - all quorums should exist (checked against `quorumCount` in orderedBytesArrayToBitmap) // - there should be no duplicates in `quorumNumbers` // - there should be one list of operators per quorum - uint192 quorumBitmap = - uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); + BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount); require( operatorsPerQuorum.length == quorumNumbers.length, InputLengthMismatch() @@ -703,8 +701,7 @@ contract RegistryCoordinator is } function _checkAllocationManager() internal view { - address allocationManager = address(serviceManager.allocationManager()); - require(msg.sender == allocationManager, OnlyAllocationManager()); + require(msg.sender == address(allocationManager), OnlyAllocationManager()); } /** @@ -967,7 +964,10 @@ contract RegistryCoordinator is operatorSetId: quorumNumber, strategies: strategies }); - serviceManager.createOperatorSets(createSetParams); + allocationManager.createOperatorSets({ + avs: address(serviceManager), + params: createSetParams + }); } // Initialize stake registry based on stake type if (stakeType == StakeType.TOTAL_DELEGATED) { diff --git a/src/RegistryCoordinatorStorage.sol b/src/RegistryCoordinatorStorage.sol index 4911da4b..296da275 100644 --- a/src/RegistryCoordinatorStorage.sol +++ b/src/RegistryCoordinatorStorage.sol @@ -6,6 +6,7 @@ import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IAllocationManager, OperatorSet, IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { @@ -40,8 +41,10 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { IStakeRegistry public immutable stakeRegistry; /// @notice the Index Registry contract that will keep track of operators' indexes IIndexRegistry public immutable indexRegistry; - /// @notice the AVS Directory that tracks operator registrations to AVS and operator sets - IAVSDirectory public immutable avsDirectory; + + /// EigenLayer contracts + /// @notice the AllocationManager that tracks OperatorSets and Slashing in EigenLayer + IAllocationManager public immutable allocationManager; /******************************************************************************* STATE @@ -84,12 +87,14 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { IServiceManager _serviceManager, IStakeRegistry _stakeRegistry, IBLSApkRegistry _blsApkRegistry, - IIndexRegistry _indexRegistry + IIndexRegistry _indexRegistry, + IAllocationManager _allocationManager ) { serviceManager = _serviceManager; stakeRegistry = _stakeRegistry; blsApkRegistry = _blsApkRegistry; indexRegistry = _indexRegistry; + allocationManager = _allocationManager; } // storage gap for upgradeability diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index b7a07df8..72074630 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -7,13 +7,12 @@ import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSD import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; -import {IAllocationManager, IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IPermissionController} from "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; import {ServiceManagerBaseStorage} from "./ServiceManagerBaseStorage.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; -import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; import {BitmapUtils} from "./libraries/BitmapUtils.sol"; import {LibMergeSort} from "./libraries/LibMergeSort.sol"; @@ -40,32 +39,20 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _; } - /// @notice only slasher can call functions with this modifier - modifier onlySlasher() { - _checkSlasher(); - _; - } - - /// @notice only StakeRegistry can call functions with this modifier - modifier onlyStakeRegistry() { - _checkStakeRegistry(); - _; - } - /// @notice Sets the (immutable) `_registryCoordinator` address constructor( IAVSDirectory __avsDirectory, IRewardsCoordinator __rewardsCoordinator, IRegistryCoordinator __registryCoordinator, IStakeRegistry __stakeRegistry, - IAllocationManager __allocationManager + IPermissionController __permissionController ) ServiceManagerBaseStorage( __avsDirectory, __rewardsCoordinator, __registryCoordinator, __stakeRegistry, - __allocationManager + __permissionController ) { _disableInitializers(); @@ -73,12 +60,62 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { function __ServiceManagerBase_init( address initialOwner, - address _rewardsInitiator, - address _slasher + address _rewardsInitiator ) internal virtual onlyInitializing { _transferOwnership(initialOwner); _setRewardsInitiator(_rewardsInitiator); - _setSlasher(_slasher); + } + + /// @inheritdoc IServiceManager + function addPendingAdmin(address admin) external onlyOwner { + _permissionController.addPendingAdmin({ + account: address(this), + admin: admin + }); + } + + /// @inheritdoc IServiceManager + function removePendingAdmin(address pendingAdmin) external onlyOwner { + _permissionController.removePendingAdmin({ + account: address(this), + admin: pendingAdmin + }); + } + + /// @inheritdoc IServiceManager + function removeAdmin(address admin) external onlyOwner { + _permissionController.removeAdmin({ + account: address(this), + admin: admin + }); + } + + /// @inheritdoc IServiceManager + function setAppointee( + address appointee, + address target, + bytes4 selector + ) external onlyOwner { + _permissionController.setAppointee({ + account: address(this), + appointee: appointee, + target: target, + selector: selector + }); + } + + /// @inheritdoc IServiceManager + function removeAppointee( + address appointee, + address target, + bytes4 selector + ) external onlyOwner { + _permissionController.removeAppointee({ + account: address(this), + appointee: appointee, + target: target, + selector: selector + }); } /** @@ -90,10 +127,6 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _avsDirectory.updateAVSMetadataURI(_metadataURI); } - function slashOperator(IAllocationManager.SlashingParams memory params) external onlySlasher { - _allocationManager.slashOperator(address(this), params); - } - /** * @notice Creates a new rewards submission to the EigenLayer RewardsCoordinator contract, to be split amongst the * set of stakers delegated to operators who are registered to this `avs` @@ -124,18 +157,6 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _rewardsCoordinator.createAVSRewardsSubmission(rewardsSubmissions); } - function createOperatorSets(IAllocationManager.CreateSetParams[] memory params) external onlyRegistryCoordinator { - _allocationManager.createOperatorSets(address(this), params); - } - - function addStrategyToOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) external onlyStakeRegistry { - _allocationManager.addStrategiesToOperatorSet(address(this), operatorSetId, strategies); - } - - function removeStrategiesFromOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) external onlyStakeRegistry { - _allocationManager.removeStrategiesFromOperatorSet(address(this), operatorSetId, strategies); - } - /** * @notice Forwards a call to EigenLayer's AVSDirectory contract to confirm operator registration with the AVS * @param operator The address of the operator to register. @@ -156,22 +177,6 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _avsDirectory.deregisterOperatorFromAVS(operator); } - /** - * @notice Forwards a call to EigenLayer's AVSDirectory contract to deregister an operator from operator sets - * @param operator The address of the operator to deregister. - * @param operatorSetIds The IDs of the operator sets. - */ - function deregisterOperatorFromOperatorSets( - address operator, - uint32[] calldata operatorSetIds - ) public virtual onlyRegistryCoordinator { - _allocationManager.deregisterFromOperatorSets(IAllocationManagerTypes.DeregisterParams({ - operator: operator, - avs: address(this), - operatorSetIds: operatorSetIds - })); - } - /** * @notice Sets the rewards initiator address * @param newRewardsInitiator The new rewards initiator address @@ -181,53 +186,11 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _setRewardsInitiator(newRewardsInitiator); } - /** - * @notice Sets the AVS registrar address in the AllocationManager - * @param registrar The new AVS registrar address - * @dev Only callable by the registry coordinator - */ - function setAVSRegistrar(IAVSRegistrar registrar) external onlyRegistryCoordinator { - _allocationManager.setAVSRegistrar(address(this), registrar); - } - - /** - * @notice Proposes a new slasher address - * @param newSlasher The new slasher address - * @dev only callable by the owner - */ - function proposeNewSlasher(address newSlasher) external onlyOwner { - _proposeNewSlasher(newSlasher); - } - - /** - * @notice Accepts the proposed slasher address after the delay period - * @dev only callable by the owner - */ - function acceptProposedSlasher() external onlyOwner { - require( - block.timestamp >= slasherProposalTimestamp + SLASHER_PROPOSAL_DELAY, - DelayPeriodNotPassed() - ); - _setSlasher(proposedSlasher); - delete proposedSlasher; - } - function _setRewardsInitiator(address newRewardsInitiator) internal { emit RewardsInitiatorUpdated(rewardsInitiator, newRewardsInitiator); rewardsInitiator = newRewardsInitiator; } - function _proposeNewSlasher(address newSlasher) internal { - proposedSlasher = newSlasher; - slasherProposalTimestamp = block.timestamp; - emit SlasherProposed(newSlasher, slasherProposalTimestamp); - } - - function _setSlasher(address newSlasher) internal { - emit SlasherUpdated(slasher, newSlasher); - slasher = newSlasher; - } - /** * @notice Returns the list of strategies that the AVS supports for restaking * @dev This function is intended to be called off-chain @@ -306,19 +269,7 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { return address(_avsDirectory); } - function allocationManager() external view override returns (address) { - return address(_allocationManager); - } - function _checkRewardsInitiator() internal view { require(msg.sender == rewardsInitiator, OnlyRewardsInitiator()); } - - function _checkStakeRegistry() internal view { - require(msg.sender == address(_stakeRegistry), OnlyStakeRegistry()); - } - - function _checkSlasher() internal view { - require(msg.sender == slasher, OnlySlasher()); - } } diff --git a/src/ServiceManagerBaseStorage.sol b/src/ServiceManagerBaseStorage.sol index 6b8ee27b..6a4ef819 100644 --- a/src/ServiceManagerBaseStorage.sol +++ b/src/ServiceManagerBaseStorage.sol @@ -10,6 +10,7 @@ import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IPermissionController} from "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; /** * @title Storage variables for the `ServiceManagerBase` contract. @@ -26,7 +27,7 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab IRewardsCoordinator internal immutable _rewardsCoordinator; IRegistryCoordinator internal immutable _registryCoordinator; IStakeRegistry internal immutable _stakeRegistry; - IAllocationManager internal immutable _allocationManager; + IPermissionController internal immutable _permissionController; /** * @@ -55,13 +56,13 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab IRewardsCoordinator __rewardsCoordinator, IRegistryCoordinator __registryCoordinator, IStakeRegistry __stakeRegistry, - IAllocationManager __allocationManager + IPermissionController __permissionController ) { _avsDirectory = __avsDirectory; _rewardsCoordinator = __rewardsCoordinator; _registryCoordinator = __registryCoordinator; _stakeRegistry = __stakeRegistry; - _allocationManager = __allocationManager; + _permissionController = __permissionController; } // storage gap for upgradeability diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index 162a9149..359da941 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -46,8 +46,9 @@ contract StakeRegistry is StakeRegistryStorage { IRegistryCoordinator _registryCoordinator, IDelegationManager _delegationManager, IAVSDirectory _avsDirectory, + IAllocationManager _allocationManager, IServiceManager _serviceManager - ) StakeRegistryStorage(_registryCoordinator, _delegationManager, _avsDirectory, _serviceManager) {} + ) StakeRegistryStorage(_registryCoordinator, _delegationManager, _avsDirectory, _allocationManager, _serviceManager) {} /******************************************************************************* EXTERNAL FUNCTIONS - REGISTRY COORDINATOR @@ -237,10 +238,13 @@ contract StakeRegistry is StakeRegistryStorage { /** * @notice Sets the look ahead time for checking operator shares for a specific quorum * @param quorumNumber The quorum number to set the look ahead period for - * @param _lookAheadPeriod The number of days to look ahead when checking shares + * @param _lookAheadBlocks The number of blocks to look ahead when checking shares */ - function setSlashableStakeLookahead(uint8 quorumNumber, uint32 _lookAheadPeriod) external onlyCoordinatorOwner quorumExists(quorumNumber) { - _setLookAheadPeriod(quorumNumber, _lookAheadPeriod); + function setSlashableStakeLookahead( + uint8 quorumNumber, + uint32 _lookAheadBlocks + ) external onlyCoordinatorOwner quorumExists(quorumNumber) { + _setLookAheadPeriod(quorumNumber, _lookAheadBlocks); } /** @@ -262,7 +266,11 @@ contract StakeRegistry is StakeRegistryStorage { for (uint256 i = 0; i < numStratsToAdd; i++) { strategiesToAdd[i] = _strategyParams[i].strategy; } - serviceManager.addStrategyToOperatorSet(quorumNumber, strategiesToAdd); + allocationManager.addStrategiesToOperatorSet({ + avs: address(serviceManager), + operatorSetId: quorumNumber, + strategies: strategiesToAdd + }); } } @@ -297,7 +305,11 @@ contract StakeRegistry is StakeRegistryStorage { } if (isOperatorSetQuorum(quorumNumber)){ - serviceManager.removeStrategiesFromOperatorSet(quorumNumber, _strategiesToRemove); + allocationManager.removeStrategiesFromOperatorSet({ + avs: address(serviceManager), + operatorSetId: quorumNumber, + strategies: _strategiesToRemove + }); } } @@ -510,15 +522,14 @@ contract StakeRegistry is StakeRegistryStorage { function _getSlashableStakePerStrategy(uint8 quorumNumber, address operator) internal view returns (uint256[] memory) { address[] memory operators = new address[](1); operators[0] = operator; - uint32 beforeTimestamp = uint32(block.timestamp + slashableStakeLookAheadPerQuorum[quorumNumber]); - - uint256[][] memory slashableShares = IAllocationManager(serviceManager.allocationManager()) - .getMinimumSlashableStake( - OperatorSet(address(serviceManager), quorumNumber), - operators, - strategiesPerQuorum[quorumNumber], - beforeTimestamp - ); + uint32 beforeTimestamp = uint32(block.number + slashableStakeLookAheadPerQuorum[quorumNumber]); + + uint256[][] memory slashableShares = allocationManager.getMinimumSlashableStake( + OperatorSet(address(serviceManager), quorumNumber), + operators, + strategiesPerQuorum[quorumNumber], + beforeTimestamp + ); return slashableShares[0]; } @@ -811,12 +822,12 @@ contract StakeRegistry is StakeRegistryStorage { /** * @notice Sets the look ahead time for checking operator shares for a specific quorum * @param quorumNumber The quorum number to set the look ahead period for - * @param _lookAheadDays The number of days to look ahead when checking shares + * @param _lookAheadBlocks The number of blocks to look ahead when checking shares */ - function _setLookAheadPeriod(uint8 quorumNumber, uint32 _lookAheadDays) internal { + function _setLookAheadPeriod(uint8 quorumNumber, uint32 _lookAheadBlocks) internal { uint32 oldLookAheadDays = slashableStakeLookAheadPerQuorum[quorumNumber]; - slashableStakeLookAheadPerQuorum[quorumNumber] = _lookAheadDays; - emit LookAheadPeriodChanged(oldLookAheadDays, _lookAheadDays); + slashableStakeLookAheadPerQuorum[quorumNumber] = _lookAheadBlocks; + emit LookAheadPeriodChanged(oldLookAheadDays, _lookAheadBlocks); } diff --git a/src/StakeRegistryStorage.sol b/src/StakeRegistryStorage.sol index fb4967ac..26f72873 100644 --- a/src/StakeRegistryStorage.sol +++ b/src/StakeRegistryStorage.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.27; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {IStrategyManager, IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; @@ -29,6 +30,9 @@ abstract contract StakeRegistryStorage is IStakeRegistry { /// @notice The address of the Delegation contract for EigenLayer. IAVSDirectory public immutable avsDirectory; + /// @notice the address of the AllocationManager for EigenLayer. + IAllocationManager public immutable allocationManager; + /// @notice the address of the ServiceManager associtated with the stake registries IServiceManager public immutable serviceManager; @@ -43,29 +47,35 @@ abstract contract StakeRegistryStorage is IStakeRegistry { mapping(uint8 => StakeUpdate[]) internal _totalStakeHistory; /// @notice mapping from operator's operatorId to the history of their stake updates - mapping(bytes32 => mapping(uint8 => StakeUpdate[])) internal operatorStakeHistory; + mapping(bytes32 operatorId => mapping(uint8 => StakeUpdate[])) internal operatorStakeHistory; /** * @notice mapping from quorum number to the list of strategies considered and their * corresponding multipliers for that specific quorum */ - mapping(uint8 => StrategyParams[]) public strategyParams; - mapping(uint8 => IStrategy[]) public strategiesPerQuorum; + mapping(uint8 quorumNumber => StrategyParams[]) public strategyParams; + + /// @notice mapping from quorum number to the list of strategies considered for that specific quorum + mapping(uint8 quorumNumber => IStrategy[]) public strategiesPerQuorum; - mapping(uint8 => StakeType) public stakeTypePerQuorum; + /// @notice mapping from quorum number to the StakeType for that specific quorum + mapping(uint8 quorumNumber => StakeType) public stakeTypePerQuorum; - mapping(uint8 => uint32) public slashableStakeLookAheadPerQuorum; + /// @notice mapping from quorum number to the slashable stake look ahead time (in blocks) + mapping(uint8 quorumNumber => uint32) public slashableStakeLookAheadPerQuorum; constructor( IRegistryCoordinator _registryCoordinator, IDelegationManager _delegationManager, IAVSDirectory _avsDirectory, + IAllocationManager _allocationManager, IServiceManager _serviceManager ) { registryCoordinator = address(_registryCoordinator); delegation = _delegationManager; avsDirectory = _avsDirectory; serviceManager = _serviceManager; + allocationManager = _allocationManager; } // storage gap for upgradeability diff --git a/src/interfaces/IServiceManager.sol b/src/interfaces/IServiceManager.sol index ccc0603f..5f3ab220 100644 --- a/src/interfaces/IServiceManager.sol +++ b/src/interfaces/IServiceManager.sol @@ -27,6 +27,9 @@ interface IServiceManagerErrors { * @author Layr Labs, Inc. */ interface IServiceManager is IServiceManagerUI, IServiceManagerErrors { + // EVENTS + event RewardsInitiatorUpdated(address prevRewardsInitiator, address newRewardsInitiator); + /** * @notice Creates a new rewards submission to the EigenLayer RewardsCoordinator contract, to be split amongst the * set of stakers delegated to operators who are registered to this `avs` @@ -40,30 +43,58 @@ interface IServiceManager is IServiceManagerUI, IServiceManagerErrors { */ function createAVSRewardsSubmission(IRewardsCoordinator.RewardsSubmission[] calldata rewardsSubmissions) external; - function createOperatorSets(IAllocationManager.CreateSetParams[] memory params) external; - - function addStrategyToOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) external; - - function removeStrategiesFromOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) external; + /******************************************************************************* + PERMISSIONCONTROLLER FUNCTIONS + *******************************************************************************/ + /** + * @notice Calls `addPendingAdmin` on the `PermissionController` contract + * with `account` being the address of this contract. + * @param admin The address of the admin to add + * @dev Only callable by the owner of the contract + */ + function addPendingAdmin(address admin) external; /** - * @notice Sets the AVS registrar address in the AllocationManager - * @param registrar The new AVS registrar address - * @dev Only callable by the registry coordinator + * @notice Calls `removePendingAdmin` on the `PermissionController` contract + * with `account` being the address of this contract. + * @param pendingAdmin The address of the pending admin to remove + * @dev Only callable by the owner of the contract */ - function setAVSRegistrar(IAVSRegistrar registrar) external; + function removePendingAdmin(address pendingAdmin) external; /** - * @notice Forwards a call to EigenLayer's AVSDirectory contract to deregister an operator from operator sets - * @param operator The address of the operator to deregister. - * @param operatorSetIds The IDs of the operator sets. + * @notice Calls `removeAdmin` on the `PermissionController` contract + * with `account` being the address of this contract. + * @param admin The address of the admin to remove + * @dev Only callable by the owner of the contract */ - function deregisterOperatorFromOperatorSets(address operator, uint32[] calldata operatorSetIds) external; + function removeAdmin(address admin) external; - function slashOperator(IAllocationManagerTypes.SlashingParams memory params) external; + /** + * @notice Calls `setAppointee` on the `PermissionController` contract + * with `account` being the address of this contract. + * @param appointee The address of the appointee to set + * @param target The address of the target to set the appointee for + * @param selector The function selector to set the appointee for + * @dev Only callable by the owner of the contract + */ + function setAppointee( + address appointee, + address target, + bytes4 selector + ) external; - // EVENTS - event RewardsInitiatorUpdated(address prevRewardsInitiator, address newRewardsInitiator); - event SlasherUpdated(address prevSlasher, address newSlasher); - event SlasherProposed(address newSlasher, uint256 slasherProposalTimestamp); + /** + * @notice Calls `removeAppointee` on the `PermissionController` contract + * with `account` being the address of this contract. + * @param appointee The address of the appointee to remove + * @param target The address of the target to remove the appointee for + * @param selector The function selector to remove the appointee for + * @dev Only callable by the owner of the contract + */ + function removeAppointee( + address appointee, + address target, + bytes4 selector + ) external; } diff --git a/src/interfaces/IServiceManagerUI.sol b/src/interfaces/IServiceManagerUI.sol index 7be5a3f0..92cdce9c 100644 --- a/src/interfaces/IServiceManagerUI.sol +++ b/src/interfaces/IServiceManagerUI.sol @@ -58,7 +58,4 @@ interface IServiceManagerUI { /// @notice Returns the EigenLayer AVSDirectory contract. function avsDirectory() external view returns (address); - - /// @notice Returns the EigenLayer AllocationManager contract. - function allocationManager() external view returns (address); } diff --git a/src/interfaces/IStakeRegistry.sol b/src/interfaces/IStakeRegistry.sol index d56c01c1..85417ecc 100644 --- a/src/interfaces/IStakeRegistry.sol +++ b/src/interfaces/IStakeRegistry.sol @@ -73,8 +73,8 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { uint96 stake ); - /// @notice emitted when the look ahead time for checking operator shares is updated - event LookAheadPeriodChanged(uint32 oldLookAheadDays, uint32 newLookAheadDays); + /// @notice emitted when the look ahead time(in blocks) for checking operator shares is updated + event LookAheadPeriodChanged(uint32 oldLookAheadBlocks, uint32 newLookAheadBlocks); /// @notice emitted when the stake type is updated event StakeTypeSet(StakeType newStakeType); diff --git a/src/slashers/InstantSlasher.sol b/src/slashers/InstantSlasher.sol index 976ad896..536259ba 100644 --- a/src/slashers/InstantSlasher.sol +++ b/src/slashers/InstantSlasher.sol @@ -3,12 +3,19 @@ pragma solidity ^0.8.27; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IServiceManager} from "../interfaces/IServiceManager.sol"; import {SlasherBase} from "./base/SlasherBase.sol"; contract InstantSlasher is SlasherBase { - function initialize(address _serviceManager, address _slasher) external initializer { - __SlasherBase_init(_serviceManager, _slasher); + constructor( + IAllocationManager _allocationManager, + IServiceManager _serviceManager, + address _slasher + ) SlasherBase(_allocationManager, _serviceManager) {} + + function initialize(address _slasher) external initializer { + __SlasherBase_init(_slasher); } function fulfillSlashingRequest( @@ -17,6 +24,4 @@ contract InstantSlasher is SlasherBase { uint256 requestId = nextRequestId++; _fulfillSlashingRequest(requestId, _slashingParams); } - - } \ No newline at end of file diff --git a/src/slashers/VetoableSlasher.sol b/src/slashers/VetoableSlasher.sol index 880b481f..37cbb3b9 100644 --- a/src/slashers/VetoableSlasher.sol +++ b/src/slashers/VetoableSlasher.sol @@ -2,10 +2,12 @@ pragma solidity ^0.8.27; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; -import {SlasherBase} from "./base/SlasherBase.sol"; import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {SlasherBase} from "./base/SlasherBase.sol"; +import {IServiceManager} from "../interfaces/IServiceManager.sol"; + -contract VetoableSlashing is SlasherBase { +contract VetoableSlasher is SlasherBase { uint256 public constant VETO_PERIOD = 3 days; address public vetoCommittee; @@ -16,12 +18,17 @@ contract VetoableSlashing is SlasherBase { _; } + constructor( + IAllocationManager _allocationManager, + IServiceManager _serviceManager, + address _slasher + ) SlasherBase(_allocationManager, _serviceManager) {} + function initialize( - address _serviceManager, address _vetoCommittee, address _slasher ) external virtual initializer { - __SlasherBase_init(_serviceManager, _slasher); + __SlasherBase_init(_slasher); vetoCommittee = _vetoCommittee; } diff --git a/src/slashers/base/SlasherBase.sol b/src/slashers/base/SlasherBase.sol index f1d46870..30a269f6 100644 --- a/src/slashers/base/SlasherBase.sol +++ b/src/slashers/base/SlasherBase.sol @@ -14,8 +14,14 @@ abstract contract SlasherBase is Initializable, SlasherStorage { _; } - function __SlasherBase_init(address _serviceManager, address _slasher) internal onlyInitializing { - serviceManager = _serviceManager; + constructor( + IAllocationManager _allocationManager, + IServiceManager _serviceManager + ) SlasherStorage(_allocationManager, _serviceManager) { + _disableInitializers(); + } + + function __SlasherBase_init(address _slasher) internal onlyInitializing { slasher = _slasher; } @@ -23,7 +29,10 @@ abstract contract SlasherBase is Initializable, SlasherStorage { uint256 _requestId, IAllocationManager.SlashingParams memory _params ) internal virtual { - IServiceManager(serviceManager).slashOperator(_params); + allocationManager.slashOperator({ + avs: address(serviceManager), + params: _params + }); emit OperatorSlashed(_requestId, _params.operator, _params.operatorSetId, _params.wadsToSlash, _params.description); } @@ -31,7 +40,3 @@ abstract contract SlasherBase is Initializable, SlasherStorage { require(account == slasher, OnlySlasher()); } } - - - - diff --git a/src/slashers/base/SlasherStorage.sol b/src/slashers/base/SlasherStorage.sol index a3924f34..3e5e9860 100644 --- a/src/slashers/base/SlasherStorage.sol +++ b/src/slashers/base/SlasherStorage.sol @@ -1,11 +1,32 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; +import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {ISlasher} from "../../interfaces/ISlasher.sol"; +import {IServiceManager} from "../../interfaces/IServiceManager.sol"; contract SlasherStorage is ISlasher { - address public serviceManager; + + /******************************************************************************* + CONSTANTS AND IMMUTABLES + *******************************************************************************/ + + /// @notice the AllocationManager that tracks OperatorSets and Slashing in EigenLayer + IAllocationManager public immutable allocationManager; + /// @notice the ServiceManager for this AVS, which forwards calls onto EigenLayer's core contracts + IServiceManager public immutable serviceManager; + + /******************************************************************************* + STATE + *******************************************************************************/ + address public slasher; + uint256 public nextRequestId; - uint256[47] private __gap; + constructor(IAllocationManager _allocationManager, IServiceManager _serviceManager) { + allocationManager = _allocationManager; + serviceManager = _serviceManager; + } + + uint256[48] private __gap; } \ No newline at end of file diff --git a/test/harnesses/RegistryCoordinatorHarness.t.sol b/test/harnesses/RegistryCoordinatorHarness.t.sol index 860e70dc..c1006682 100644 --- a/test/harnesses/RegistryCoordinatorHarness.t.sol +++ b/test/harnesses/RegistryCoordinatorHarness.t.sol @@ -12,8 +12,9 @@ contract RegistryCoordinatorHarness is RegistryCoordinator, Test { IStakeRegistry _stakeRegistry, IBLSApkRegistry _blsApkRegistry, IIndexRegistry _indexRegistry, + IAllocationManager _allocationManager, IPauserRegistry _pauserRegistry - ) RegistryCoordinator(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry, _pauserRegistry) { + ) RegistryCoordinator(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry, _allocationManager, _pauserRegistry) { _transferOwnership(msg.sender); } diff --git a/test/harnesses/StakeRegistryHarness.sol b/test/harnesses/StakeRegistryHarness.sol index 7d00b107..38ee15e8 100644 --- a/test/harnesses/StakeRegistryHarness.sol +++ b/test/harnesses/StakeRegistryHarness.sol @@ -9,8 +9,9 @@ contract StakeRegistryHarness is StakeRegistry { IRegistryCoordinator _registryCoordinator, IDelegationManager _delegationManager, IAVSDirectory _avsDirectory, + IAllocationManager _allocationManager, IServiceManager _serviceManager - ) StakeRegistry(_registryCoordinator, _delegationManager, _avsDirectory, _serviceManager) { + ) StakeRegistry(_registryCoordinator, _delegationManager, _avsDirectory, _allocationManager, _serviceManager) { } function recordOperatorStakeUpdate(bytes32 operatorId, uint8 quorumNumber, uint96 newStake) external returns(int256) { diff --git a/test/integration/CoreRegistration.t.sol b/test/integration/CoreRegistration.t.sol index 4fbfc3ad..68f586a9 100644 --- a/test/integration/CoreRegistration.t.sol +++ b/test/integration/CoreRegistration.t.sol @@ -83,7 +83,7 @@ contract Test_CoreRegistration is MockAVSDeployer { rewardsCoordinatorMock, registryCoordinator, stakeRegistry, - allocationManager + permissionController ); registryCoordinatorImplementation = new RegistryCoordinatorHarness( @@ -91,6 +91,7 @@ contract Test_CoreRegistration is MockAVSDeployer { stakeRegistry, blsApkRegistry, indexRegistry, + allocationManager, pauserRegistry ); diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index dda8ce58..acb89afd 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -332,7 +332,7 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { cheats.stopPrank(); StakeRegistry stakeRegistryImplementation = new StakeRegistry( - IRegistryCoordinator(registryCoordinator), IDelegationManager(delegationManager), IAVSDirectory(avsDirectory), IServiceManager(serviceManager) + IRegistryCoordinator(registryCoordinator), IDelegationManager(delegationManager), IAVSDirectory(avsDirectory), allocationManager, IServiceManager(serviceManager) ); BLSApkRegistry blsApkRegistryImplementation = new BLSApkRegistry(IRegistryCoordinator(registryCoordinator)); @@ -343,7 +343,7 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { rewardsCoordinator, IRegistryCoordinator(registryCoordinator), stakeRegistry, - allocationManager + permissionController ); proxyAdmin.upgrade( @@ -368,15 +368,14 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { serviceManager.initialize({ initialOwner: registryCoordinatorOwner, - rewardsInitiator: address(msg.sender), - slasher: address(msg.sender) + rewardsInitiator: address(msg.sender) }); StakeType[] memory quorumStakeTypes = new StakeType[](0); uint32[] memory slashableStakeQuorumLookAheadPeriods = new uint32[](0); RegistryCoordinator registryCoordinatorImplementation = - new RegistryCoordinator(serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, pauserRegistry); + new RegistryCoordinator(serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, allocationManager, pauserRegistry); proxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(registryCoordinator))), address(registryCoordinatorImplementation), diff --git a/test/mocks/ECDSAServiceManagerMock.sol b/test/mocks/ECDSAServiceManagerMock.sol index 102d076e..df93cdd1 100644 --- a/test/mocks/ECDSAServiceManagerMock.sol +++ b/test/mocks/ECDSAServiceManagerMock.sol @@ -28,21 +28,21 @@ contract ECDSAServiceManagerMock is ECDSAServiceManagerBase { __ServiceManagerBase_init(initialOwner, rewardsInitiator); } - function createOperatorSets(IAllocationManager.CreateSetParams[] memory params) external{} + function addPendingAdmin(address admin) external {} - function addStrategyToOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) external{} + function removePendingAdmin(address pendingAdmin) external {} - function removeStrategiesFromOperatorSet(uint32 operatorSetId, IStrategy[] memory strategies) external{} + function removeAdmin(address admin) external {} - function registerOperatorToOperatorSets( - address operator, - uint32[] calldata operatorSetIds, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + function setAppointee( + address appointee, + address target, + bytes4 selector ) external {} - function deregisterOperatorFromOperatorSets(address operator, uint32[] calldata operatorSetIds) external{} - - function slashOperator(IAllocationManagerTypes.SlashingParams memory params) external override { - // Mock implementation - no actual slashing occurs - } + function removeAppointee( + address appointee, + address target, + bytes4 selector + ) external {} } diff --git a/test/mocks/ServiceManagerMock.sol b/test/mocks/ServiceManagerMock.sol index a60e63c8..423c08ec 100644 --- a/test/mocks/ServiceManagerMock.sol +++ b/test/mocks/ServiceManagerMock.sol @@ -9,22 +9,21 @@ contract ServiceManagerMock is ServiceManagerBase { IRewardsCoordinator _rewardsCoordinator, IRegistryCoordinator _registryCoordinator, IStakeRegistry _stakeRegistry, - IAllocationManager _allocationManager + IPermissionController _permissionController ) ServiceManagerBase( _avsDirectory, _rewardsCoordinator, _registryCoordinator, _stakeRegistry, - _allocationManager + _permissionController ) {} function initialize( address initialOwner, - address rewardsInitiator, - address slasher + address rewardsInitiator ) public virtual initializer { - __ServiceManagerBase_init(initialOwner, rewardsInitiator, slasher); + __ServiceManagerBase_init(initialOwner, rewardsInitiator); } } diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index 72207dcc..048e0cf1 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -5,6 +5,8 @@ import "../utils/MockAVSDeployer.sol"; import {IRegistryCoordinatorErrors} from "../../src/interfaces/IRegistryCoordinator.sol"; import {QuorumBitmapHistoryLib} from "../../src/libraries/QuorumBitmapHistoryLib.sol"; import {BitmapUtils} from "../../src/libraries/BitmapUtils.sol"; +import {console} from "forge-std/console.sol"; + contract RegistryCoordinatorUnitTests is MockAVSDeployer { using BN254 for BN254.G1Point; @@ -1891,7 +1893,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnitTests { function test_registerALMHook_Reverts() public { - cheats.prank(address(serviceManager.allocationManager())); + cheats.prank(address(registryCoordinator.allocationManager())); cheats.expectRevert(); registryCoordinator.registerOperator(defaultOperator, new uint32[](0), abi.encode(defaultSocket, pubkeyRegistrationParams)); } @@ -1899,7 +1901,7 @@ contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnit function test_deregisterALMHook_Reverts() public { uint32[] memory operatorSetIds = new uint32[](1); operatorSetIds[0] = 0; - cheats.prank(address(serviceManager.allocationManager())); + cheats.prank(address(registryCoordinator.allocationManager())); cheats.expectRevert(); registryCoordinator.deregisterOperator(defaultOperator, operatorSetIds); } @@ -2162,8 +2164,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT bytes memory data = abi.encode(socket, params); - address allocationManager = address(serviceManager.allocationManager()); - cheats.prank(allocationManager); + cheats.prank(address(registryCoordinator.allocationManager())); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); } @@ -2225,8 +2226,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT ); // Prank as allocation manager and call register hook - address allocationManager = address(serviceManager.allocationManager()); - cheats.prank(allocationManager); + cheats.prank(address(registryCoordinator.allocationManager())); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, registerParams); } @@ -2304,8 +2304,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT bytes memory data = abi.encode(socket, params); - address allocationManager = address(serviceManager.allocationManager()); - cheats.startPrank(allocationManager); + cheats.startPrank(address(registryCoordinator.allocationManager())); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); registryCoordinator.deregisterOperator(defaultOperator, operatorSetIds); @@ -2313,7 +2312,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT cheats.stopPrank(); } - function test_registerHook_Reverts_WhenNotALM() public { + function test_registerHook_Reverts_WhenNotALM() public { _deployMockEigenLayerAndAVS(0); // Enable operator sets first @@ -2406,8 +2405,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT bytes memory data = abi.encode(socket, params); - address allocationManager = address(serviceManager.allocationManager()); - cheats.startPrank(allocationManager); + cheats.prank(address(registryCoordinator.allocationManager())); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); cheats.stopPrank(); diff --git a/test/unit/ServiceManagerBase.t.sol b/test/unit/ServiceManagerBase.t.sol index ca3d0e9f..572998ca 100644 --- a/test/unit/ServiceManagerBase.t.sol +++ b/test/unit/ServiceManagerBase.t.sol @@ -90,7 +90,7 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve rewardsCoordinator, registryCoordinatorImplementation, stakeRegistryImplementation, - allocationManagerImplementation + permissionControllerMock ); serviceManager = ServiceManagerMock( diff --git a/test/unit/ServiceManagerRouter.t.sol b/test/unit/ServiceManagerRouter.t.sol index 5cf1d3b7..2e3d1e94 100644 --- a/test/unit/ServiceManagerRouter.t.sol +++ b/test/unit/ServiceManagerRouter.t.sol @@ -20,7 +20,7 @@ contract ServiceManagerRouter_UnitTests is MockAVSDeployer { rewardsCoordinatorImplementation, registryCoordinatorImplementation, stakeRegistryImplementation, - allocationManagerImplementation + permissionControllerMock ); _registerOperatorWithCoordinator(defaultOperator, MAX_QUORUM_BITMAP, defaultPubKey); diff --git a/test/unit/StakeRegistryUnit.t.sol b/test/unit/StakeRegistryUnit.t.sol index a21a8c39..aefb220e 100644 --- a/test/unit/StakeRegistryUnit.t.sol +++ b/test/unit/StakeRegistryUnit.t.sol @@ -49,11 +49,12 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { stakeRegistry, IBLSApkRegistry(blsApkRegistry), IIndexRegistry(indexRegistry), + allocationManager, pauserRegistry ); stakeRegistryImplementation = new StakeRegistryHarness( - IRegistryCoordinator(address(registryCoordinator)), delegationMock, avsDirectoryMock, serviceManager + IRegistryCoordinator(address(registryCoordinator)), delegationMock, avsDirectoryMock, allocationManager, serviceManager ); stakeRegistry = StakeRegistryHarness( diff --git a/test/utils/MockAVSDeployer.sol b/test/utils/MockAVSDeployer.sol index 3a14c824..a0ef478e 100644 --- a/test/utils/MockAVSDeployer.sol +++ b/test/utils/MockAVSDeployer.sol @@ -206,7 +206,7 @@ contract MockAVSDeployer is Test { cheats.startPrank(proxyAdminOwner); stakeRegistryImplementation = - new StakeRegistryHarness(IRegistryCoordinator(registryCoordinator), delegationMock, avsDirectory, serviceManager); + new StakeRegistryHarness(IRegistryCoordinator(registryCoordinator), delegationMock, avsDirectory, allocationManagerMock, serviceManager); proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(stakeRegistry))), address(stakeRegistryImplementation) @@ -229,7 +229,7 @@ contract MockAVSDeployer is Test { IRewardsCoordinator(address(rewardsCoordinatorMock)), registryCoordinator, stakeRegistry, - allocationManager + permissionControllerMock ); proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(serviceManager))), @@ -250,8 +250,7 @@ contract MockAVSDeployer is Test { serviceManager.initialize({ initialOwner: registryCoordinatorOwner, - rewardsInitiator: proxyAdminOwner, - slasher: proxyAdminOwner + rewardsInitiator: proxyAdminOwner }); // set the public key for an operator, using harnessed function to bypass checks @@ -274,7 +273,7 @@ contract MockAVSDeployer is Test { } registryCoordinatorImplementation = new RegistryCoordinatorHarness( - serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, pauserRegistry + serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, allocationManagerMock, pauserRegistry ); { delete operatorSetParams; From 365447882fe1ae0b0cb431f0ace6091936351581 Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Wed, 22 Jan 2025 12:30:04 -0500 Subject: [PATCH 43/52] feat: ci forge coverage (#349) * feat: ci forge coverage * fix: ci --- .github/workflows/forge-coverage.yml | 72 ++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 .github/workflows/forge-coverage.yml diff --git a/.github/workflows/forge-coverage.yml b/.github/workflows/forge-coverage.yml new file mode 100644 index 00000000..436a0c7a --- /dev/null +++ b/.github/workflows/forge-coverage.yml @@ -0,0 +1,72 @@ +name: Coverage + +on: + push: + workflow_dispatch: {} + +jobs: + run-coverage: + name: CI + runs-on: ubuntu-latest + strategy: + fail-fast: false + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Load issue number + uses: actions/github-script@v6 + id: get_issue_number + with: + script: | + const pullRequests = await github.rest.repos.listPullRequestsAssociatedWithCommit({ + commit_sha: context.sha, + owner: context.repo.owner, + repo: context.repo.repo, + }); + + if (pullRequests.data.length > 0) { + return pullRequests.data[0].number; + } else { + throw new Error('No associated pull request found.'); + } + result-encoding: string + + - name: Install dependencies + run: | + sudo apt-get install lcov + id: lcov + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + + - name: Run coverage + run: FOUNDRY_PROFILE=ci forge coverage --report lcov + env: + RPC_MAINNET: ${{ secrets.RPC_MAINNET }} + RPC_HOLESKY: ${{ secrets.RPC_HOLESKY }} + + - name: Prune coverage report + run: lcov --remove ./lcov.info -o ./lcov.info.pruned 'test/*' 'script/*' '*Storage.sol' --ignore-errors inconsistent + + - name: Generate reports + run: genhtml -o report ./lcov.info.pruned + + - name: Upload coverage results + uses: actions/upload-artifact@v4 + with: + name: code-coverage-report + path: report/* + + - name: View and log coverage + id: print_coverage + run: | + EOF=$(dd if=/dev/urandom bs=15 count=1 status=none | base64) + echo "comment_contents<<$EOF" >> $GITHUB_OUTPUT + echo "$(lcov --list ./lcov.info.pruned --ignore-errors inconsistent)" >> $GITHUB_OUTPUT + echo "$EOF" >> $GITHUB_OUTPUT + - name: Log Coverage Report + run: echo "${{ steps.print_coverage.outputs.comment_contents }}" \ No newline at end of file From d2bfd5777f8ab9eb94ab4e3a6bfe79e4fe3bd844 Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Wed, 22 Jan 2025 12:36:59 -0500 Subject: [PATCH 44/52] feat: add forge fmt to ci (#363) * feat: ci forge fmt * chore: forge fmt --- .github/workflows/forge-fmt.yml | 30 + foundry.toml | 138 +- script/utils/OperatorSetUpgradeLib.sol | 16 +- src/BLSApkRegistry.sol | 143 +- src/BLSApkRegistryStorage.sol | 7 +- src/BLSSignatureChecker.sol | 112 +- src/EjectionManager.sol | 68 +- src/IndexRegistry.sol | 136 +- src/IndexRegistryStorage.sol | 3 +- src/OperatorStateRetriever.sol | 66 +- src/RegistryCoordinator.sol | 235 ++- src/RegistryCoordinatorStorage.sol | 33 +- src/ServiceManagerBase.sol | 69 +- src/ServiceManagerBaseStorage.sol | 9 +- src/ServiceManagerRouter.sol | 27 +- src/StakeRegistry.sol | 262 +-- src/StakeRegistryStorage.sol | 16 +- src/interfaces/IBLSApkRegistry.sol | 60 +- src/interfaces/IBLSSignatureChecker.sol | 9 +- .../IECDSAStakeRegistryEventsAndErrors.sol | 12 +- src/interfaces/IEjectionManager.sol | 20 +- src/interfaces/IIndexRegistry.sol | 36 +- src/interfaces/IRegistryCoordinator.sol | 73 +- src/interfaces/IServiceManager.sol | 45 +- src/interfaces/IServiceManagerUI.sol | 30 +- src/interfaces/ISlasher.sol | 5 +- src/interfaces/ISocketUpdater.sol | 4 +- src/interfaces/IStakeRegistry.sol | 107 +- src/libraries/BN254.sol | 85 +- src/libraries/BitmapUtils.sol | 29 +- src/libraries/LibMergeSort.sol | 18 +- src/libraries/QuorumBitmapHistoryLib.sol | 3 +- src/slashers/InstantSlasher.sol | 10 +- src/slashers/VetoableSlasher.sol | 47 +- src/slashers/base/SlasherBase.sol | 27 +- src/slashers/base/SlasherStorage.sol | 24 +- src/unaudited/ECDSAServiceManagerBase.sol | 60 +- src/unaudited/ECDSAStakeRegistry.sol | 120 +- src/unaudited/ECDSAStakeRegistryStorage.sol | 28 +- .../ECDSAStakeRegistryEqualWeight.sol | 18 +- .../ECDSAStakeRegistryPermissioned.sol | 33 +- test/events/IBLSApkRegistryEvents.sol | 16 +- test/events/IIndexRegistryEvents.sol | 4 +- test/events/IServiceManagerBaseEvents.sol | 10 +- test/events/IStakeRegistryEvents.sol | 10 +- test/ffi/BLSPubKeyCompendiumFFI.t.sol | 34 +- test/ffi/BLSSignatureCheckerFFI.t.sol | 109 +- test/ffi/UpdateOperators.t.sol | 1049 +++++++++++- test/ffi/util/G2Operations.sol | 5 +- test/harnesses/AVSDirectoryHarness.sol | 4 +- test/harnesses/BLSApkRegistryHarness.sol | 2 - test/harnesses/BitmapUtilsWrapper.sol | 20 +- .../RegistryCoordinatorHarness.t.sol | 20 +- test/harnesses/StakeRegistryHarness.sol | 17 +- test/integration/CoreRegistration.t.sol | 84 +- test/integration/IntegrationBase.t.sol | 390 +++-- test/integration/IntegrationChecks.t.sol | 493 +++--- test/integration/IntegrationConfig.t.sol | 251 +-- test/integration/IntegrationDeployer.t.sol | 58 +- test/integration/TimeMachine.t.sol | 13 +- test/integration/User.t.sol | 147 +- .../mocks/BeaconChainOracleMock.t.sol | 5 +- .../tests/Full_Register_Deregister.t.sol | 23 +- ...ll_Register_CoreBalanceChange_Update.t.sol | 31 +- .../tests/NonFull_Register_Deregister.t.sol | 15 +- test/integration/utils/BitmapStrings.t.sol | 18 +- test/integration/utils/Sort.t.sol | 4 +- test/mocks/AVSDirectoryMock.sol | 310 ++-- test/mocks/AllocationManagerMock.sol | 313 ++-- test/mocks/DelegationMock.sol | 505 +++--- test/mocks/ECDSAServiceManagerMock.sol | 27 +- test/mocks/ECDSAStakeRegistryMock.sol | 6 +- test/mocks/EigenPodManagerMock.sol | 93 +- test/mocks/PermissionControllerMock.sol | 123 +- test/mocks/RegistryCoordinatorMock.sol | 85 +- test/mocks/RewardsCoordinatorMock.sol | 292 ++-- test/mocks/StakeRegistryMock.sol | 110 +- test/unit/AVSRegistrar.t.sol | 40 +- test/unit/BLSApkRegistryUnit.t.sol | 457 ++---- test/unit/BLSSignatureCheckerUnit.t.sol | 388 +++-- test/unit/BitmapUtils.t.sol | 107 +- .../ECDSAStakeRegistryEqualWeightUnit.t.sol | 83 +- .../ECDSAStakeRegistryPermissionedUnit.t.sol | 57 +- test/unit/ECDSAStakeRegistryUnit.t.sol | 317 +--- test/unit/EjectionManagerUnit.t.sol | 244 ++- test/unit/IndexRegistryUnit.t.sol | 247 +-- test/unit/LibMergeSort.t.sol | 157 +- test/unit/OperatorStateRetrieverUnit.t.sol | 20 +- test/unit/RegistryCoordinatorUnit.t.sol | 1423 +++++++++++------ test/unit/ServiceManagerBase.t.sol | 61 +- test/unit/ServiceManagerRouter.t.sol | 9 +- test/unit/StakeRegistryUnit.t.sol | 100 +- test/unit/UpgradeableProxyLib.sol | 12 +- test/unit/Utils.sol | 15 +- test/utils/BLSMockAVSDeployer.sol | 105 +- test/utils/CoreDeployLib.sol | 2 +- test/utils/MockAVSDeployer.sol | 35 +- test/utils/Operators.sol | 44 +- test/utils/Owners.sol | 19 +- test/utils/ProofParsing.sol | 103 +- test/utils/SignatureCompaction.sol | 9 +- 101 files changed, 6534 insertions(+), 4489 deletions(-) create mode 100644 .github/workflows/forge-fmt.yml diff --git a/.github/workflows/forge-fmt.yml b/.github/workflows/forge-fmt.yml new file mode 100644 index 00000000..f1fa3cc6 --- /dev/null +++ b/.github/workflows/forge-fmt.yml @@ -0,0 +1,30 @@ +name: Forge Fmt + +on: + workflow_dispatch: + push: + branches: + - master + - mainnet + - testnet-goerli + - dev + pull_request: + +jobs: + check: + name: CI + strategy: + fail-fast: true + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: nightly + - name: Run forge fmt + run: | + forge fmt --check + id: fmt \ No newline at end of file diff --git a/foundry.toml b/foundry.toml index 3d0d84cb..7b02b1c8 100644 --- a/foundry.toml +++ b/foundry.toml @@ -1,33 +1,111 @@ [profile.default] -src = "src" -out = "out" -libs = ["lib"] -fs_permissions = [{ access = "read-write", path = "./" }] -gas_limit = 5000000000 - -ffi = true -no-match-contract = "FFI" - -# Enables or disables the optimizer -optimizer = true -# Sets the number of optimizer runs -optimizer_runs = 200 -# Whether or not to use the Yul intermediate representation compilation pipeline -via_ir = false -# Override the Solidity version (this overrides `auto_detect_solc`) -solc_version = '0.8.27' + # Project Configuration + + # Path to contract sources relative to the root of the project. + src = "src" + # Path to the test contract sources relative to the root of the project. + test = "test" + # Path to the script contract sources relative to the root of the project. + script = "script" + # Path to store contract artifacts relative to the root of the project. + out = "out" + # Array of paths that contain libraries, relative to the root of the project. + libs = ["lib"] + + # Solidity Compiler Configuration + + # Defines paths for Solidity imports. + remappings = [ + "@openzeppelin/=lib/openzeppelin-contracts-v4.9.0/", + "@openzeppelin-upgrades/=lib/openzeppelin-contracts-upgradeable-v4.9.0/", + "ds-test/=lib/ds-test/src/", + "forge-std/=lib/forge-std/src/" + ] + # Specifies the exact version of Solidity to use, overriding auto-detection. + solc_version = '0.8.27' + # If enabled, treats Solidity compiler warnings as errors, preventing artifact generation if warnings are present. + deny_warnings = false + # If set to true, changes compilation pipeline to go through the new IR optimizer. + via_ir = false + # Whether or not to enable the Solidity optimizer. + optimizer = true + # The number of runs specifies roughly how often each opcode of the deployed code will be executed + # across the life-time of the contract. This means it is a trade-off parameter between code size (deploy cost) + # and code execution cost (cost after deployment). + optimizer_runs = 200 + + # Test Configuration + + # Verbosity level during test execution. Higher levels provide more detailed information: + # - 2 (-vv): Logs emitted during tests are displayed. + # - 3 (-vvv): Stack traces for failing tests are displayed. + # - 4 (-vvvv): Stack traces for all tests and setup traces for failing tests are displayed. + # - 5 (-vvvvv): Stack and setup traces are always displayed. + verbosity = 0 + # Enables the Foreign Function Interface (FFI) cheatcode. + # WARNING: This allows arbitrary programs to run on your computer, which poses security risks. + ffi = true + # Contracts to include in gas reports. By default, all contracts are included. + gas_reports = ["./src/**/*"] + # Show test execution progress if set to true. + show_progress = true + # Sparse mode only compiles files that match certain criteria. + sparse_mode = true + + gas_limit = 5000000000 + no-match-contract = "FFI" + fs_permissions = [{ access = "read-write", path = "./" }] + +[profile.default.fmt] + # Single-line vs multi-line statement blocks + single_line_statement_blocks = "preserve" # Options: "single", "multi", "preserve" + # Formatting style for long function headers + multiline_func_header = "params_first" # Options: "attributes_first", "params_first", "all" + # Sort import statements alphabetically + sort_imports = false + # Maximum line length where formatter will wrap the line + line_length = 100 # Default: 120 + # Number of spaces per indentation level + tab_width = 4 # Default: 4 + # Whether to print spaces between brackets + bracket_spacing = false + # Style of uint/int256 types + int_types = "long" # Options: "long", "short", "preserve" + # Quotation mark style + quote_style = "double" # Options: "double", "single", "preserve" + # Style of underscores in number literals + number_underscore = "thousands" # Options: "preserve", "thousands", "remove" + # Whether or not to wrap comments at line_length + wrap_comments = false + # List of files to ignore during formatting (can use glob patterns) + # ignore = [ + # "./script/**/*", + # "./test/**/*" + # ] + +# TODO: Decide if we want to enable this. +# [profile.test.fmt] +# int_types = "short" +# line_length = 140 +# ignore = [ +# "./src/**/*" +# ] + +[profile.ci.fuzz] + optimizer = false + runs = 32 + +[profile.intense.fuzz] + optimizer = false + runs = 15000 + +[profile.forktest.fuzz] + runs = 16 + +[rpc_endpoints] + mainnet = "${RPC_MAINNET}" + holesky = "${RPC_HOLESKY}" [etherscan] -mainnet = { key = "${ETHERSCAN_API_KEY}" } -holesky = { key = "${ETHERSCAN_API_KEY}" } - -[fmt] -bracket_spacing = false -int_types = "long" -line_length = 100 -multiline_func_header = "params_first" -number_underscore = "thousands" -quote_style = "double" -tab_width = 4 - -# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options + mainnet = { key = "${ETHERSCAN_API_KEY}" } + holesky = { key = "${ETHERSCAN_API_KEY}" } \ No newline at end of file diff --git a/script/utils/OperatorSetUpgradeLib.sol b/script/utils/OperatorSetUpgradeLib.sol index 30e921dc..fe25839d 100644 --- a/script/utils/OperatorSetUpgradeLib.sol +++ b/script/utils/OperatorSetUpgradeLib.sol @@ -2,7 +2,8 @@ pragma solidity ^0.8.0; // Deploy L2AVS proxy -import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; +import {TransparentUpgradeableProxy} from + "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import {Vm} from "forge-std/Vm.sol"; @@ -27,8 +28,7 @@ library OperatorSetUpgradeLib { * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1. */ bytes32 internal constant ADMIN_SLOT = - 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; - + 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; function upgrade(address proxy, address implementation, bytes memory data) internal { ProxyAdmin admin = ProxyAdmin(getAdmin(proxy)); @@ -40,13 +40,17 @@ library OperatorSetUpgradeLib { admin.upgrade(TransparentUpgradeableProxy(payable(proxy)), implementation); } - function getAdmin(address proxy) internal view returns (address) { + function getAdmin( + address proxy + ) internal view returns (address) { bytes32 value = vm.load(proxy, ADMIN_SLOT); return address(uint160(uint256(value))); } - function getImplementation(address proxy) internal view returns (address) { + function getImplementation( + address proxy + ) internal view returns (address) { bytes32 value = vm.load(proxy, IMPLEMENTATION_SLOT); return address(uint160(uint256(value))); } -} \ No newline at end of file +} diff --git a/src/BLSApkRegistry.sol b/src/BLSApkRegistry.sol index 189716a6..93972f5c 100644 --- a/src/BLSApkRegistry.sol +++ b/src/BLSApkRegistry.sol @@ -21,9 +21,11 @@ contract BLSApkRegistry is BLSApkRegistryStorage { IRegistryCoordinator _registryCoordinator ) BLSApkRegistryStorage(_registryCoordinator) {} - /******************************************************************************* - EXTERNAL FUNCTIONS - REGISTRY COORDINATOR - *******************************************************************************/ + /** + * + * EXTERNAL FUNCTIONS - REGISTRY COORDINATOR + * + */ /** * @notice Registers the `operator`'s pubkey for the specified `quorumNumbers`. @@ -41,7 +43,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage { bytes memory quorumNumbers ) public virtual onlyRegistryCoordinator { // Get the operator's pubkey. Reverts if they have not registered a key - (BN254.G1Point memory pubkey, ) = getRegisteredPubkey(operator); + (BN254.G1Point memory pubkey,) = getRegisteredPubkey(operator); // Update each quorum's aggregate pubkey _processQuorumApkUpdate(quorumNumbers, pubkey); @@ -67,7 +69,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage { bytes memory quorumNumbers ) public virtual onlyRegistryCoordinator { // Get the operator's pubkey. Reverts if they have not registered a key - (BN254.G1Point memory pubkey, ) = getRegisteredPubkey(operator); + (BN254.G1Point memory pubkey,) = getRegisteredPubkey(operator); // Update each quorum's aggregate pubkey _processQuorumApkUpdate(quorumNumbers, pubkey.negate()); @@ -78,14 +80,18 @@ contract BLSApkRegistry is BLSApkRegistryStorage { * @notice Initializes a new quorum by pushing its first apk update * @param quorumNumber The number of the new quorum */ - function initializeQuorum(uint8 quorumNumber) public virtual onlyRegistryCoordinator { + function initializeQuorum( + uint8 quorumNumber + ) public virtual onlyRegistryCoordinator { require(apkHistory[quorumNumber].length == 0, QuorumAlreadyExists()); - apkHistory[quorumNumber].push(ApkUpdate({ - apkHash: bytes24(0), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - })); + apkHistory[quorumNumber].push( + ApkUpdate({ + apkHash: bytes24(0), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }) + ); } /** @@ -105,24 +111,31 @@ contract BLSApkRegistry is BLSApkRegistryStorage { require(pubkeyHashToOperator[pubkeyHash] == address(0), BLSPubkeyAlreadyRegistered()); // gamma = h(sigma, P, P', H(m)) - uint256 gamma = uint256(keccak256(abi.encodePacked( - params.pubkeyRegistrationSignature.X, - params.pubkeyRegistrationSignature.Y, - params.pubkeyG1.X, - params.pubkeyG1.Y, - params.pubkeyG2.X, - params.pubkeyG2.Y, - pubkeyRegistrationMessageHash.X, - pubkeyRegistrationMessageHash.Y - ))) % BN254.FR_MODULUS; + uint256 gamma = uint256( + keccak256( + abi.encodePacked( + params.pubkeyRegistrationSignature.X, + params.pubkeyRegistrationSignature.Y, + params.pubkeyG1.X, + params.pubkeyG1.Y, + params.pubkeyG2.X, + params.pubkeyG2.Y, + pubkeyRegistrationMessageHash.X, + pubkeyRegistrationMessageHash.Y + ) + ) + ) % BN254.FR_MODULUS; // e(sigma + P * gamma, [-1]_2) = e(H(m) + [1]_1 * gamma, P') - require(BN254.pairing( - params.pubkeyRegistrationSignature.plus(params.pubkeyG1.scalar_mul(gamma)), - BN254.negGeneratorG2(), - pubkeyRegistrationMessageHash.plus(BN254.generatorG1().scalar_mul(gamma)), - params.pubkeyG2 - ), InvalidBLSSignatureOrPrivateKey()); + require( + BN254.pairing( + params.pubkeyRegistrationSignature.plus(params.pubkeyG1.scalar_mul(gamma)), + BN254.negGeneratorG2(), + pubkeyRegistrationMessageHash.plus(BN254.generatorG1().scalar_mul(gamma)), + params.pubkeyG2 + ), + InvalidBLSSignatureOrPrivateKey() + ); operatorToPubkey[operator] = params.pubkeyG1; operatorToPubkeyHash[operator] = pubkeyHash; @@ -132,11 +145,15 @@ contract BLSApkRegistry is BLSApkRegistryStorage { return pubkeyHash; } - /******************************************************************************* - INTERNAL FUNCTIONS - *******************************************************************************/ - - function _processQuorumApkUpdate(bytes memory quorumNumbers, BN254.G1Point memory point) internal { + /** + * + * INTERNAL FUNCTIONS + * + */ + function _processQuorumApkUpdate( + bytes memory quorumNumbers, + BN254.G1Point memory point + ) internal { BN254.G1Point memory newApk; for (uint256 i = 0; i < quorumNumbers.length; i++) { @@ -157,23 +174,29 @@ contract BLSApkRegistry is BLSApkRegistryStorage { lastUpdate.apkHash = newApkHash; } else { lastUpdate.nextUpdateBlockNumber = uint32(block.number); - apkHistory[quorumNumber].push(ApkUpdate({ - apkHash: newApkHash, - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - })); + apkHistory[quorumNumber].push( + ApkUpdate({ + apkHash: newApkHash, + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }) + ); } } } - /******************************************************************************* - VIEW FUNCTIONS - *******************************************************************************/ + /** + * + * VIEW FUNCTIONS + * + */ /** * @notice Returns the pubkey and pubkey hash of an operator * @dev Reverts if the operator has not registered a valid pubkey */ - function getRegisteredPubkey(address operator) public view returns (BN254.G1Point memory, bytes32) { + function getRegisteredPubkey( + address operator + ) public view returns (BN254.G1Point memory, bytes32) { BN254.G1Point memory pubkey = operatorToPubkey[operator]; bytes32 pubkeyHash = operatorToPubkeyHash[operator]; @@ -196,8 +219,13 @@ contract BLSApkRegistry is BLSApkRegistryStorage { uint8 quorumNumber = uint8(quorumNumbers[i]); uint256 quorumApkUpdatesLength = apkHistory[quorumNumber].length; - if (quorumApkUpdatesLength == 0 || blockNumber < apkHistory[quorumNumber][0].updateBlockNumber) { - revert("BLSApkRegistry.getApkIndicesAtBlockNumber: blockNumber is before the first update"); + if ( + quorumApkUpdatesLength == 0 + || blockNumber < apkHistory[quorumNumber][0].updateBlockNumber + ) { + revert( + "BLSApkRegistry.getApkIndicesAtBlockNumber: blockNumber is before the first update" + ); } // Loop backward through apkHistory until we find an entry that preceeds `blockNumber` @@ -212,12 +240,17 @@ contract BLSApkRegistry is BLSApkRegistryStorage { } /// @notice Returns the current APK for the provided `quorumNumber ` - function getApk(uint8 quorumNumber) external view returns (BN254.G1Point memory) { + function getApk( + uint8 quorumNumber + ) external view returns (BN254.G1Point memory) { return currentApk[quorumNumber]; } /// @notice Returns the `ApkUpdate` struct at `index` in the list of APK updates for the `quorumNumber` - function getApkUpdateAtIndex(uint8 quorumNumber, uint256 index) external view returns (ApkUpdate memory) { + function getApkUpdateAtIndex( + uint8 quorumNumber, + uint256 index + ) external view returns (ApkUpdate memory) { return apkHistory[quorumNumber][index]; } @@ -240,12 +273,10 @@ contract BLSApkRegistry is BLSApkRegistryStorage { * - blockNumber should be >= the update block number * - the next update block number should be either 0 or strictly greater than blockNumber */ + require(blockNumber >= quorumApkUpdate.updateBlockNumber, BlockNumberTooRecent()); require( - blockNumber >= quorumApkUpdate.updateBlockNumber, - BlockNumberTooRecent() - ); - require( - quorumApkUpdate.nextUpdateBlockNumber == 0 || blockNumber < quorumApkUpdate.nextUpdateBlockNumber, + quorumApkUpdate.nextUpdateBlockNumber == 0 + || blockNumber < quorumApkUpdate.nextUpdateBlockNumber, BlockNumberNotLatest() ); @@ -253,18 +284,24 @@ contract BLSApkRegistry is BLSApkRegistryStorage { } /// @notice Returns the length of ApkUpdates for the provided `quorumNumber` - function getApkHistoryLength(uint8 quorumNumber) external view returns (uint32) { + function getApkHistoryLength( + uint8 quorumNumber + ) external view returns (uint32) { return uint32(apkHistory[quorumNumber].length); } /// @notice Returns the operator address for the given `pubkeyHash` - function getOperatorFromPubkeyHash(bytes32 pubkeyHash) public view returns (address) { + function getOperatorFromPubkeyHash( + bytes32 pubkeyHash + ) public view returns (address) { return pubkeyHashToOperator[pubkeyHash]; } /// @notice returns the ID used to identify the `operator` within this AVS /// @dev Returns zero in the event that the `operator` has never registered for the AVS - function getOperatorId(address operator) public view returns (bytes32) { + function getOperatorId( + address operator + ) public view returns (bytes32) { return operatorToPubkeyHash[operator]; } diff --git a/src/BLSApkRegistryStorage.sol b/src/BLSApkRegistryStorage.sol index b35b9362..5007367a 100644 --- a/src/BLSApkRegistryStorage.sol +++ b/src/BLSApkRegistryStorage.sol @@ -10,7 +10,8 @@ import {BN254} from "./libraries/BN254.sol"; abstract contract BLSApkRegistryStorage is Initializable, IBLSApkRegistry { /// @notice the hash of the zero pubkey aka BN254.G1Point(0,0) - bytes32 internal constant ZERO_PK_HASH = hex"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5"; + bytes32 internal constant ZERO_PK_HASH = + hex"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5"; /// @notice the registry coordinator contract address public immutable registryCoordinator; @@ -29,7 +30,9 @@ abstract contract BLSApkRegistryStorage is Initializable, IBLSApkRegistry { /// @notice maps quorumNumber => current aggregate pubkey of quorum mapping(uint8 => BN254.G1Point) public currentApk; - constructor(IRegistryCoordinator _registryCoordinator) { + constructor( + IRegistryCoordinator _registryCoordinator + ) { registryCoordinator = address(_registryCoordinator); // disable initializers so that the implementation contract cannot be initialized _disableInitializers(); diff --git a/src/BLSSignatureChecker.sol b/src/BLSSignatureChecker.sol index 944ed4f7..2ff55e37 100644 --- a/src/BLSSignatureChecker.sol +++ b/src/BLSSignatureChecker.sol @@ -35,7 +35,9 @@ contract BLSSignatureChecker is IBLSSignatureChecker { _; } - constructor(IRegistryCoordinator _registryCoordinator) { + constructor( + IRegistryCoordinator _registryCoordinator + ) { registryCoordinator = _registryCoordinator; stakeRegistry = _registryCoordinator.stakeRegistry(); blsApkRegistry = _registryCoordinator.blsApkRegistry(); @@ -48,7 +50,9 @@ contract BLSSignatureChecker is IBLSSignatureChecker { * than the delegation.minWithdrawalDelayBlocks() window. * @param value to toggle staleStakesForbidden */ - function setStaleStakesForbidden(bool value) external onlyCoordinatorOwner { + function setStaleStakesForbidden( + bool value + ) external onlyCoordinatorOwner { _setStaleStakesForbidden(value); } @@ -91,16 +95,15 @@ contract BLSSignatureChecker is IBLSSignatureChecker { require(quorumNumbers.length != 0, InputEmptyQuorumNumbers()); require( - (quorumNumbers.length == params.quorumApks.length) && - (quorumNumbers.length == params.quorumApkIndices.length) && - (quorumNumbers.length == params.totalStakeIndices.length) && - (quorumNumbers.length == params.nonSignerStakeIndices.length), + (quorumNumbers.length == params.quorumApks.length) + && (quorumNumbers.length == params.quorumApkIndices.length) + && (quorumNumbers.length == params.totalStakeIndices.length) + && (quorumNumbers.length == params.nonSignerStakeIndices.length), InputArrayLengthMismatch() ); require( - params.nonSignerPubkeys.length == - params.nonSignerQuorumBitmapIndices.length, + params.nonSignerPubkeys.length == params.nonSignerQuorumBitmapIndices.length, InputNonSignerLengthMismatch() ); @@ -122,30 +125,25 @@ contract BLSSignatureChecker is IBLSSignatureChecker { stakeTotals.signedStakeForQuorum = new uint96[](quorumNumbers.length); NonSignerInfo memory nonSigners; - nonSigners.quorumBitmaps = new uint256[]( - params.nonSignerPubkeys.length - ); + nonSigners.quorumBitmaps = new uint256[](params.nonSignerPubkeys.length); nonSigners.pubkeyHashes = new bytes32[](params.nonSignerPubkeys.length); { // Get a bitmap of the quorums signing the message, and validate that // quorumNumbers contains only unique, valid quorum numbers uint256 signingQuorumBitmap = BitmapUtils.orderedBytesArrayToBitmap( - quorumNumbers, - registryCoordinator.quorumCount() + quorumNumbers, registryCoordinator.quorumCount() ); for (uint256 j = 0; j < params.nonSignerPubkeys.length; j++) { // The nonsigner's pubkey hash doubles as their operatorId // The check below validates that these operatorIds are sorted (and therefore // free of duplicates) - nonSigners.pubkeyHashes[j] = params - .nonSignerPubkeys[j] - .hashG1Point(); + nonSigners.pubkeyHashes[j] = params.nonSignerPubkeys[j].hashG1Point(); if (j != 0) { require( - uint256(nonSigners.pubkeyHashes[j]) > - uint256(nonSigners.pubkeyHashes[j - 1]), + uint256(nonSigners.pubkeyHashes[j]) + > uint256(nonSigners.pubkeyHashes[j - 1]), NonSignerPubkeysNotSorted() ); } @@ -153,19 +151,17 @@ contract BLSSignatureChecker is IBLSSignatureChecker { // Get the quorums the nonsigner was registered for at referenceBlockNumber nonSigners.quorumBitmaps[j] = registryCoordinator .getQuorumBitmapAtBlockNumberByIndex({ - operatorId: nonSigners.pubkeyHashes[j], - blockNumber: referenceBlockNumber, - index: params.nonSignerQuorumBitmapIndices[j] - }); + operatorId: nonSigners.pubkeyHashes[j], + blockNumber: referenceBlockNumber, + index: params.nonSignerQuorumBitmapIndices[j] + }); // Add the nonsigner's pubkey to the total apk, multiplied by the number // of quorums they have in common with the signing quorums, because their // public key will be a part of each signing quorum's aggregate pubkey apk = apk.plus( params.nonSignerPubkeys[j].scalar_mul_tiny( - BitmapUtils.countNumOnes( - nonSigners.quorumBitmaps[j] & signingQuorumBitmap - ) + BitmapUtils.countNumOnes(nonSigners.quorumBitmaps[j] & signingQuorumBitmap) ) ); } @@ -184,20 +180,16 @@ contract BLSSignatureChecker is IBLSSignatureChecker { */ { bool _staleStakesForbidden = staleStakesForbidden; - uint256 withdrawalDelayBlocks = _staleStakesForbidden - ? delegation.minWithdrawalDelayBlocks() - : 0; + uint256 withdrawalDelayBlocks = + _staleStakesForbidden ? delegation.minWithdrawalDelayBlocks() : 0; for (uint256 i = 0; i < quorumNumbers.length; i++) { // If we're disallowing stale stake updates, check that each quorum's last update block // is within withdrawalDelayBlocks if (_staleStakesForbidden) { require( - registryCoordinator.quorumUpdateBlockNumber( - uint8(quorumNumbers[i]) - ) + - withdrawalDelayBlocks > - referenceBlockNumber, + registryCoordinator.quorumUpdateBlockNumber(uint8(quorumNumbers[i])) + + withdrawalDelayBlocks > referenceBlockNumber, StaleStakesForbidden() ); } @@ -205,8 +197,8 @@ contract BLSSignatureChecker is IBLSSignatureChecker { // Validate params.quorumApks is correct for this quorum at the referenceBlockNumber, // then add it to the total apk require( - bytes24(params.quorumApks[i].hashG1Point()) == - blsApkRegistry.getApkHashAtBlockNumberAndIndex({ + bytes24(params.quorumApks[i].hashG1Point()) + == blsApkRegistry.getApkHashAtBlockNumberAndIndex({ quorumNumber: uint8(quorumNumbers[i]), blockNumber: referenceBlockNumber, index: params.quorumApkIndices[i] @@ -218,12 +210,11 @@ contract BLSSignatureChecker is IBLSSignatureChecker { // Get the total and starting signed stake for the quorum at referenceBlockNumber stakeTotals.totalStakeForQuorum[i] = stakeRegistry .getTotalStakeAtBlockNumberFromIndex({ - quorumNumber: uint8(quorumNumbers[i]), - blockNumber: referenceBlockNumber, - index: params.totalStakeIndices[i] - }); - stakeTotals.signedStakeForQuorum[i] = stakeTotals - .totalStakeForQuorum[i]; + quorumNumber: uint8(quorumNumbers[i]), + blockNumber: referenceBlockNumber, + index: params.totalStakeIndices[i] + }); + stakeTotals.signedStakeForQuorum[i] = stakeTotals.totalStakeForQuorum[i]; // Keep track of the nonSigners index in the quorum uint256 nonSignerForQuorumIndex = 0; @@ -232,21 +223,14 @@ contract BLSSignatureChecker is IBLSSignatureChecker { // if so, load their stake at referenceBlockNumber and subtract it from running stake signed for (uint256 j = 0; j < params.nonSignerPubkeys.length; j++) { // if the nonSigner is a part of the quorum, subtract their stake from the running total - if ( - BitmapUtils.isSet( - nonSigners.quorumBitmaps[j], - uint8(quorumNumbers[i]) - ) - ) { + if (BitmapUtils.isSet(nonSigners.quorumBitmaps[j], uint8(quorumNumbers[i]))) { stakeTotals.signedStakeForQuorum[i] -= stakeRegistry .getStakeAtBlockNumberAndIndex({ - quorumNumber: uint8(quorumNumbers[i]), - blockNumber: referenceBlockNumber, - operatorId: nonSigners.pubkeyHashes[j], - index: params.nonSignerStakeIndices[i][ - nonSignerForQuorumIndex - ] - }); + quorumNumber: uint8(quorumNumbers[i]), + blockNumber: referenceBlockNumber, + operatorId: nonSigners.pubkeyHashes[j], + index: params.nonSignerStakeIndices[i][nonSignerForQuorumIndex] + }); unchecked { ++nonSignerForQuorumIndex; } @@ -256,22 +240,14 @@ contract BLSSignatureChecker is IBLSSignatureChecker { } { // verify the signature - ( - bool pairingSuccessful, - bool signatureIsValid - ) = trySignatureAndApkVerification( - msgHash, - apk, - params.apkG2, - params.sigma - ); + (bool pairingSuccessful, bool signatureIsValid) = + trySignatureAndApkVerification(msgHash, apk, params.apkG2, params.sigma); require(pairingSuccessful, InvalidBLSPairingKey()); require(signatureIsValid, InvalidBLSSignature()); } // set signatoryRecordHash variable used for fraudproofs - bytes32 signatoryRecordHash = keccak256( - abi.encodePacked(referenceBlockNumber, nonSigners.pubkeyHashes) - ); + bytes32 signatoryRecordHash = + keccak256(abi.encodePacked(referenceBlockNumber, nonSigners.pubkeyHashes)); // return the total stakes that signed for each quorum, and a hash of the information required to prove the exact signers and stake return (stakeTotals, signatoryRecordHash); @@ -318,7 +294,9 @@ contract BLSSignatureChecker is IBLSSignatureChecker { ); } - function _setStaleStakesForbidden(bool value) internal { + function _setStaleStakesForbidden( + bool value + ) internal { staleStakesForbidden = value; emit StaleStakesForbiddenUpdate(value); } diff --git a/src/EjectionManager.sol b/src/EjectionManager.sol index 8ebf6002..f7d3d55d 100644 --- a/src/EjectionManager.sol +++ b/src/EjectionManager.sol @@ -11,7 +11,6 @@ import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; * @author Layr Labs, Inc. */ contract EjectionManager is IEjectionManager, OwnableUpgradeable { - /// @notice The basis point denominator for the ejectable stake percent uint16 internal constant BIPS_DENOMINATOR = 10_000; @@ -31,10 +30,7 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { /// @notice Ratelimit parameters for each quorum mapping(uint8 => QuorumEjectionParams) public quorumEjectionParams; - constructor( - IRegistryCoordinator _registryCoordinator, - IStakeRegistry _stakeRegistry - ) { + constructor(IRegistryCoordinator _registryCoordinator, IStakeRegistry _stakeRegistry) { registryCoordinator = _registryCoordinator; stakeRegistry = _stakeRegistry; @@ -52,10 +48,10 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { QuorumEjectionParams[] memory _quorumEjectionParams ) external initializer { _transferOwnership(_owner); - for(uint8 i = 0; i < _ejectors.length; i++) { + for (uint8 i = 0; i < _ejectors.length; i++) { _setEjector(_ejectors[i], true); } - for(uint8 i = 0; i < _quorumEjectionParams.length; i++) { + for (uint8 i = 0; i < _quorumEjectionParams.length; i++) { _setQuorumEjectionParams(i, _quorumEjectionParams[i]); } } @@ -66,10 +62,12 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { * @dev This function will eject as many operators as possible prioritizing operators at the lower index * @dev The owner can eject operators without recording of stake ejection */ - function ejectOperators(bytes32[][] memory _operatorIds) external { + function ejectOperators( + bytes32[][] memory _operatorIds + ) external { require(isEjector[msg.sender] || msg.sender == owner(), OnlyOwnerOrEjector()); - for(uint i = 0; i < _operatorIds.length; ++i) { + for (uint256 i = 0; i < _operatorIds.length; ++i) { uint8 quorumNumber = uint8(i); uint256 amountEjectable = amountEjectableForQuorum(quorumNumber); @@ -77,19 +75,18 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { uint32 ejectedOperators; bool ratelimitHit; - for(uint8 j = 0; j < _operatorIds[i].length; ++j) { - uint256 operatorStake = stakeRegistry.getCurrentStake(_operatorIds[i][j], quorumNumber); + for (uint8 j = 0; j < _operatorIds[i].length; ++j) { + uint256 operatorStake = + stakeRegistry.getCurrentStake(_operatorIds[i][j], quorumNumber); //if caller is ejector enforce ratelimit - if( - isEjector[msg.sender] && - quorumEjectionParams[quorumNumber].rateLimitWindow > 0 && - stakeForEjection + operatorStake > amountEjectable - ){ - stakeEjectedForQuorum[quorumNumber].push(StakeEjection({ - timestamp: block.timestamp, - stakeEjected: stakeForEjection - })); + if ( + isEjector[msg.sender] && quorumEjectionParams[quorumNumber].rateLimitWindow > 0 + && stakeForEjection + operatorStake > amountEjectable + ) { + stakeEjectedForQuorum[quorumNumber].push( + StakeEjection({timestamp: block.timestamp, stakeEjected: stakeForEjection}) + ); ratelimitHit = true; break; } @@ -106,11 +103,10 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { } //record the stake ejected if ejector and ratelimit enforced - if(!ratelimitHit && isEjector[msg.sender]){ - stakeEjectedForQuorum[quorumNumber].push(StakeEjection({ - timestamp: block.timestamp, - stakeEjected: stakeForEjection - })); + if (!ratelimitHit && isEjector[msg.sender]) { + stakeEjectedForQuorum[quorumNumber].push( + StakeEjection({timestamp: block.timestamp, stakeEjected: stakeForEjection}) + ); } emit QuorumEjection(ejectedOperators, ratelimitHit); @@ -122,7 +118,10 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { * @param _quorumNumber The quorum number to set the ratelimit parameters for * @param _quorumEjectionParams The quorum ratelimit parameters to set for the given quorum */ - function setQuorumEjectionParams(uint8 _quorumNumber, QuorumEjectionParams memory _quorumEjectionParams) external onlyOwner() { + function setQuorumEjectionParams( + uint8 _quorumNumber, + QuorumEjectionParams memory _quorumEjectionParams + ) external onlyOwner { _setQuorumEjectionParams(_quorumNumber, _quorumEjectionParams); } @@ -131,15 +130,22 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { * @param _ejector The address to permission * @param _status The status to set for the given address */ - function setEjector(address _ejector, bool _status) external onlyOwner() { + function setEjector(address _ejector, bool _status) external onlyOwner { _setEjector(_ejector, _status); } ///@dev internal function to set the quorum ejection params - function _setQuorumEjectionParams(uint8 _quorumNumber, QuorumEjectionParams memory _quorumEjectionParams) internal { + function _setQuorumEjectionParams( + uint8 _quorumNumber, + QuorumEjectionParams memory _quorumEjectionParams + ) internal { require(_quorumNumber < MAX_QUORUM_COUNT, MaxQuorumCount()); quorumEjectionParams[_quorumNumber] = _quorumEjectionParams; - emit QuorumEjectionParamsSet(_quorumNumber, _quorumEjectionParams.rateLimitWindow, _quorumEjectionParams.ejectableStakePercent); + emit QuorumEjectionParamsSet( + _quorumNumber, + _quorumEjectionParams.rateLimitWindow, + _quorumEjectionParams.ejectableStakePercent + ); } ///@dev internal function to set the ejector @@ -152,7 +158,9 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { * @notice Returns the amount of stake that can be ejected for a quorum at the current block.timestamp * @param _quorumNumber The quorum number to view ejectable stake for */ - function amountEjectableForQuorum(uint8 _quorumNumber) public view returns (uint256) { + function amountEjectableForQuorum( + uint8 _quorumNumber + ) public view returns (uint256) { uint256 totalEjectable = uint256(quorumEjectionParams[_quorumNumber].ejectableStakePercent) * uint256(stakeRegistry.getCurrentTotalStake(_quorumNumber)) / uint256(BIPS_DENOMINATOR); diff --git a/src/IndexRegistry.sol b/src/IndexRegistry.sol index cab62a17..c8b46061 100644 --- a/src/IndexRegistry.sol +++ b/src/IndexRegistry.sol @@ -9,7 +9,6 @@ import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; * @author Layr Labs, Inc. */ contract IndexRegistry is IndexRegistryStorage { - /// @notice when applied to a function, only allows the RegistryCoordinator to call it modifier onlyRegistryCoordinator() { _checkRegistryCoordinator(); @@ -21,9 +20,11 @@ contract IndexRegistry is IndexRegistryStorage { IRegistryCoordinator _registryCoordinator ) IndexRegistryStorage(_registryCoordinator) {} - /******************************************************************************* - EXTERNAL FUNCTIONS - REGISTRY COORDINATOR - *******************************************************************************/ + /** + * + * EXTERNAL FUNCTIONS - REGISTRY COORDINATOR + * + */ /** * @notice Registers the operator with the specified `operatorId` for the quorums specified by `quorumNumbers`. @@ -40,7 +41,7 @@ contract IndexRegistry is IndexRegistryStorage { function registerOperator( bytes32 operatorId, bytes calldata quorumNumbers - ) public virtual onlyRegistryCoordinator returns(uint32[] memory) { + ) public virtual onlyRegistryCoordinator returns (uint32[] memory) { uint32[] memory numOperatorsPerQuorum = new uint32[](quorumNumbers.length); for (uint256 i = 0; i < quorumNumbers.length; i++) { @@ -112,23 +113,28 @@ contract IndexRegistry is IndexRegistryStorage { * @notice Initialize a quorum by pushing its first quorum update * @param quorumNumber The number of the new quorum */ - function initializeQuorum(uint8 quorumNumber) public virtual onlyRegistryCoordinator { + function initializeQuorum( + uint8 quorumNumber + ) public virtual onlyRegistryCoordinator { require(_operatorCountHistory[quorumNumber].length == 0, QuorumDoesNotExist()); - _operatorCountHistory[quorumNumber].push(QuorumUpdate({ - numOperators: 0, - fromBlockNumber: uint32(block.number) - })); + _operatorCountHistory[quorumNumber].push( + QuorumUpdate({numOperators: 0, fromBlockNumber: uint32(block.number)}) + ); } - /******************************************************************************* - INTERNAL FUNCTIONS - *******************************************************************************/ + /** + * + * INTERNAL FUNCTIONS + * + */ /** * @notice Increases the historical operator count by 1 and returns the new count */ - function _increaseOperatorCount(uint8 quorumNumber) internal returns (uint32) { + function _increaseOperatorCount( + uint8 quorumNumber + ) internal returns (uint32) { QuorumUpdate storage lastUpdate = _latestQuorumUpdate(quorumNumber); uint32 newOperatorCount = lastUpdate.numOperators + 1; @@ -137,10 +143,12 @@ contract IndexRegistry is IndexRegistryStorage { // If this is the first time we're using this operatorIndex, push its first update // This maintains an invariant: existing indices have nonzero history if (_operatorIndexHistory[quorumNumber][newOperatorCount - 1].length == 0) { - _operatorIndexHistory[quorumNumber][newOperatorCount - 1].push(OperatorUpdate({ - operatorId: OPERATOR_DOES_NOT_EXIST_ID, - fromBlockNumber: uint32(block.number) - })); + _operatorIndexHistory[quorumNumber][newOperatorCount - 1].push( + OperatorUpdate({ + operatorId: OPERATOR_DOES_NOT_EXIST_ID, + fromBlockNumber: uint32(block.number) + }) + ); } return newOperatorCount; @@ -149,7 +157,9 @@ contract IndexRegistry is IndexRegistryStorage { /** * @notice Decreases the historical operator count by 1 and returns the new count */ - function _decreaseOperatorCount(uint8 quorumNumber) internal returns (uint32) { + function _decreaseOperatorCount( + uint8 quorumNumber + ) internal returns (uint32) { QuorumUpdate storage lastUpdate = _latestQuorumUpdate(quorumNumber); uint32 newOperatorCount = lastUpdate.numOperators - 1; @@ -171,10 +181,9 @@ contract IndexRegistry is IndexRegistryStorage { if (lastUpdate.fromBlockNumber == uint32(block.number)) { lastUpdate.numOperators = newOperatorCount; } else { - _operatorCountHistory[quorumNumber].push(QuorumUpdate({ - numOperators: newOperatorCount, - fromBlockNumber: uint32(block.number) - })); + _operatorCountHistory[quorumNumber].push( + QuorumUpdate({numOperators: newOperatorCount, fromBlockNumber: uint32(block.number)}) + ); } } @@ -183,12 +192,17 @@ contract IndexRegistry is IndexRegistryStorage { * @dev The last entry's operatorId is updated to OPERATOR_DOES_NOT_EXIST_ID * @return The removed operatorId */ - function _popLastOperator(uint8 quorumNumber, uint32 operatorIndex) internal returns (bytes32) { + function _popLastOperator( + uint8 quorumNumber, + uint32 operatorIndex + ) internal returns (bytes32) { OperatorUpdate storage lastUpdate = _latestOperatorIndexUpdate(quorumNumber, operatorIndex); bytes32 removedOperatorId = lastUpdate.operatorId; // Set the current operator id for this operatorIndex to 0 - _updateOperatorIndexHistory(quorumNumber, operatorIndex, lastUpdate, OPERATOR_DOES_NOT_EXIST_ID); + _updateOperatorIndexHistory( + quorumNumber, operatorIndex, lastUpdate, OPERATOR_DOES_NOT_EXIST_ID + ); return removedOperatorId; } @@ -199,7 +213,11 @@ contract IndexRegistry is IndexRegistryStorage { * @param quorumNumber quorumNumber of the operator to update * @param operatorIndex the latest index of that operator in the list of operators registered for this quorum */ - function _assignOperatorToIndex(bytes32 operatorId, uint8 quorumNumber, uint32 operatorIndex) internal { + function _assignOperatorToIndex( + bytes32 operatorId, + uint8 quorumNumber, + uint32 operatorIndex + ) internal { OperatorUpdate storage lastUpdate = _latestOperatorIndexUpdate(quorumNumber, operatorIndex); _updateOperatorIndexHistory(quorumNumber, operatorIndex, lastUpdate, operatorId); @@ -223,23 +241,27 @@ contract IndexRegistry is IndexRegistryStorage { if (lastUpdate.fromBlockNumber == uint32(block.number)) { lastUpdate.operatorId = newOperatorId; } else { - _operatorIndexHistory[quorumNumber][operatorIndex].push(OperatorUpdate({ - operatorId: newOperatorId, - fromBlockNumber: uint32(block.number) - })); + _operatorIndexHistory[quorumNumber][operatorIndex].push( + OperatorUpdate({operatorId: newOperatorId, fromBlockNumber: uint32(block.number)}) + ); } } /// @notice Returns the most recent operator count update for a quorum /// @dev Reverts if the quorum does not exist (history length == 0) - function _latestQuorumUpdate(uint8 quorumNumber) internal view returns (QuorumUpdate storage) { + function _latestQuorumUpdate( + uint8 quorumNumber + ) internal view returns (QuorumUpdate storage) { uint256 historyLength = _operatorCountHistory[quorumNumber].length; return _operatorCountHistory[quorumNumber][historyLength - 1]; } /// @notice Returns the most recent operator id update for an index /// @dev Reverts if the index has never been used (history length == 0) - function _latestOperatorIndexUpdate(uint8 quorumNumber, uint32 operatorIndex) internal view returns (OperatorUpdate storage) { + function _latestOperatorIndexUpdate( + uint8 quorumNumber, + uint32 operatorIndex + ) internal view returns (OperatorUpdate storage) { uint256 historyLength = _operatorIndexHistory[quorumNumber][operatorIndex].length; return _operatorIndexHistory[quorumNumber][operatorIndex][historyLength - 1]; } @@ -251,7 +273,7 @@ contract IndexRegistry is IndexRegistryStorage { function _operatorCountAtBlockNumber( uint8 quorumNumber, uint32 blockNumber - ) internal view returns (uint32){ + ) internal view returns (uint32) { uint256 historyLength = _operatorCountHistory[quorumNumber].length; // Loop backwards through _operatorCountHistory until we find an entry that preceeds `blockNumber` @@ -263,7 +285,9 @@ contract IndexRegistry is IndexRegistryStorage { } } - revert("IndexRegistry._operatorCountAtBlockNumber: quorum did not exist at given block number"); + revert( + "IndexRegistry._operatorCountAtBlockNumber: quorum did not exist at given block number" + ); } /** @@ -274,12 +298,13 @@ contract IndexRegistry is IndexRegistryStorage { uint8 quorumNumber, uint32 operatorIndex, uint32 blockNumber - ) internal view returns(bytes32) { + ) internal view returns (bytes32) { uint256 historyLength = _operatorIndexHistory[quorumNumber][operatorIndex].length; // Loop backward through _operatorIndexHistory until we find an entry that preceeds `blockNumber` for (uint256 i = historyLength; i > 0; i--) { - OperatorUpdate memory operatorIndexUpdate = _operatorIndexHistory[quorumNumber][operatorIndex][i - 1]; + OperatorUpdate memory operatorIndexUpdate = + _operatorIndexHistory[quorumNumber][operatorIndex][i - 1]; if (operatorIndexUpdate.fromBlockNumber <= blockNumber) { // Special case: this will be OPERATOR_DOES_NOT_EXIST_ID if this operatorIndex was not used at the block number @@ -291,30 +316,44 @@ contract IndexRegistry is IndexRegistryStorage { return OPERATOR_DOES_NOT_EXIST_ID; } - /******************************************************************************* - VIEW FUNCTIONS - *******************************************************************************/ + /** + * + * VIEW FUNCTIONS + * + */ /// @notice Returns the _operatorIndexHistory entry for the specified `operatorIndex` and `quorumNumber` /// at the specified `arrayIndex` - function getOperatorUpdateAtIndex(uint8 quorumNumber, uint32 operatorIndex, uint32 arrayIndex) external view returns (OperatorUpdate memory) { + function getOperatorUpdateAtIndex( + uint8 quorumNumber, + uint32 operatorIndex, + uint32 arrayIndex + ) external view returns (OperatorUpdate memory) { return _operatorIndexHistory[quorumNumber][operatorIndex][arrayIndex]; } /// @notice Returns the _operatorCountHistory entry for the specified `quorumNumber` at the specified `quorumIndex` - function getQuorumUpdateAtIndex(uint8 quorumNumber, uint32 quorumIndex) external view returns (QuorumUpdate memory) { + function getQuorumUpdateAtIndex( + uint8 quorumNumber, + uint32 quorumIndex + ) external view returns (QuorumUpdate memory) { return _operatorCountHistory[quorumNumber][quorumIndex]; } /// @notice Returns the most recent QuorumUpdate entry for the specified quorumNumber /// @dev Reverts if the quorum does not exist - function getLatestQuorumUpdate(uint8 quorumNumber) external view returns (QuorumUpdate memory) { + function getLatestQuorumUpdate( + uint8 quorumNumber + ) external view returns (QuorumUpdate memory) { return _latestQuorumUpdate(quorumNumber); } /// @notice Returns the most recent OperatorUpdate entry for the specified quorumNumber and operatorIndex /// @dev Reverts if there is no update for the given operatorIndex - function getLatestOperatorUpdate(uint8 quorumNumber, uint32 operatorIndex) external view returns (OperatorUpdate memory) { + function getLatestOperatorUpdate( + uint8 quorumNumber, + uint32 operatorIndex + ) external view returns (OperatorUpdate memory) { return _latestOperatorIndexUpdate(quorumNumber, operatorIndex); } @@ -322,22 +361,21 @@ contract IndexRegistry is IndexRegistryStorage { function getOperatorListAtBlockNumber( uint8 quorumNumber, uint32 blockNumber - ) external view returns (bytes32[] memory){ + ) external view returns (bytes32[] memory) { uint32 operatorCount = _operatorCountAtBlockNumber(quorumNumber, blockNumber); bytes32[] memory operatorList = new bytes32[](operatorCount); for (uint256 i = 0; i < operatorCount; i++) { operatorList[i] = _operatorIdForIndexAtBlockNumber(quorumNumber, uint32(i), blockNumber); - require( - operatorList[i] != OPERATOR_DOES_NOT_EXIST_ID, - OperatorIdDoesNotExist() - ); + require(operatorList[i] != OPERATOR_DOES_NOT_EXIST_ID, OperatorIdDoesNotExist()); } return operatorList; } /// @notice Returns the total number of operators for a given `quorumNumber` /// @dev This will revert if the quorum does not exist - function totalOperatorsForQuorum(uint8 quorumNumber) external view returns (uint32){ + function totalOperatorsForQuorum( + uint8 quorumNumber + ) external view returns (uint32) { return _latestQuorumUpdate(quorumNumber).numOperators; } diff --git a/src/IndexRegistryStorage.sol b/src/IndexRegistryStorage.sol index b5b800d6..95f39e34 100644 --- a/src/IndexRegistryStorage.sol +++ b/src/IndexRegistryStorage.sol @@ -12,7 +12,6 @@ import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; * @notice This storage contract is separate from the logic to simplify the upgrade process. */ abstract contract IndexRegistryStorage is Initializable, IIndexRegistry { - /// @notice The value that is returned when an operator does not exist at an index at a certain block bytes32 public constant OPERATOR_DOES_NOT_EXIST_ID = bytes32(0); @@ -32,7 +31,7 @@ abstract contract IndexRegistryStorage is Initializable, IIndexRegistry { constructor( IRegistryCoordinator _registryCoordinator - ){ + ) { registryCoordinator = address(_registryCoordinator); // disable initializers so that the implementation contract cannot be initialized _disableInitializers(); diff --git a/src/OperatorStateRetriever.sol b/src/OperatorStateRetriever.sol index 87672b66..82dc8d6e 100644 --- a/src/OperatorStateRetriever.sol +++ b/src/OperatorStateRetriever.sol @@ -46,9 +46,11 @@ contract OperatorStateRetriever { ) external view returns (uint256, Operator[][] memory) { bytes32[] memory operatorIds = new bytes32[](1); operatorIds[0] = operatorId; - uint256 index = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds)[0]; + uint256 index = + registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds)[0]; - uint256 quorumBitmap = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); + uint256 quorumBitmap = + registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); @@ -67,7 +69,7 @@ contract OperatorStateRetriever { IRegistryCoordinator registryCoordinator, bytes memory quorumNumbers, uint32 blockNumber - ) public view returns(Operator[][] memory) { + ) public view returns (Operator[][] memory) { IStakeRegistry stakeRegistry = registryCoordinator.stakeRegistry(); IIndexRegistry indexRegistry = registryCoordinator.indexRegistry(); IBLSApkRegistry blsApkRegistry = registryCoordinator.blsApkRegistry(); @@ -75,13 +77,16 @@ contract OperatorStateRetriever { Operator[][] memory operators = new Operator[][](quorumNumbers.length); for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); - bytes32[] memory operatorIds = indexRegistry.getOperatorListAtBlockNumber(quorumNumber, blockNumber); + bytes32[] memory operatorIds = + indexRegistry.getOperatorListAtBlockNumber(quorumNumber, blockNumber); operators[i] = new Operator[](operatorIds.length); for (uint256 j = 0; j < operatorIds.length; j++) { operators[i][j] = Operator({ operator: blsApkRegistry.getOperatorFromPubkeyHash(operatorIds[j]), operatorId: bytes32(operatorIds[j]), - stake: stakeRegistry.getStakeAtBlockNumber(bytes32(operatorIds[j]), quorumNumber, blockNumber) + stake: stakeRegistry.getStakeAtBlockNumber( + bytes32(operatorIds[j]), quorumNumber, blockNumber + ) }); } } @@ -113,32 +118,40 @@ contract OperatorStateRetriever { CheckSignaturesIndices memory checkSignaturesIndices; // get the indices of the quorumBitmap updates for each of the operators in the nonSignerOperatorIds array - checkSignaturesIndices.nonSignerQuorumBitmapIndices = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(referenceBlockNumber, nonSignerOperatorIds); + checkSignaturesIndices.nonSignerQuorumBitmapIndices = registryCoordinator + .getQuorumBitmapIndicesAtBlockNumber(referenceBlockNumber, nonSignerOperatorIds); // get the indices of the totalStake updates for each of the quorums in the quorumNumbers array - checkSignaturesIndices.totalStakeIndices = stakeRegistry.getTotalStakeIndicesAtBlockNumber(referenceBlockNumber, quorumNumbers); + checkSignaturesIndices.totalStakeIndices = + stakeRegistry.getTotalStakeIndicesAtBlockNumber(referenceBlockNumber, quorumNumbers); checkSignaturesIndices.nonSignerStakeIndices = new uint32[][](quorumNumbers.length); - for (uint8 quorumNumberIndex = 0; quorumNumberIndex < quorumNumbers.length; quorumNumberIndex++) { + for ( + uint8 quorumNumberIndex = 0; + quorumNumberIndex < quorumNumbers.length; + quorumNumberIndex++ + ) { uint256 numNonSignersForQuorum = 0; // this array's length will be at most the number of nonSignerOperatorIds, this will be trimmed after it is filled - checkSignaturesIndices.nonSignerStakeIndices[quorumNumberIndex] = new uint32[](nonSignerOperatorIds.length); + checkSignaturesIndices.nonSignerStakeIndices[quorumNumberIndex] = + new uint32[](nonSignerOperatorIds.length); - for (uint i = 0; i < nonSignerOperatorIds.length; i++) { + for (uint256 i = 0; i < nonSignerOperatorIds.length; i++) { // get the quorumBitmap for the operator at the given blocknumber and index - uint192 nonSignerQuorumBitmap = - registryCoordinator.getQuorumBitmapAtBlockNumberByIndex( - nonSignerOperatorIds[i], - referenceBlockNumber, - checkSignaturesIndices.nonSignerQuorumBitmapIndices[i] - ); + uint192 nonSignerQuorumBitmap = registryCoordinator + .getQuorumBitmapAtBlockNumberByIndex( + nonSignerOperatorIds[i], + referenceBlockNumber, + checkSignaturesIndices.nonSignerQuorumBitmapIndices[i] + ); require(nonSignerQuorumBitmap != 0, OperatorNotRegistered()); // if the operator was a part of the quorum and the quorum is a part of the provided quorumNumbers if ((nonSignerQuorumBitmap >> uint8(quorumNumbers[quorumNumberIndex])) & 1 == 1) { // get the index of the stake update for the operator at the given blocknumber and quorum number - checkSignaturesIndices.nonSignerStakeIndices[quorumNumberIndex][numNonSignersForQuorum] = stakeRegistry.getStakeUpdateIndexAtBlockNumber( + checkSignaturesIndices.nonSignerStakeIndices[quorumNumberIndex][numNonSignersForQuorum] + = stakeRegistry.getStakeUpdateIndexAtBlockNumber( nonSignerOperatorIds[i], uint8(quorumNumbers[quorumNumberIndex]), referenceBlockNumber @@ -149,15 +162,18 @@ contract OperatorStateRetriever { // resize the array to the number of nonSigners for this quorum uint32[] memory nonSignerStakeIndicesForQuorum = new uint32[](numNonSignersForQuorum); - for (uint i = 0; i < numNonSignersForQuorum; i++) { - nonSignerStakeIndicesForQuorum[i] = checkSignaturesIndices.nonSignerStakeIndices[quorumNumberIndex][i]; + for (uint256 i = 0; i < numNonSignersForQuorum; i++) { + nonSignerStakeIndicesForQuorum[i] = + checkSignaturesIndices.nonSignerStakeIndices[quorumNumberIndex][i]; } - checkSignaturesIndices.nonSignerStakeIndices[quorumNumberIndex] = nonSignerStakeIndicesForQuorum; + checkSignaturesIndices.nonSignerStakeIndices[quorumNumberIndex] = + nonSignerStakeIndicesForQuorum; } IBLSApkRegistry blsApkRegistry = registryCoordinator.blsApkRegistry(); // get the indices of the quorum apks for each of the provided quorums at the given blocknumber - checkSignaturesIndices.quorumApkIndices = blsApkRegistry.getApkIndicesAtBlockNumber(quorumNumbers, referenceBlockNumber); + checkSignaturesIndices.quorumApkIndices = + blsApkRegistry.getApkIndicesAtBlockNumber(quorumNumbers, referenceBlockNumber); return checkSignaturesIndices; } @@ -173,10 +189,13 @@ contract OperatorStateRetriever { bytes32[] memory operatorIds, uint32 blockNumber ) external view returns (uint256[] memory) { - uint32[] memory quorumBitmapIndices = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); + uint32[] memory quorumBitmapIndices = + registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); uint256[] memory quorumBitmaps = new uint256[](operatorIds.length); for (uint256 i = 0; i < operatorIds.length; i++) { - quorumBitmaps[i] = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorIds[i], blockNumber, quorumBitmapIndices[i]); + quorumBitmaps[i] = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex( + operatorIds[i], blockNumber, quorumBitmapIndices[i] + ); } return quorumBitmaps; } @@ -212,5 +231,4 @@ contract OperatorStateRetriever { operators[i] = registryCoordinator.getOperatorFromId(operatorIds[i]); } } - } diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 9a55ffc5..7b906a70 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -3,8 +3,12 @@ pragma solidity ^0.8.27; import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; -import {IStrategy } from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; -import {IAllocationManager, OperatorSet, IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; +import { + IAllocationManager, + OperatorSet, + IAllocationManagerTypes +} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {ISocketUpdater} from "./interfaces/ISocketUpdater.sol"; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; @@ -54,7 +58,9 @@ contract RegistryCoordinator is /// @dev Checks that `quorumNumber` corresponds to a quorum that has been created /// via `initialize` or `createQuorum` - modifier quorumExists(uint8 quorumNumber) { + modifier quorumExists( + uint8 quorumNumber + ) { _checkQuorumExists(quorumNumber); _; } @@ -122,7 +128,13 @@ contract RegistryCoordinator is // Create quorums for (uint256 i = 0; i < _operatorSetParams.length; i++) { - _createQuorum(_operatorSetParams[i], _minimumStakes[i], _strategyParams[i], _stakeTypes[i], _lookAheadPeriods[i]); + _createQuorum( + _operatorSetParams[i], + _minimumStakes[i], + _strategyParams[i], + _stakeTypes[i], + _lookAheadPeriods[i] + ); } } @@ -201,10 +213,7 @@ contract RegistryCoordinator is SignatureWithSaltAndExpiry memory operatorSignature ) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { require(!isUsingOperatorSets(), OperatorSetsEnabled()); - require( - operatorKickParams.length == quorumNumbers.length, - InputLengthMismatch() - ); + require(operatorKickParams.length == quorumNumbers.length, InputLengthMismatch()); /** * If the operator has NEVER registered a pubkey before, use `params` to register @@ -261,19 +270,15 @@ contract RegistryCoordinator is * @notice Deregisters the caller from one or more quorums * @param quorumNumbers is an ordered byte array containing the quorum numbers being deregistered from */ - function deregisterOperator(bytes memory quorumNumbers) - external - onlyWhenNotPaused(PAUSED_DEREGISTER_OPERATOR) - { + function deregisterOperator( + bytes memory quorumNumbers + ) external onlyWhenNotPaused(PAUSED_DEREGISTER_OPERATOR) { // Check that either: // 1. The AVS hasn't migrated to operator sets yet (!isOperatorSetAVS), or // 2. The AVS has migrated but this is an M2 quorum for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); - require( - !isOperatorSetAVS || isM2Quorum[quorumNumber], - OperatorSetsEnabled() - ); + require(!isOperatorSetAVS || isM2Quorum[quorumNumber], OperatorSetsEnabled()); } _deregisterOperator({operator: msg.sender, quorumNumbers: quorumNumbers}); } @@ -306,10 +311,8 @@ contract RegistryCoordinator is _checkAllocationManager(); // Decode registration data from bytes - ( - string memory socket, - IBLSApkRegistry.PubkeyRegistrationParams memory params - ) = abi.decode(data, (string, IBLSApkRegistry.PubkeyRegistrationParams)); + (string memory socket, IBLSApkRegistry.PubkeyRegistrationParams memory params) = + abi.decode(data, (string, IBLSApkRegistry.PubkeyRegistrationParams)); // Get operator ID from BLS registry bytes32 operatorId = _getOrCreateOperatorId(operator, params); @@ -350,10 +353,9 @@ contract RegistryCoordinator is * @dev stakes are queried from the Eigenlayer core DelegationManager contract * @param operators a list of operator addresses to update */ - function updateOperators(address[] memory operators) - external - onlyWhenNotPaused(PAUSED_UPDATE_OPERATOR) - { + function updateOperators( + address[] memory operators + ) external onlyWhenNotPaused(PAUSED_UPDATE_OPERATOR) { for (uint256 i = 0; i < operators.length; i++) { address operator = operators[i]; OperatorInfo memory operatorInfo = _operatorInfo[operator]; @@ -389,10 +391,7 @@ contract RegistryCoordinator is // - there should be no duplicates in `quorumNumbers` // - there should be one list of operators per quorum BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount); - require( - operatorsPerQuorum.length == quorumNumbers.length, - InputLengthMismatch() - ); + require(operatorsPerQuorum.length == quorumNumbers.length, InputLengthMismatch()); // For each quorum, update ALL registered operators for (uint256 i = 0; i < quorumNumbers.length; ++i) { @@ -420,14 +419,10 @@ contract RegistryCoordinator is uint192 currentBitmap = _currentOperatorBitmap(operatorId); // Check that the operator is registered require( - BitmapUtils.isSet(currentBitmap, quorumNumber), - NotRegisteredForQuorum() + BitmapUtils.isSet(currentBitmap, quorumNumber), NotRegisteredForQuorum() ); // Prevent duplicate operators - require( - operator > prevOperatorAddress, - NotSorted() - ); + require(operator > prevOperatorAddress, NotSorted()); } // Update the operator @@ -445,11 +440,10 @@ contract RegistryCoordinator is * @notice Updates the socket of the msg.sender given they are a registered operator * @param socket is the new socket of the operator */ - function updateSocket(string memory socket) external { - require( - _operatorInfo[msg.sender].status == OperatorStatus.REGISTERED, - NotRegistered() - ); + function updateSocket( + string memory socket + ) external { + require(_operatorInfo[msg.sender].status == OperatorStatus.REGISTERED, NotRegistered()); emit OperatorSocketUpdate(_operatorInfo[msg.sender].operatorId, socket); } @@ -513,7 +507,13 @@ contract RegistryCoordinator is uint32 lookAheadPeriod ) external virtual onlyOwner { require(isUsingOperatorSets(), OperatorSetsNotEnabled()); - _createQuorum(operatorSetParams, minimumStake, strategyParams, StakeType.TOTAL_SLASHABLE, lookAheadPeriod); + _createQuorum( + operatorSetParams, + minimumStake, + strategyParams, + StakeType.TOTAL_SLASHABLE, + lookAheadPeriod + ); } /** @@ -536,7 +536,9 @@ contract RegistryCoordinator is * @param _churnApprover the new churn approver * @dev only callable by the owner */ - function setChurnApprover(address _churnApprover) external onlyOwner { + function setChurnApprover( + address _churnApprover + ) external onlyOwner { _setChurnApprover(_churnApprover); } @@ -545,7 +547,9 @@ contract RegistryCoordinator is * @param _ejector the new ejector * @dev only callable by the owner */ - function setEjector(address _ejector) external onlyOwner { + function setEjector( + address _ejector + ) external onlyOwner { _setEjector(_ejector); } @@ -555,7 +559,9 @@ contract RegistryCoordinator is * @param _ejectionCooldown the new ejection cooldown in seconds * @dev only callable by the owner */ - function setEjectionCooldown(uint256 _ejectionCooldown) external onlyOwner { + function setEjectionCooldown( + uint256 _ejectionCooldown + ) external onlyOwner { ejectionCooldown = _ejectionCooldown; } @@ -591,13 +597,8 @@ contract RegistryCoordinator is uint192 quorumsToAdd = uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); uint192 currentBitmap = _currentOperatorBitmap(operatorId); - require( - !quorumsToAdd.isEmpty(), BitmapEmpty() - ); - require( - quorumsToAdd.noBitsInCommon(currentBitmap), - AlreadyRegisteredForQuorums() - ); + require(!quorumsToAdd.isEmpty(), BitmapEmpty()); + require(quorumsToAdd.noBitsInCommon(currentBitmap), AlreadyRegisteredForQuorums()); uint192 newBitmap = uint192(currentBitmap.plus(quorumsToAdd)); // Check that the operator can reregister if ejected @@ -622,7 +623,6 @@ contract RegistryCoordinator is serviceManager.registerOperatorToAVS(operator, operatorSignature); emit OperatorRegistered(operator, operatorId); - } // Register the operator with the BLSApkRegistry, StakeRegistry, and IndexRegistry @@ -654,13 +654,8 @@ contract RegistryCoordinator is uint192 quorumsToAdd = uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); uint192 currentBitmap = _currentOperatorBitmap(operatorId); - require( - !quorumsToAdd.isEmpty(), BitmapEmpty() - ); - require( - quorumsToAdd.noBitsInCommon(currentBitmap), - AlreadyRegisteredForQuorums() - ); + require(!quorumsToAdd.isEmpty(), BitmapEmpty()); + require(quorumsToAdd.noBitsInCommon(currentBitmap), AlreadyRegisteredForQuorums()); uint192 newBitmap = uint192(currentBitmap.plus(quorumsToAdd)); // Check that the operator can reregister if ejected @@ -709,11 +704,10 @@ contract RegistryCoordinator is * @param quorumNumber The quorum number to check * @dev Reverts if the quorum does not exist */ - function _checkQuorumExists(uint8 quorumNumber) internal view { - require( - quorumNumber < quorumCount, - QuorumDoesNotExist() - ); + function _checkQuorumExists( + uint8 quorumNumber + ) internal view { + require(quorumNumber < quorumCount, QuorumDoesNotExist()); } /** @@ -765,14 +759,8 @@ contract RegistryCoordinator is ) internal view { address operatorToKick = kickParams.operator; bytes32 idToKick = _operatorInfo[operatorToKick].operatorId; - require( - newOperator != operatorToKick, - CannotChurnSelf() - ); - require( - kickParams.quorumNumber == quorumNumber, - QuorumOperatorCountMismatch() - ); + require(newOperator != operatorToKick, CannotChurnSelf()); + require(kickParams.quorumNumber == quorumNumber, QuorumOperatorCountMismatch()); // Get the target operator's stake and check that it is below the kick thresholds uint96 operatorToKickStake = stakeRegistry.getCurrentStake(idToKick, quorumNumber); @@ -795,10 +783,7 @@ contract RegistryCoordinator is // Fetch the operator's info and ensure they are registered OperatorInfo storage operatorInfo = _operatorInfo[operator]; bytes32 operatorId = operatorInfo.operatorId; - require( - operatorInfo.status == OperatorStatus.REGISTERED, - NotRegistered() - ); + require(operatorInfo.status == OperatorStatus.REGISTERED, NotRegistered()); /** * Get bitmap of quorums to deregister from and operator's current bitmap. Validate that: @@ -810,14 +795,8 @@ contract RegistryCoordinator is uint192 quorumsToRemove = uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); uint192 currentBitmap = _currentOperatorBitmap(operatorId); - require( - !quorumsToRemove.isEmpty(), - BitmapCannotBeZero() - ); - require( - quorumsToRemove.isSubsetOf(currentBitmap), - NotRegisteredForQuorum() - ); + require(!quorumsToRemove.isEmpty(), BitmapCannotBeZero()); + require(quorumsToRemove.isSubsetOf(currentBitmap), NotRegisteredForQuorum()); uint192 newBitmap = uint192(currentBitmap.minus(quorumsToRemove)); // Update operator's bitmap and status @@ -893,14 +872,8 @@ contract RegistryCoordinator is SignatureWithSaltAndExpiry memory churnApproverSignature ) internal { // make sure the salt hasn't been used already - require( - !isChurnApproverSaltUsed[churnApproverSignature.salt], - ChurnApproverSaltUsed() - ); - require( - churnApproverSignature.expiry >= block.timestamp, - SignatureExpired() - ); + require(!isChurnApproverSaltUsed[churnApproverSignature.salt], ChurnApproverSaltUsed()); + require(churnApproverSignature.expiry >= block.timestamp, SignatureExpired()); // set salt used to true isChurnApproverSaltUsed[churnApproverSignature.salt] = true; @@ -936,10 +909,7 @@ contract RegistryCoordinator is ) internal { // Increment the total quorum count. Fails if we're already at the max uint8 prevQuorumCount = quorumCount; - require( - prevQuorumCount < MAX_QUORUM_COUNT, - MaxQuorumsReached() - ); + require(prevQuorumCount < MAX_QUORUM_COUNT, MaxQuorumsReached()); quorumCount = prevQuorumCount + 1; // The previous count is the new quorum's number @@ -951,7 +921,8 @@ contract RegistryCoordinator is /// Update the AllocationManager if operatorSetQuorum if (isOperatorSetAVS && !isM2Quorum[quorumNumber]) { // Create array of CreateSetParams for the new quorum - IAllocationManagerTypes.CreateSetParams[] memory createSetParams = new IAllocationManagerTypes.CreateSetParams[](1); + IAllocationManagerTypes.CreateSetParams[] memory createSetParams = + new IAllocationManagerTypes.CreateSetParams[](1); // Extract strategies from strategyParams IStrategy[] memory strategies = new IStrategy[](strategyParams.length); @@ -973,7 +944,9 @@ contract RegistryCoordinator is if (stakeType == StakeType.TOTAL_DELEGATED) { stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); } else if (stakeType == StakeType.TOTAL_SLASHABLE) { - stakeRegistry.initializeSlashableStakeQuorum(quorumNumber, minimumStake, lookAheadPeriod, strategyParams); + stakeRegistry.initializeSlashableStakeQuorum( + quorumNumber, minimumStake, lookAheadPeriod, strategyParams + ); } indexRegistry.initializeQuorum(quorumNumber); @@ -990,7 +963,9 @@ contract RegistryCoordinator is /// @notice Get the most recent bitmap for the operator, returning an empty bitmap if /// the operator is not registered. - function _currentOperatorBitmap(bytes32 operatorId) internal view returns (uint192) { + function _currentOperatorBitmap( + bytes32 operatorId + ) internal view returns (uint192) { return QuorumBitmapHistoryLib.currentOperatorBitmap(_operatorBitmapHistory, operatorId); } @@ -1003,7 +978,9 @@ contract RegistryCoordinator is uint32 blockNumber, bytes32 operatorId ) internal view returns (uint32 index) { - return QuorumBitmapHistoryLib.getQuorumBitmapIndexAtBlockNumber(_operatorBitmapHistory,blockNumber, operatorId); + return QuorumBitmapHistoryLib.getQuorumBitmapIndexAtBlockNumber( + _operatorBitmapHistory, blockNumber, operatorId + ); } function _setOperatorSetParams( @@ -1014,12 +991,16 @@ contract RegistryCoordinator is emit OperatorSetParamsUpdated(quorumNumber, operatorSetParams); } - function _setChurnApprover(address newChurnApprover) internal { + function _setChurnApprover( + address newChurnApprover + ) internal { emit ChurnApproverUpdated(churnApprover, newChurnApprover); churnApprover = newChurnApprover; } - function _setEjector(address newEjector) internal { + function _setEjector( + address newEjector + ) internal { emit EjectorUpdated(ejector, newEjector); ejector = newEjector; } @@ -1031,35 +1012,37 @@ contract RegistryCoordinator is */ /// @notice Returns the operator set params for the given `quorumNumber` - function getOperatorSetParams(uint8 quorumNumber) - external - view - returns (OperatorSetParam memory) - { + function getOperatorSetParams( + uint8 quorumNumber + ) external view returns (OperatorSetParam memory) { return _quorumParams[quorumNumber]; } /// @notice Returns the operator struct for the given `operator` - function getOperator(address operator) external view returns (OperatorInfo memory) { + function getOperator( + address operator + ) external view returns (OperatorInfo memory) { return _operatorInfo[operator]; } /// @notice Returns the operatorId for the given `operator` - function getOperatorId(address operator) external view returns (bytes32) { + function getOperatorId( + address operator + ) external view returns (bytes32) { return _operatorInfo[operator].operatorId; } /// @notice Returns the operator address for the given `operatorId` - function getOperatorFromId(bytes32 operatorId) external view returns (address) { + function getOperatorFromId( + bytes32 operatorId + ) external view returns (address) { return blsApkRegistry.getOperatorFromPubkeyHash(operatorId); } /// @notice Returns the status for the given `operator` - function getOperatorStatus(address operator) - external - view - returns (IRegistryCoordinator.OperatorStatus) - { + function getOperatorStatus( + address operator + ) external view returns (IRegistryCoordinator.OperatorStatus) { return _operatorInfo[operator].status; } @@ -1072,7 +1055,9 @@ contract RegistryCoordinator is uint32 blockNumber, bytes32[] memory operatorIds ) external view returns (uint32[] memory) { - return QuorumBitmapHistoryLib.getQuorumBitmapIndicesAtBlockNumber(_operatorBitmapHistory, blockNumber, operatorIds); + return QuorumBitmapHistoryLib.getQuorumBitmapIndicesAtBlockNumber( + _operatorBitmapHistory, blockNumber, operatorIds + ); } /** @@ -1086,7 +1071,9 @@ contract RegistryCoordinator is uint32 blockNumber, uint256 index ) external view returns (uint192) { - return QuorumBitmapHistoryLib.getQuorumBitmapAtBlockNumberByIndex(_operatorBitmapHistory, operatorId, blockNumber, index); + return QuorumBitmapHistoryLib.getQuorumBitmapAtBlockNumberByIndex( + _operatorBitmapHistory, operatorId, blockNumber, index + ); } /// @notice Returns the `index`th entry in the operator with `operatorId`'s bitmap history @@ -1098,12 +1085,16 @@ contract RegistryCoordinator is } /// @notice Returns the current quorum bitmap for the given `operatorId` or 0 if the operator is not registered for any quorum - function getCurrentQuorumBitmap(bytes32 operatorId) external view returns (uint192) { + function getCurrentQuorumBitmap( + bytes32 operatorId + ) external view returns (uint192) { return _currentOperatorBitmap(operatorId); } /// @notice Returns the length of the quorum bitmap history for the given `operatorId` - function getQuorumBitmapHistoryLength(bytes32 operatorId) external view returns (uint256) { + function getQuorumBitmapHistoryLength( + bytes32 operatorId + ) external view returns (uint256) { return _operatorBitmapHistory[operatorId].length; } @@ -1145,11 +1136,9 @@ contract RegistryCoordinator is * @notice Returns the message hash that an operator must sign to register their BLS public key. * @param operator is the address of the operator registering their BLS public key */ - function pubkeyRegistrationMessageHash(address operator) - public - view - returns (BN254.G1Point memory) - { + function pubkeyRegistrationMessageHash( + address operator + ) public view returns (BN254.G1Point memory) { return BN254.hashToG1( _hashTypedDataV4(keccak256(abi.encode(PUBKEY_REGISTRATION_TYPEHASH, operator))) ); diff --git a/src/RegistryCoordinatorStorage.sol b/src/RegistryCoordinatorStorage.sol index 296da275..00a422ba 100644 --- a/src/RegistryCoordinatorStorage.sol +++ b/src/RegistryCoordinatorStorage.sol @@ -6,24 +6,31 @@ import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; -import {IAllocationManager, OperatorSet, IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import { + IAllocationManager, + OperatorSet, + IAllocationManagerTypes +} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { - - /******************************************************************************* - CONSTANTS AND IMMUTABLES - *******************************************************************************/ + /** + * + * CONSTANTS AND IMMUTABLES + * + */ /// @notice The EIP-712 typehash for the `DelegationApproval` struct used by the contract - bytes32 public constant OPERATOR_CHURN_APPROVAL_TYPEHASH = - keccak256("OperatorChurnApproval(address registeringOperator,bytes32 registeringOperatorId,OperatorKickParam[] operatorKickParams,bytes32 salt,uint256 expiry)OperatorKickParam(uint8 quorumNumber,address operator)"); + bytes32 public constant OPERATOR_CHURN_APPROVAL_TYPEHASH = keccak256( + "OperatorChurnApproval(address registeringOperator,bytes32 registeringOperatorId,OperatorKickParam[] operatorKickParams,bytes32 salt,uint256 expiry)OperatorKickParam(uint8 quorumNumber,address operator)" + ); /// @notice The EIP-712 typehash used for registering BLS public keys - bytes32 public constant PUBKEY_REGISTRATION_TYPEHASH = keccak256("BN254PubkeyRegistration(address operator)"); + bytes32 public constant PUBKEY_REGISTRATION_TYPEHASH = + keccak256("BN254PubkeyRegistration(address operator)"); /// @notice The maximum value of a quorum bitmap uint256 internal constant MAX_QUORUM_BITMAP = type(uint192).max; /// @notice The basis point denominator - uint16 internal constant BIPS_DENOMINATOR = 10000; + uint16 internal constant BIPS_DENOMINATOR = 10_000; /// @notice Index for flag that pauses operator registration uint8 internal constant PAUSED_REGISTER_OPERATOR = 0; /// @notice Index for flag that pauses operator deregistration @@ -46,9 +53,11 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { /// @notice the AllocationManager that tracks OperatorSets and Slashing in EigenLayer IAllocationManager public immutable allocationManager; - /******************************************************************************* - STATE - *******************************************************************************/ + /** + * + * STATE + * + */ /// @notice the current number of quorums supported by the registry coordinator uint8 public quorumCount; diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index 72074630..a7be2742 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -7,7 +7,8 @@ import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSD import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; -import {IPermissionController} from "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; +import {IPermissionController} from + "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; import {ServiceManagerBaseStorage} from "./ServiceManagerBaseStorage.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; @@ -67,39 +68,32 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { } /// @inheritdoc IServiceManager - function addPendingAdmin(address admin) external onlyOwner { - _permissionController.addPendingAdmin({ - account: address(this), - admin: admin - }); + function addPendingAdmin( + address admin + ) external onlyOwner { + _permissionController.addPendingAdmin({account: address(this), admin: admin}); } /// @inheritdoc IServiceManager - function removePendingAdmin(address pendingAdmin) external onlyOwner { - _permissionController.removePendingAdmin({ - account: address(this), - admin: pendingAdmin - }); + function removePendingAdmin( + address pendingAdmin + ) external onlyOwner { + _permissionController.removePendingAdmin({account: address(this), admin: pendingAdmin}); } /// @inheritdoc IServiceManager - function removeAdmin(address admin) external onlyOwner { - _permissionController.removeAdmin({ - account: address(this), - admin: admin - }); + function removeAdmin( + address admin + ) external onlyOwner { + _permissionController.removeAdmin({account: address(this), admin: admin}); } /// @inheritdoc IServiceManager - function setAppointee( - address appointee, - address target, - bytes4 selector - ) external onlyOwner { + function setAppointee(address appointee, address target, bytes4 selector) external onlyOwner { _permissionController.setAppointee({ - account: address(this), - appointee: appointee, - target: target, + account: address(this), + appointee: appointee, + target: target, selector: selector }); } @@ -123,7 +117,9 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { * @param _metadataURI is the metadata URI for the AVS * @dev only callable by the owner */ - function updateAVSMetadataURI(string memory _metadataURI) public virtual onlyOwner { + function updateAVSMetadataURI( + string memory _metadataURI + ) public virtual onlyOwner { _avsDirectory.updateAVSMetadataURI(_metadataURI); } @@ -173,7 +169,9 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { * @notice Forwards a call to EigenLayer's AVSDirectory contract to confirm operator deregistration from the AVS * @param operator The address of the operator to deregister. */ - function deregisterOperatorFromAVS(address operator) public virtual onlyRegistryCoordinator { + function deregisterOperatorFromAVS( + address operator + ) public virtual onlyRegistryCoordinator { _avsDirectory.deregisterOperatorFromAVS(operator); } @@ -182,11 +180,15 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { * @param newRewardsInitiator The new rewards initiator address * @dev only callable by the owner */ - function setRewardsInitiator(address newRewardsInitiator) external onlyOwner { + function setRewardsInitiator( + address newRewardsInitiator + ) external onlyOwner { _setRewardsInitiator(newRewardsInitiator); } - function _setRewardsInitiator(address newRewardsInitiator) internal { + function _setRewardsInitiator( + address newRewardsInitiator + ) internal { emit RewardsInitiatorUpdated(rewardsInitiator, newRewardsInitiator); rewardsInitiator = newRewardsInitiator; } @@ -197,7 +199,7 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { * @dev No guarantee is made on uniqueness of each element in the returned array. * The off-chain service should do that validation separately */ - function getRestakeableStrategies() external virtual view returns (address[] memory) { + function getRestakeableStrategies() external view virtual returns (address[] memory) { uint256 quorumCount = _registryCoordinator.quorumCount(); if (quorumCount == 0) { @@ -229,12 +231,9 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { * @dev No guarantee is made on whether the operator has shares for a strategy in a quorum or uniqueness * of each element in the returned array. The off-chain service should do that validation separately */ - function getOperatorRestakedStrategies(address operator) - external - virtual - view - returns (address[] memory) - { + function getOperatorRestakedStrategies( + address operator + ) external view virtual returns (address[] memory) { bytes32 operatorId = _registryCoordinator.getOperatorId(operator); uint192 operatorBitmap = _registryCoordinator.getCurrentQuorumBitmap(operatorId); diff --git a/src/ServiceManagerBaseStorage.sol b/src/ServiceManagerBaseStorage.sol index 6a4ef819..a94212ef 100644 --- a/src/ServiceManagerBaseStorage.sol +++ b/src/ServiceManagerBaseStorage.sol @@ -8,9 +8,12 @@ import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; -import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; -import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IPermissionController} from "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; +import {IRewardsCoordinator} from + "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import {IAllocationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IPermissionController} from + "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; /** * @title Storage variables for the `ServiceManagerBase` contract. diff --git a/src/ServiceManagerRouter.sol b/src/ServiceManagerRouter.sol index 05a56780..2589ea74 100644 --- a/src/ServiceManagerRouter.sol +++ b/src/ServiceManagerRouter.sol @@ -9,19 +9,19 @@ import {IServiceManagerUI} from "./interfaces/IServiceManagerUI.sol"; * errors to be handled gracefully. * @author Layr Labs, Inc. */ - contract ServiceManagerRouter { - - address public constant FAILED_CALL_ADDRESS = address(0x000000000000000000000000000000000000dEaD); + address public constant FAILED_CALL_ADDRESS = + address(0x000000000000000000000000000000000000dEaD); /** * @notice Returns the list of strategies that the AVS supports for restaking * @param serviceManager Address of AVS's ServiceManager contract */ - function getRestakeableStrategies(address serviceManager) external view returns (address[] memory) { - bytes memory data = abi.encodeWithSelector( - IServiceManagerUI.getRestakeableStrategies.selector - ); + function getRestakeableStrategies( + address serviceManager + ) external view returns (address[] memory) { + bytes memory data = + abi.encodeWithSelector(IServiceManagerUI.getRestakeableStrategies.selector); return _makeCall(serviceManager, data); } @@ -30,10 +30,12 @@ contract ServiceManagerRouter { * @param serviceManager Address of AVS's ServiceManager contract * @param operator Address of the operator to get restaked strategies for */ - function getOperatorRestakedStrategies(address serviceManager, address operator) external view returns (address[] memory) { + function getOperatorRestakedStrategies( + address serviceManager, + address operator + ) external view returns (address[] memory) { bytes memory data = abi.encodeWithSelector( - IServiceManagerUI.getOperatorRestakedStrategies.selector, - operator + IServiceManagerUI.getOperatorRestakedStrategies.selector, operator ); return _makeCall(serviceManager, data); } @@ -43,7 +45,10 @@ contract ServiceManagerRouter { * @dev Handles calls to contracts that don't implement the given function and to EOAs by * returning a failed call address */ - function _makeCall(address serviceManager, bytes memory data) internal view returns (address[] memory) { + function _makeCall( + address serviceManager, + bytes memory data + ) internal view returns (address[] memory) { (bool success, bytes memory strategiesBytes) = serviceManager.staticcall(data); if (success && strategiesBytes.length > 0) { return abi.decode(strategiesBytes, (address[])); diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index 359da941..d93763c3 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -1,10 +1,12 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; -import {IAVSDirectory } from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IDelegationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {StakeRegistryStorage, IStrategy} from "./StakeRegistryStorage.sol"; @@ -24,7 +26,6 @@ import {BitmapUtils} from "./libraries/BitmapUtils.sol"; * @author Layr Labs, Inc. */ contract StakeRegistry is StakeRegistryStorage { - using BitmapUtils for *; modifier onlyRegistryCoordinator() { @@ -37,7 +38,9 @@ contract StakeRegistry is StakeRegistryStorage { _; } - modifier quorumExists(uint8 quorumNumber) { + modifier quorumExists( + uint8 quorumNumber + ) { _checkQuorumExists(quorumNumber); _; } @@ -48,11 +51,21 @@ contract StakeRegistry is StakeRegistryStorage { IAVSDirectory _avsDirectory, IAllocationManager _allocationManager, IServiceManager _serviceManager - ) StakeRegistryStorage(_registryCoordinator, _delegationManager, _avsDirectory, _allocationManager, _serviceManager) {} + ) + StakeRegistryStorage( + _registryCoordinator, + _delegationManager, + _avsDirectory, + _allocationManager, + _serviceManager + ) + {} - /******************************************************************************* - EXTERNAL FUNCTIONS - REGISTRY COORDINATOR - *******************************************************************************/ + /** + * + * EXTERNAL FUNCTIONS - REGISTRY COORDINATOR + * + */ /** * @notice Registers the `operator` with `operatorId` for the specified `quorumNumbers`. @@ -72,17 +85,16 @@ contract StakeRegistry is StakeRegistryStorage { bytes32 operatorId, bytes calldata quorumNumbers ) public virtual onlyRegistryCoordinator returns (uint96[] memory, uint96[] memory) { - uint96[] memory currentStakes = new uint96[](quorumNumbers.length); uint96[] memory totalStakes = new uint96[](quorumNumbers.length); for (uint256 i = 0; i < quorumNumbers.length; i++) { - uint8 quorumNumber = uint8(quorumNumbers[i]); _checkQuorumExists(quorumNumber); // Retrieve the operator's current weighted stake for the quorum, reverting if they have not met // the minimum. - (uint96 currentStake, bool hasMinimumStake) = _weightOfOperatorForQuorum(quorumNumber, operator); + (uint96 currentStake, bool hasMinimumStake) = + _weightOfOperatorForQuorum(quorumNumber, operator); require(hasMinimumStake, BelowMinimumStakeRequirement()); // Update the operator's stake @@ -166,7 +178,8 @@ contract StakeRegistry is StakeRegistryStorage { // Fetch the operator's current stake, applying weighting parameters and checking // against the minimum stake requirements for the quorum. - (uint96 stakeWeight, bool hasMinimumStake) = _weightOfOperatorForQuorum(quorumNumber, operator); + (uint96 stakeWeight, bool hasMinimumStake) = + _weightOfOperatorForQuorum(quorumNumber, operator); // If the operator no longer meets the minimum stake, set their stake to zero and mark them for removal /// also handle setting the operator's stake to 0 and remove them from the quorum if (!hasMinimumStake) { @@ -200,14 +213,15 @@ contract StakeRegistry is StakeRegistryStorage { _setMinimumStakeForQuorum(quorumNumber, minimumStake); _setStakeType(quorumNumber, StakeType.TOTAL_DELEGATED); - _totalStakeHistory[quorumNumber].push(StakeUpdate({ - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0, - stake: 0 - })); + _totalStakeHistory[quorumNumber].push( + StakeUpdate({ + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0, + stake: 0 + }) + ); } - /// @notice Initialize a new quorum and push its first history update function initializeSlashableStakeQuorum( uint8 quorumNumber, @@ -221,11 +235,13 @@ contract StakeRegistry is StakeRegistryStorage { _setStakeType(quorumNumber, StakeType.TOTAL_SLASHABLE); _setLookAheadPeriod(quorumNumber, lookAheadPeriod); - _totalStakeHistory[quorumNumber].push(StakeUpdate({ - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0, - stake: 0 - })); + _totalStakeHistory[quorumNumber].push( + StakeUpdate({ + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0, + stake: 0 + }) + ); } function setMinimumStakeForQuorum( @@ -261,7 +277,7 @@ contract StakeRegistry is StakeRegistryStorage { uint256 numStratsToAdd = _strategyParams.length; - if (isOperatorSetQuorum(quorumNumber)){ + if (isOperatorSetQuorum(quorumNumber)) { IStrategy[] memory strategiesToAdd = new IStrategy[](numStratsToAdd); for (uint256 i = 0; i < numStratsToAdd; i++) { strategiesToAdd[i] = _strategyParams[i].strategy; @@ -291,20 +307,23 @@ contract StakeRegistry is StakeRegistryStorage { IStrategy[] memory _strategiesToRemove = new IStrategy[](toRemoveLength); for (uint256 i = 0; i < toRemoveLength; i++) { - _strategiesToRemove[i]=_strategyParams[indicesToRemove[i]].strategy; - emit StrategyRemovedFromQuorum(quorumNumber, _strategyParams[indicesToRemove[i]].strategy); - emit StrategyMultiplierUpdated(quorumNumber, _strategyParams[indicesToRemove[i]].strategy, 0); - - + _strategiesToRemove[i] = _strategyParams[indicesToRemove[i]].strategy; + emit StrategyRemovedFromQuorum( + quorumNumber, _strategyParams[indicesToRemove[i]].strategy + ); + emit StrategyMultiplierUpdated( + quorumNumber, _strategyParams[indicesToRemove[i]].strategy, 0 + ); // Replace index to remove with the last item in the list, then pop the last item _strategyParams[indicesToRemove[i]] = _strategyParams[_strategyParams.length - 1]; _strategyParams.pop(); - _strategiesPerQuorum[indicesToRemove[i]] = _strategiesPerQuorum[_strategiesPerQuorum.length - 1]; + _strategiesPerQuorum[indicesToRemove[i]] = + _strategiesPerQuorum[_strategiesPerQuorum.length - 1]; _strategiesPerQuorum.pop(); } - if (isOperatorSetQuorum(quorumNumber)){ + if (isOperatorSetQuorum(quorumNumber)) { allocationManager.removeStrategiesFromOperatorSet({ avs: address(serviceManager), operatorSetId: quorumNumber, @@ -333,14 +352,17 @@ contract StakeRegistry is StakeRegistryStorage { for (uint256 i = 0; i < numStrats; i++) { // Change the strategy's associated multiplier _strategyParams[strategyIndices[i]].multiplier = newMultipliers[i]; - emit StrategyMultiplierUpdated(quorumNumber, _strategyParams[strategyIndices[i]].strategy, newMultipliers[i]); + emit StrategyMultiplierUpdated( + quorumNumber, _strategyParams[strategyIndices[i]].strategy, newMultipliers[i] + ); } } - /******************************************************************************* - INTERNAL FUNCTIONS - *******************************************************************************/ - + /** + * + * INTERNAL FUNCTIONS + * + */ function _getStakeUpdateIndexForOperatorAtBlockNumber( bytes32 operatorId, uint8 quorumNumber, @@ -350,7 +372,10 @@ contract StakeRegistry is StakeRegistryStorage { // Iterate backwards through operatorStakeHistory until we find an update that preceeds blockNumber for (uint256 i = length; i > 0; i--) { - if (operatorStakeHistory[operatorId][quorumNumber][i - 1].updateBlockNumber <= blockNumber) { + if ( + operatorStakeHistory[operatorId][quorumNumber][i - 1].updateBlockNumber + <= blockNumber + ) { return uint32(i - 1); } } @@ -375,20 +400,22 @@ contract StakeRegistry is StakeRegistryStorage { uint8 quorumNumber, uint96 newStake ) internal returns (int256) { - uint96 prevStake; uint256 historyLength = operatorStakeHistory[operatorId][quorumNumber].length; if (historyLength == 0) { // No prior stake history - push our first entry - operatorStakeHistory[operatorId][quorumNumber].push(StakeUpdate({ - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0, - stake: newStake - })); + operatorStakeHistory[operatorId][quorumNumber].push( + StakeUpdate({ + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0, + stake: newStake + }) + ); } else { // We have prior stake history - fetch our last-recorded stake - StakeUpdate storage lastUpdate = operatorStakeHistory[operatorId][quorumNumber][historyLength-1]; + StakeUpdate storage lastUpdate = + operatorStakeHistory[operatorId][quorumNumber][historyLength - 1]; prevStake = lastUpdate.stake; // Short-circuit in case there's no change in stake @@ -404,22 +431,27 @@ contract StakeRegistry is StakeRegistryStorage { lastUpdate.stake = newStake; } else { lastUpdate.nextUpdateBlockNumber = uint32(block.number); - operatorStakeHistory[operatorId][quorumNumber].push(StakeUpdate({ - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0, - stake: newStake - })); + operatorStakeHistory[operatorId][quorumNumber].push( + StakeUpdate({ + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0, + stake: newStake + }) + ); } } // Log update and return stake delta emit OperatorStakeUpdate(operatorId, quorumNumber, newStake); - return _calculateDelta({ prev: prevStake, cur: newStake }); + return _calculateDelta({prev: prevStake, cur: newStake}); } /// @notice Applies a delta to the total stake recorded for `quorumNumber` /// @return Returns the new total stake for the quorum - function _recordTotalStakeUpdate(uint8 quorumNumber, int256 stakeDelta) internal returns (uint96) { + function _recordTotalStakeUpdate( + uint8 quorumNumber, + int256 stakeDelta + ) internal returns (uint96) { // Get our last-recorded stake update uint256 historyLength = _totalStakeHistory[quorumNumber].length; StakeUpdate storage lastStakeUpdate = _totalStakeHistory[quorumNumber][historyLength - 1]; @@ -440,11 +472,13 @@ contract StakeRegistry is StakeRegistryStorage { lastStakeUpdate.stake = newStake; } else { lastStakeUpdate.nextUpdateBlockNumber = uint32(block.number); - _totalStakeHistory[quorumNumber].push(StakeUpdate({ - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0, - stake: newStake - })); + _totalStakeHistory[quorumNumber].push( + StakeUpdate({ + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0, + stake: newStake + }) + ); } return newStake; @@ -480,9 +514,7 @@ contract StakeRegistry is StakeRegistryStorage { strategiesPerQuorum[quorumNumber].push(_strategyParams[i].strategy); emit StrategyAddedToQuorum(quorumNumber, _strategyParams[i].strategy); emit StrategyMultiplierUpdated( - quorumNumber, - _strategyParams[i].strategy, - _strategyParams[i].multiplier + quorumNumber, _strategyParams[i].strategy, _strategyParams[i].multiplier ); } } @@ -513,16 +545,21 @@ contract StakeRegistry is StakeRegistryStorage { */ require(blockNumber >= stakeUpdate.updateBlockNumber, InvalidBlockNumber()); require( - stakeUpdate.nextUpdateBlockNumber == 0 || blockNumber < stakeUpdate.nextUpdateBlockNumber, + stakeUpdate.nextUpdateBlockNumber == 0 + || blockNumber < stakeUpdate.nextUpdateBlockNumber, InvalidBlockNumber() ); } /// Returns total Slashable stake for an operator per strategy that can have the weights applied based on strategy multipliers - function _getSlashableStakePerStrategy(uint8 quorumNumber, address operator) internal view returns (uint256[] memory) { + function _getSlashableStakePerStrategy( + uint8 quorumNumber, + address operator + ) internal view returns (uint256[] memory) { address[] memory operators = new address[](1); operators[0] = operator; - uint32 beforeTimestamp = uint32(block.number + slashableStakeLookAheadPerQuorum[quorumNumber]); + uint32 beforeTimestamp = + uint32(block.number + slashableStakeLookAheadPerQuorum[quorumNumber]); uint256[][] memory slashableShares = allocationManager.getMinimumSlashableStake( OperatorSet(address(serviceManager), quorumNumber), @@ -540,30 +577,38 @@ contract StakeRegistry is StakeRegistryStorage { * @return `uint96` The weighted sum of the operator's shares across each strategy considered by the quorum * @return `bool` True if the operator meets the quorum's minimum stake */ - function _weightOfOperatorForQuorum(uint8 quorumNumber, address operator) internal virtual view returns (uint96, bool) { + function _weightOfOperatorForQuorum( + uint8 quorumNumber, + address operator + ) internal view virtual returns (uint96, bool) { uint96 weight; uint256 stratsLength = strategyParamsLength(quorumNumber); StrategyParams memory strategyAndMultiplier; uint256[] memory strategyShares; - if (stakeTypePerQuorum[quorumNumber]== StakeType.TOTAL_SLASHABLE) { + if (stakeTypePerQuorum[quorumNumber] == StakeType.TOTAL_SLASHABLE) { strategyShares = _getSlashableStakePerStrategy(quorumNumber, operator); for (uint256 i = 0; i < stratsLength; i++) { strategyAndMultiplier = strategyParams[quorumNumber][i]; if (strategyShares[i] > 0) { - weight += uint96(strategyShares[i] * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR); + weight += uint96( + strategyShares[i] * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR + ); } } } else { /// M2 Concept of delegated stake - strategyShares = delegation.getOperatorShares(operator, strategiesPerQuorum[quorumNumber]); + strategyShares = + delegation.getOperatorShares(operator, strategiesPerQuorum[quorumNumber]); for (uint256 i = 0; i < stratsLength; i++) { // accessing i^th StrategyParams struct for the quorumNumber strategyAndMultiplier = strategyParams[quorumNumber][i]; // add the weight from the shares for this strategy to the total weight if (strategyShares[i] > 0) { - weight += uint96(strategyShares[i] * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR); + weight += uint96( + strategyShares[i] * strategyAndMultiplier.multiplier / WEIGHTING_DIVISOR + ); } } } @@ -574,13 +619,17 @@ contract StakeRegistry is StakeRegistryStorage { } /// @notice Returns `true` if the quorum has been initialized - function _quorumExists(uint8 quorumNumber) internal view returns (bool) { + function _quorumExists( + uint8 quorumNumber + ) internal view returns (bool) { return _totalStakeHistory[quorumNumber].length != 0; } - /******************************************************************************* - VIEW FUNCTIONS - *******************************************************************************/ + /** + * + * VIEW FUNCTIONS + * + */ /** * @notice Returns whether a quorum is an operator set quorum based on its stake type @@ -589,7 +638,9 @@ contract StakeRegistry is StakeRegistryStorage { * @param quorumNumber The quorum number to check * @return True if the quorum is an operator set quorum */ - function isOperatorSetQuorum(uint8 quorumNumber) public view returns (bool) { + function isOperatorSetQuorum( + uint8 quorumNumber + ) public view returns (bool) { bool isM2 = IRegistryCoordinator(registryCoordinator).isM2Quorum(quorumNumber); bool isOperatorSet = IRegistryCoordinator(registryCoordinator).isOperatorSetAVS(); return isOperatorSet && !isM2; @@ -602,13 +653,15 @@ contract StakeRegistry is StakeRegistryStorage { function weightOfOperatorForQuorum( uint8 quorumNumber, address operator - ) public virtual view quorumExists(quorumNumber) returns (uint96) { - (uint96 stake, ) = _weightOfOperatorForQuorum(quorumNumber, operator); + ) public view virtual quorumExists(quorumNumber) returns (uint96) { + (uint96 stake,) = _weightOfOperatorForQuorum(quorumNumber, operator); return stake; } /// @notice Returns the length of the dynamic array stored in `strategyParams[quorumNumber]`. - function strategyParamsLength(uint8 quorumNumber) public view returns (uint256) { + function strategyParamsLength( + uint8 quorumNumber + ) public view returns (uint256) { return strategyParams[quorumNumber].length; } @@ -616,14 +669,15 @@ contract StakeRegistry is StakeRegistryStorage { function strategyParamsByIndex( uint8 quorumNumber, uint256 index - ) public view returns (StrategyParams memory) - { + ) public view returns (StrategyParams memory) { return strategyParams[quorumNumber][index]; } - /******************************************************************************* - VIEW FUNCTIONS - Operator Stake History - *******************************************************************************/ + /** + * + * VIEW FUNCTIONS - Operator Stake History + * + */ /** * @notice Returns the length of an operator's stake history for the given quorum @@ -651,7 +705,10 @@ contract StakeRegistry is StakeRegistryStorage { * @notice Returns the most recent stake weight for the `operatorId` for quorum `quorumNumber` * @dev Function returns weight of **0** in the event that the operator has no stake history */ - function getCurrentStake(bytes32 operatorId, uint8 quorumNumber) external view returns (uint96) { + function getCurrentStake( + bytes32 operatorId, + uint8 quorumNumber + ) external view returns (uint96) { StakeUpdate memory operatorStakeUpdate = getLatestStakeUpdate(operatorId, quorumNumber); return operatorStakeUpdate.stake; } @@ -695,10 +752,9 @@ contract StakeRegistry is StakeRegistryStorage { uint8 quorumNumber, uint32 blockNumber ) external view returns (uint96) { - return - operatorStakeHistory[operatorId][quorumNumber][ - _getStakeUpdateIndexForOperatorAtBlockNumber(operatorId, quorumNumber, blockNumber) - ].stake; + return operatorStakeHistory[operatorId][quorumNumber][_getStakeUpdateIndexForOperatorAtBlockNumber( + operatorId, quorumNumber, blockNumber + )].stake; } /// @notice Returns the indices of the operator stakes for the provided `quorumNumber` at the given `blockNumber` @@ -726,19 +782,24 @@ contract StakeRegistry is StakeRegistryStorage { bytes32 operatorId, uint256 index ) external view returns (uint96) { - StakeUpdate memory operatorStakeUpdate = operatorStakeHistory[operatorId][quorumNumber][index]; + StakeUpdate memory operatorStakeUpdate = + operatorStakeHistory[operatorId][quorumNumber][index]; _validateStakeUpdateAtBlockNumber(operatorStakeUpdate, blockNumber); return operatorStakeUpdate.stake; } - /******************************************************************************* - VIEW FUNCTIONS - Total Stake History - *******************************************************************************/ + /** + * + * VIEW FUNCTIONS - Total Stake History + * + */ /** * @notice Returns the length of the total stake history for the given quorum */ - function getTotalStakeHistoryLength(uint8 quorumNumber) external view returns (uint256) { + function getTotalStakeHistoryLength( + uint8 quorumNumber + ) external view returns (uint256) { return _totalStakeHistory[quorumNumber].length; } @@ -746,7 +807,9 @@ contract StakeRegistry is StakeRegistryStorage { * @notice Returns the stake weight from the latest entry in `_totalStakeHistory` for quorum `quorumNumber`. * @dev Will revert if `_totalStakeHistory[quorumNumber]` is empty. */ - function getCurrentTotalStake(uint8 quorumNumber) external view returns (uint96) { + function getCurrentTotalStake( + uint8 quorumNumber + ) external view returns (uint96) { return _totalStakeHistory[quorumNumber][_totalStakeHistory[quorumNumber].length - 1].stake; } @@ -800,7 +863,10 @@ contract StakeRegistry is StakeRegistryStorage { ); uint256 length = _totalStakeHistory[quorumNumber].length; for (uint256 j = 0; j < length; j++) { - if (_totalStakeHistory[quorumNumber][length - j - 1].updateBlockNumber <= blockNumber) { + if ( + _totalStakeHistory[quorumNumber][length - j - 1].updateBlockNumber + <= blockNumber + ) { indices[i] = uint32(length - j - 1); break; } @@ -830,16 +896,20 @@ contract StakeRegistry is StakeRegistryStorage { emit LookAheadPeriodChanged(oldLookAheadDays, _lookAheadBlocks); } - function _checkRegistryCoordinator() internal view { require(msg.sender == address(registryCoordinator), OnlyRegistryCoordinator()); } function _checkRegistryCoordinatorOwner() internal view { - require(msg.sender == IRegistryCoordinator(registryCoordinator).owner(), OnlyRegistryCoordinatorOwner()); + require( + msg.sender == IRegistryCoordinator(registryCoordinator).owner(), + OnlyRegistryCoordinatorOwner() + ); } - function _checkQuorumExists(uint8 quorumNumber) internal view { + function _checkQuorumExists( + uint8 quorumNumber + ) internal view { require(_quorumExists(quorumNumber), QuorumDoesNotExist()); } } diff --git a/src/StakeRegistryStorage.sol b/src/StakeRegistryStorage.sol index 26f72873..c0d7b933 100644 --- a/src/StakeRegistryStorage.sol +++ b/src/StakeRegistryStorage.sol @@ -1,14 +1,19 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {IDelegationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; -import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; -import {IStrategyManager, IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; +import { + IStrategyManager, + IStrategy +} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; -import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; +import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; /** * @title Storage variables for the `StakeRegistry` contract. @@ -16,13 +21,12 @@ import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; * @notice This storage contract is separate from the logic to simplify the upgrade process. */ abstract contract StakeRegistryStorage is IStakeRegistry { - /// @notice Constant used as a divisor in calculating weights. uint256 public constant WEIGHTING_DIVISOR = 1e18; /// @notice Maximum length of dynamic arrays in the `strategyParams` mapping. uint8 public constant MAX_WEIGHING_FUNCTION_LENGTH = 32; /// @notice Constant used as a divisor in dealing with BIPS amounts. - uint256 internal constant MAX_BIPS = 10000; + uint256 internal constant MAX_BIPS = 10_000; /// @notice The address of the Delegation contract for EigenLayer. IDelegationManager public immutable delegation; diff --git a/src/interfaces/IBLSApkRegistry.sol b/src/interfaces/IBLSApkRegistry.sol index a93d4d53..0b1370b5 100644 --- a/src/interfaces/IBLSApkRegistry.sol +++ b/src/interfaces/IBLSApkRegistry.sol @@ -58,21 +58,15 @@ interface IBLSApkRegistry is IRegistry, IBLSApkRegistryErrors { // EVENTS /// @notice Emitted when `operator` registers with the public keys `pubkeyG1` and `pubkeyG2`. - event NewPubkeyRegistration(address indexed operator, BN254.G1Point pubkeyG1, BN254.G2Point pubkeyG2); + event NewPubkeyRegistration( + address indexed operator, BN254.G1Point pubkeyG1, BN254.G2Point pubkeyG2 + ); // @notice Emitted when a new operator pubkey is registered for a set of quorums - event OperatorAddedToQuorums( - address operator, - bytes32 operatorId, - bytes quorumNumbers - ); + event OperatorAddedToQuorums(address operator, bytes32 operatorId, bytes quorumNumbers); // @notice Emitted when an operator pubkey is removed from a set of quorums - event OperatorRemovedFromQuorums( - address operator, - bytes32 operatorId, - bytes quorumNumbers - ); + event OperatorRemovedFromQuorums(address operator, bytes32 operatorId, bytes quorumNumbers); /** * @notice Registers the `operator`'s pubkey for the specified `quorumNumbers`. @@ -105,20 +99,26 @@ interface IBLSApkRegistry is IRegistry, IBLSApkRegistryErrors { * @notice Initializes a new quorum by pushing its first apk update * @param quorumNumber The number of the new quorum */ - function initializeQuorum(uint8 quorumNumber) external; + function initializeQuorum( + uint8 quorumNumber + ) external; /** * @notice mapping from operator address to pubkey hash. * Returns *zero* if the `operator` has never registered, and otherwise returns the hash of the public key of the operator. */ - function operatorToPubkeyHash(address operator) external view returns (bytes32); + function operatorToPubkeyHash( + address operator + ) external view returns (bytes32); /** * @notice mapping from pubkey hash to operator address. * Returns *zero* if no operator has ever registered the public key corresponding to `pubkeyHash`, * and otherwise returns the (unique) registered operator who owns the BLS public key that is the preimage of `pubkeyHash`. */ - function pubkeyHashToOperator(bytes32 pubkeyHash) external view returns (address); + function pubkeyHashToOperator( + bytes32 pubkeyHash + ) external view returns (address); /** * @notice Called by the RegistryCoordinator register an operator as the owner of a BLS public key. @@ -136,19 +136,31 @@ interface IBLSApkRegistry is IRegistry, IBLSApkRegistryErrors { * @notice Returns the pubkey and pubkey hash of an operator * @dev Reverts if the operator has not registered a valid pubkey */ - function getRegisteredPubkey(address operator) external view returns (BN254.G1Point memory, bytes32); + function getRegisteredPubkey( + address operator + ) external view returns (BN254.G1Point memory, bytes32); /// @notice Returns the current APK for the provided `quorumNumber ` - function getApk(uint8 quorumNumber) external view returns (BN254.G1Point memory); + function getApk( + uint8 quorumNumber + ) external view returns (BN254.G1Point memory); /// @notice Returns the index of the quorumApk index at `blockNumber` for the provided `quorumNumber` - function getApkIndicesAtBlockNumber(bytes calldata quorumNumbers, uint256 blockNumber) external view returns(uint32[] memory); + function getApkIndicesAtBlockNumber( + bytes calldata quorumNumbers, + uint256 blockNumber + ) external view returns (uint32[] memory); /// @notice Returns the `ApkUpdate` struct at `index` in the list of APK updates for the `quorumNumber` - function getApkUpdateAtIndex(uint8 quorumNumber, uint256 index) external view returns (ApkUpdate memory); + function getApkUpdateAtIndex( + uint8 quorumNumber, + uint256 index + ) external view returns (ApkUpdate memory); /// @notice Returns the operator address for the given `pubkeyHash` - function getOperatorFromPubkeyHash(bytes32 pubkeyHash) external view returns (address); + function getOperatorFromPubkeyHash( + bytes32 pubkeyHash + ) external view returns (address); /** * @notice get 24 byte hash of the apk of `quorumNumber` at `blockNumber` using the provided `index`; @@ -157,9 +169,15 @@ interface IBLSApkRegistry is IRegistry, IBLSApkRegistryErrors { * @param blockNumber is the number of the block for which the latest ApkHash will be retrieved * @param index is the index of the apkUpdate being retrieved from the list of quorum apkUpdates in storage */ - function getApkHashAtBlockNumberAndIndex(uint8 quorumNumber, uint32 blockNumber, uint256 index) external view returns (bytes24); + function getApkHashAtBlockNumberAndIndex( + uint8 quorumNumber, + uint32 blockNumber, + uint256 index + ) external view returns (bytes24); /// @notice returns the ID used to identify the `operator` within this AVS. /// @dev Returns zero in the event that the `operator` has never registered for the AVS - function getOperatorId(address operator) external view returns (bytes32); + function getOperatorId( + address operator + ) external view returns (bytes32); } diff --git a/src/interfaces/IBLSSignatureChecker.sol b/src/interfaces/IBLSSignatureChecker.sol index 4ab73f4c..6a7df2c5 100644 --- a/src/interfaces/IBLSSignatureChecker.sol +++ b/src/interfaces/IBLSSignatureChecker.sol @@ -54,7 +54,6 @@ interface IBLSSignatureChecker is IBLSSignatureCheckerErrors { * @notice this data structure is used for recording the details on the total stake of the registered * operators and those operators who are part of the quorum for a particular taskNumber */ - struct QuorumStakeTotals { // total stake of the operators in each quorum uint96[] signedStakeForQuorum; @@ -95,11 +94,5 @@ interface IBLSSignatureChecker is IBLSSignatureCheckerErrors { bytes calldata quorumNumbers, uint32 referenceBlockNumber, NonSignerStakesAndSignature memory nonSignerStakesAndSignature - ) - external - view - returns ( - QuorumStakeTotals memory, - bytes32 - ); + ) external view returns (QuorumStakeTotals memory, bytes32); } diff --git a/src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol b/src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol index b43743d3..96bea50a 100644 --- a/src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol +++ b/src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol @@ -36,20 +36,13 @@ interface ECDSAStakeRegistryEventsAndErrors { /// @notice Emitted when the weight required to be an operator changes /// @param oldMinimumWeight The previous weight /// @param newMinimumWeight The updated weight - event UpdateMinimumWeight( - uint256 oldMinimumWeight, - uint256 newMinimumWeight - ); + event UpdateMinimumWeight(uint256 oldMinimumWeight, uint256 newMinimumWeight); /// @notice Emitted when the system updates an operator's weight /// @param _operator The address of the operator updated /// @param oldWeight The operator's weight before the update /// @param newWeight The operator's weight after the update - event OperatorWeightUpdated( - address indexed _operator, - uint256 oldWeight, - uint256 newWeight - ); + event OperatorWeightUpdated(address indexed _operator, uint256 oldWeight, uint256 newWeight); /// @notice Emitted when the system updates the total weight /// @param oldTotalWeight The total weight before the update @@ -71,6 +64,7 @@ interface ECDSAStakeRegistryEventsAndErrors { address oldSigningKey ); /// @notice Indicates when the lengths of the signers array and signatures array do not match. + error LengthMismatch(); /// @notice Indicates encountering an invalid length for the signers or signatures array. diff --git a/src/interfaces/IEjectionManager.sol b/src/interfaces/IEjectionManager.sol index 478e21d8..a491a973 100644 --- a/src/interfaces/IEjectionManager.sol +++ b/src/interfaces/IEjectionManager.sol @@ -13,7 +13,6 @@ interface IEjectionManagerErrors { * @author Layr Labs, Inc. */ interface IEjectionManager is IEjectionManagerErrors { - /// @notice A quorum's ratelimit parameters struct QuorumEjectionParams { uint32 rateLimitWindow; // Time delta to track ejection over @@ -29,24 +28,31 @@ interface IEjectionManager is IEjectionManagerErrors { ///@notice Emitted when the ejector address is set event EjectorUpdated(address ejector, bool status); ///@notice Emitted when the ratelimit parameters for a quorum are set - event QuorumEjectionParamsSet(uint8 quorumNumber, uint32 rateLimitWindow, uint16 ejectableStakePercent); + event QuorumEjectionParamsSet( + uint8 quorumNumber, uint32 rateLimitWindow, uint16 ejectableStakePercent + ); ///@notice Emitted when an operator is ejected event OperatorEjected(bytes32 operatorId, uint8 quorumNumber); ///@notice Emitted when operators are ejected for a quroum event QuorumEjection(uint32 ejectedOperators, bool ratelimitHit); - /** + /** * @notice Ejects operators from the AVSs registryCoordinator under a ratelimit * @param _operatorIds The ids of the operators to eject for each quorum */ - function ejectOperators(bytes32[][] memory _operatorIds) external; + function ejectOperators( + bytes32[][] memory _operatorIds + ) external; /** * @notice Sets the ratelimit parameters for a quorum * @param _quorumNumber The quorum number to set the ratelimit parameters for * @param _quorumEjectionParams The quorum ratelimit parameters to set for the given quorum */ - function setQuorumEjectionParams(uint8 _quorumNumber, QuorumEjectionParams memory _quorumEjectionParams) external; + function setQuorumEjectionParams( + uint8 _quorumNumber, + QuorumEjectionParams memory _quorumEjectionParams + ) external; /** * @notice Sets the address permissioned to eject operators under a ratelimit @@ -58,5 +64,7 @@ interface IEjectionManager is IEjectionManagerErrors { * @notice Returns the amount of stake that can be ejected for a quorum at the current block.timestamp * @param _quorumNumber The quorum number to view ejectable stake for */ - function amountEjectableForQuorum(uint8 _quorumNumber) external view returns (uint256); + function amountEjectableForQuorum( + uint8 _quorumNumber + ) external view returns (uint256); } diff --git a/src/interfaces/IIndexRegistry.sol b/src/interfaces/IIndexRegistry.sol index df1e0e73..08b963ad 100644 --- a/src/interfaces/IIndexRegistry.sol +++ b/src/interfaces/IIndexRegistry.sol @@ -20,7 +20,9 @@ interface IIndexRegistry is IRegistry, IIndexRegistryErrors { // EVENTS // emitted when an operator's index in the ordered operator list for the quorum with number `quorumNumber` is updated - event QuorumIndexUpdate(bytes32 indexed operatorId, uint8 quorumNumber, uint32 newOperatorIndex); + event QuorumIndexUpdate( + bytes32 indexed operatorId, uint8 quorumNumber, uint32 newOperatorIndex + ); // DATA STRUCTURES @@ -53,7 +55,10 @@ interface IIndexRegistry is IRegistry, IIndexRegistryErrors { * 3) `quorumNumbers` is ordered in ascending order * 4) the operator is not already registered */ - function registerOperator(bytes32 operatorId, bytes calldata quorumNumbers) external returns(uint32[] memory); + function registerOperator( + bytes32 operatorId, + bytes calldata quorumNumbers + ) external returns (uint32[] memory); /** * @notice Deregisters the operator with the specified `operatorId` for the quorums specified by `quorumNumbers`. @@ -73,7 +78,9 @@ interface IIndexRegistry is IRegistry, IIndexRegistryErrors { * @notice Initialize a quorum by pushing its first quorum update * @param quorumNumber The number of the new quorum */ - function initializeQuorum(uint8 quorumNumber) external; + function initializeQuorum( + uint8 quorumNumber + ) external; /// @notice Returns the OperatorUpdate entry for the specified `operatorIndex` and `quorumNumber` at the specified `arrayIndex` function getOperatorUpdateAtIndex( @@ -83,17 +90,30 @@ interface IIndexRegistry is IRegistry, IIndexRegistryErrors { ) external view returns (OperatorUpdate memory); /// @notice Returns the QuorumUpdate entry for the specified `quorumNumber` at the specified `quorumIndex` - function getQuorumUpdateAtIndex(uint8 quorumNumber, uint32 quorumIndex) external view returns (QuorumUpdate memory); + function getQuorumUpdateAtIndex( + uint8 quorumNumber, + uint32 quorumIndex + ) external view returns (QuorumUpdate memory); /// @notice Returns the most recent OperatorUpdate entry for the specified quorumNumber and operatorIndex - function getLatestOperatorUpdate(uint8 quorumNumber, uint32 operatorIndex) external view returns (OperatorUpdate memory); + function getLatestOperatorUpdate( + uint8 quorumNumber, + uint32 operatorIndex + ) external view returns (OperatorUpdate memory); /// @notice Returns the most recent QuorumUpdate entry for the specified quorumNumber - function getLatestQuorumUpdate(uint8 quorumNumber) external view returns (QuorumUpdate memory); + function getLatestQuorumUpdate( + uint8 quorumNumber + ) external view returns (QuorumUpdate memory); /// @notice Returns the current number of operators of this service for `quorumNumber`. - function totalOperatorsForQuorum(uint8 quorumNumber) external view returns (uint32); + function totalOperatorsForQuorum( + uint8 quorumNumber + ) external view returns (uint32); /// @notice Returns an ordered list of operators of the services for the given `quorumNumber` at the given `blockNumber` - function getOperatorListAtBlockNumber(uint8 quorumNumber, uint32 blockNumber) external view returns (bytes32[] memory); + function getOperatorListAtBlockNumber( + uint8 quorumNumber, + uint32 blockNumber + ) external view returns (bytes32[] memory); } diff --git a/src/interfaces/IRegistryCoordinator.sol b/src/interfaces/IRegistryCoordinator.sol index 4ce2e917..3a7fcfd7 100644 --- a/src/interfaces/IRegistryCoordinator.sol +++ b/src/interfaces/IRegistryCoordinator.sol @@ -35,7 +35,8 @@ interface IRegistryCoordinatorErrors { * @title Interface for a contract that coordinates between various registries for an AVS. * @author Layr Labs, Inc. */ -interface IRegistryCoordinator is IRegistryCoordinatorErrors{ + +interface IRegistryCoordinator is IRegistryCoordinatorErrors { // EVENTS /// Emits when an operator is registered @@ -54,8 +55,7 @@ interface IRegistryCoordinator is IRegistryCoordinatorErrors{ event QuorumBlockNumberUpdated(uint8 indexed quorumNumber, uint256 blocknumber); // DATA STRUCTURES - enum OperatorStatus - { + enum OperatorStatus { // default is NEVER_REGISTERED NEVER_REGISTERED, REGISTERED, @@ -91,7 +91,7 @@ interface IRegistryCoordinator is IRegistryCoordinatorErrors{ * `kickBIPsOfOperatorStake` is the basis points of a new operator needs to have of an operator they are trying to kick from the quorum, * and `kickBIPsOfTotalStake` is the basis points of the total stake of the quorum that an operator needs to be below to be kicked. */ - struct OperatorSetParam { + struct OperatorSetParam { uint32 maxOperatorCount; uint16 kickBIPsOfOperatorStake; uint16 kickBIPsOfTotalStake; @@ -107,7 +107,9 @@ interface IRegistryCoordinator is IRegistryCoordinatorErrors{ } /// @notice Returns the operator set params for the given `quorumNumber` - function getOperatorSetParams(uint8 quorumNumber) external view returns (OperatorSetParam memory); + function getOperatorSetParams( + uint8 quorumNumber + ) external view returns (OperatorSetParam memory); /// @notice the Stake registry contract that will keep track of operators' stakes function stakeRegistry() external view returns (IStakeRegistry); /// @notice the BLS Aggregate Pubkey Registry contract that will keep track of operators' BLS aggregate pubkeys per quorum @@ -120,46 +122,67 @@ interface IRegistryCoordinator is IRegistryCoordinatorErrors{ * @param operator is the operator to eject * @param quorumNumbers are the quorum numbers to eject the operator from */ - function ejectOperator( - address operator, - bytes calldata quorumNumbers - ) external; + function ejectOperator(address operator, bytes calldata quorumNumbers) external; /// @notice Returns the number of quorums the registry coordinator has created function quorumCount() external view returns (uint8); /// @notice Returns the operator struct for the given `operator` - function getOperator(address operator) external view returns (OperatorInfo memory); + function getOperator( + address operator + ) external view returns (OperatorInfo memory); /// @notice Returns the operatorId for the given `operator` - function getOperatorId(address operator) external view returns (bytes32); + function getOperatorId( + address operator + ) external view returns (bytes32); /// @notice Returns the operator address for the given `operatorId` - function getOperatorFromId(bytes32 operatorId) external view returns (address operator); + function getOperatorFromId( + bytes32 operatorId + ) external view returns (address operator); /// @notice Returns the status for the given `operator` - function getOperatorStatus(address operator) external view returns (IRegistryCoordinator.OperatorStatus); + function getOperatorStatus( + address operator + ) external view returns (IRegistryCoordinator.OperatorStatus); /// @notice Returns the indices of the quorumBitmaps for the provided `operatorIds` at the given `blockNumber` - function getQuorumBitmapIndicesAtBlockNumber(uint32 blockNumber, bytes32[] memory operatorIds) external view returns (uint32[] memory); + function getQuorumBitmapIndicesAtBlockNumber( + uint32 blockNumber, + bytes32[] memory operatorIds + ) external view returns (uint32[] memory); /** * @notice Returns the quorum bitmap for the given `operatorId` at the given `blockNumber` via the `index` * @dev reverts if `index` is incorrect */ - function getQuorumBitmapAtBlockNumberByIndex(bytes32 operatorId, uint32 blockNumber, uint256 index) external view returns (uint192); + function getQuorumBitmapAtBlockNumberByIndex( + bytes32 operatorId, + uint32 blockNumber, + uint256 index + ) external view returns (uint192); /// @notice Returns the `index`th entry in the operator with `operatorId`'s bitmap history - function getQuorumBitmapUpdateByIndex(bytes32 operatorId, uint256 index) external view returns (QuorumBitmapUpdate memory); + function getQuorumBitmapUpdateByIndex( + bytes32 operatorId, + uint256 index + ) external view returns (QuorumBitmapUpdate memory); /// @notice Returns the current quorum bitmap for the given `operatorId` - function getCurrentQuorumBitmap(bytes32 operatorId) external view returns (uint192); + function getCurrentQuorumBitmap( + bytes32 operatorId + ) external view returns (uint192); /// @notice Returns the length of the quorum bitmap history for the given `operatorId` - function getQuorumBitmapHistoryLength(bytes32 operatorId) external view returns (uint256); + function getQuorumBitmapHistoryLength( + bytes32 operatorId + ) external view returns (uint256); /// @notice Returns the registry at the desired index - function registries(uint256) external view returns (address); + function registries( + uint256 + ) external view returns (address); /// @notice Returns the number of registries function numRegistries() external view returns (uint256); @@ -167,7 +190,9 @@ interface IRegistryCoordinator is IRegistryCoordinatorErrors{ /// @notice Returns whether a quorum is an M2 quorum /// @param quorumNumber The quorum number to check /// @return True if the quorum is an M2 quorum - function isM2Quorum(uint8 quorumNumber) external view returns (bool); + function isM2Quorum( + uint8 quorumNumber + ) external view returns (bool); /// @notice Returns whether the AVS is an operator set AVS /// @return True if the AVS is an operator set AVS @@ -177,10 +202,14 @@ interface IRegistryCoordinator is IRegistryCoordinatorErrors{ * @notice Returns the message hash that an operator must sign to register their BLS public key. * @param operator is the address of the operator registering their BLS public key */ - function pubkeyRegistrationMessageHash(address operator) external view returns (BN254.G1Point memory); + function pubkeyRegistrationMessageHash( + address operator + ) external view returns (BN254.G1Point memory); /// @notice returns the blocknumber the quorum was last updated all at once for all operators - function quorumUpdateBlockNumber(uint8 quorumNumber) external view returns (uint256); + function quorumUpdateBlockNumber( + uint8 quorumNumber + ) external view returns (uint256); /// @notice The owner of the registry coordinator function owner() external view returns (address); diff --git a/src/interfaces/IServiceManager.sol b/src/interfaces/IServiceManager.sol index 5f3ab220..28d9c2db 100644 --- a/src/interfaces/IServiceManager.sol +++ b/src/interfaces/IServiceManager.sol @@ -1,11 +1,14 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity >=0.5.0; -import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import {IRewardsCoordinator} from + "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; import {IServiceManagerUI} from "./IServiceManagerUI.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; -import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManagerTypes} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; @@ -41,18 +44,24 @@ interface IServiceManager is IServiceManagerUI, IServiceManagerErrors { * @dev This function will revert if the `rewardsSubmission` is malformed, * e.g. if the `strategies` and `weights` arrays are of non-equal lengths */ - function createAVSRewardsSubmission(IRewardsCoordinator.RewardsSubmission[] calldata rewardsSubmissions) external; + function createAVSRewardsSubmission( + IRewardsCoordinator.RewardsSubmission[] calldata rewardsSubmissions + ) external; - /******************************************************************************* - PERMISSIONCONTROLLER FUNCTIONS - *******************************************************************************/ + /** + * + * PERMISSIONCONTROLLER FUNCTIONS + * + */ /** * @notice Calls `addPendingAdmin` on the `PermissionController` contract * with `account` being the address of this contract. * @param admin The address of the admin to add * @dev Only callable by the owner of the contract */ - function addPendingAdmin(address admin) external; + function addPendingAdmin( + address admin + ) external; /** * @notice Calls `removePendingAdmin` on the `PermissionController` contract @@ -60,7 +69,9 @@ interface IServiceManager is IServiceManagerUI, IServiceManagerErrors { * @param pendingAdmin The address of the pending admin to remove * @dev Only callable by the owner of the contract */ - function removePendingAdmin(address pendingAdmin) external; + function removePendingAdmin( + address pendingAdmin + ) external; /** * @notice Calls `removeAdmin` on the `PermissionController` contract @@ -68,7 +79,9 @@ interface IServiceManager is IServiceManagerUI, IServiceManagerErrors { * @param admin The address of the admin to remove * @dev Only callable by the owner of the contract */ - function removeAdmin(address admin) external; + function removeAdmin( + address admin + ) external; /** * @notice Calls `setAppointee` on the `PermissionController` contract @@ -78,11 +91,7 @@ interface IServiceManager is IServiceManagerUI, IServiceManagerErrors { * @param selector The function selector to set the appointee for * @dev Only callable by the owner of the contract */ - function setAppointee( - address appointee, - address target, - bytes4 selector - ) external; + function setAppointee(address appointee, address target, bytes4 selector) external; /** * @notice Calls `removeAppointee` on the `PermissionController` contract @@ -92,9 +101,5 @@ interface IServiceManager is IServiceManagerUI, IServiceManagerErrors { * @param selector The function selector to remove the appointee for * @dev Only callable by the owner of the contract */ - function removeAppointee( - address appointee, - address target, - bytes4 selector - ) external; + function removeAppointee(address appointee, address target, bytes4 selector) external; } diff --git a/src/interfaces/IServiceManagerUI.sol b/src/interfaces/IServiceManagerUI.sol index 92cdce9c..558dca85 100644 --- a/src/interfaces/IServiceManagerUI.sol +++ b/src/interfaces/IServiceManagerUI.sol @@ -11,17 +11,19 @@ import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISi interface IServiceManagerUI { /** * Metadata should follow the format outlined by this example. - { - "name": "EigenLabs AVS 1", - "website": "https://www.eigenlayer.xyz/", - "description": "This is my 1st AVS", - "logo": "https://holesky-operator-metadata.s3.amazonaws.com/eigenlayer.png", - "twitter": "https://twitter.com/eigenlayer" - } + * { + * "name": "EigenLabs AVS 1", + * "website": "https://www.eigenlayer.xyz/", + * "description": "This is my 1st AVS", + * "logo": "https://holesky-operator-metadata.s3.amazonaws.com/eigenlayer.png", + * "twitter": "https://twitter.com/eigenlayer" + * } * @notice Updates the metadata URI for the AVS * @param _metadataURI is the metadata URI for the AVS */ - function updateAVSMetadataURI(string memory _metadataURI) external; + function updateAVSMetadataURI( + string memory _metadataURI + ) external; /** * @notice Forwards a call to EigenLayer's AVSDirectory contract to confirm operator registration with the AVS @@ -37,21 +39,25 @@ interface IServiceManagerUI { * @notice Forwards a call to EigenLayer's AVSDirectory contract to confirm operator deregistration from the AVS * @param operator The address of the operator to deregister. */ - function deregisterOperatorFromAVS(address operator) external; + function deregisterOperatorFromAVS( + address operator + ) external; /** * @notice Returns the list of strategies that the operator has potentially restaked on the AVS * @param operator The address of the operator to get restaked strategies for * @dev This function is intended to be called off-chain - * @dev No guarantee is made on whether the operator has shares for a strategy in a quorum or uniqueness + * @dev No guarantee is made on whether the operator has shares for a strategy in a quorum or uniqueness * of each element in the returned array. The off-chain service should do that validation separately */ - function getOperatorRestakedStrategies(address operator) external view returns (address[] memory); + function getOperatorRestakedStrategies( + address operator + ) external view returns (address[] memory); /** * @notice Returns the list of strategies that the AVS supports for restaking * @dev This function is intended to be called off-chain - * @dev No guarantee is made on uniqueness of each element in the returned array. + * @dev No guarantee is made on uniqueness of each element in the returned array. * The off-chain service should do that validation separately */ function getRestakeableStrategies() external view returns (address[] memory); diff --git a/src/interfaces/ISlasher.sol b/src/interfaces/ISlasher.sol index 44222150..b00fd65a 100644 --- a/src/interfaces/ISlasher.sol +++ b/src/interfaces/ISlasher.sol @@ -1,9 +1,9 @@ - // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; -import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; interface ISlasherEvents { event SlashingRequested( @@ -53,7 +53,6 @@ interface ISlasherTypes { uint256 requestTimestamp; SlashingStatus status; } - } interface ISlasher is ISlasherEvents, ISlasherTypes, ISlasherErrors {} diff --git a/src/interfaces/ISocketUpdater.sol b/src/interfaces/ISocketUpdater.sol index dc17ecfa..921b1a46 100644 --- a/src/interfaces/ISocketUpdater.sol +++ b/src/interfaces/ISocketUpdater.sol @@ -16,5 +16,7 @@ interface ISocketUpdater { * @notice Updates the socket of the msg.sender given they are a registered operator * @param socket is the new socket of the operator */ - function updateSocket(string memory socket) external; + function updateSocket( + string memory socket + ) external; } diff --git a/src/interfaces/IStakeRegistry.sol b/src/interfaces/IStakeRegistry.sol index 85417ecc..a9d3d5a3 100644 --- a/src/interfaces/IStakeRegistry.sol +++ b/src/interfaces/IStakeRegistry.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {IDelegationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IRegistry} from "./IRegistry.sol"; @@ -67,11 +68,7 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { // EVENTS /// @notice emitted whenever the stake of `operator` is updated - event OperatorStakeUpdate( - bytes32 indexed operatorId, - uint8 quorumNumber, - uint96 stake - ); + event OperatorStakeUpdate(bytes32 indexed operatorId, uint8 quorumNumber, uint96 stake); /// @notice emitted when the look ahead time(in blocks) for checking operator shares is updated event LookAheadPeriodChanged(uint32 oldLookAheadBlocks, uint32 newLookAheadBlocks); @@ -87,7 +84,9 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { /// @notice emitted when `strategy` has removed from the array at `strategyParams[quorumNumber]` event StrategyRemovedFromQuorum(uint8 indexed quorumNumber, IStrategy strategy); /// @notice emitted when `strategy` has its `multiplier` updated in the array at `strategyParams[quorumNumber]` - event StrategyMultiplierUpdated(uint8 indexed quorumNumber, IStrategy strategy, uint256 multiplier); + event StrategyMultiplierUpdated( + uint8 indexed quorumNumber, IStrategy strategy, uint256 multiplier + ); /** * @notice Registers the `operator` with `operatorId` for the specified `quorumNumbers`. @@ -141,10 +140,7 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { ) external; /// @notice Adds new strategies and the associated multipliers to the @param quorumNumber. - function addStrategies( - uint8 quorumNumber, - StrategyParams[] memory strategyParams - ) external; + function addStrategies(uint8 quorumNumber, StrategyParams[] memory strategyParams) external; /** * @notice This function is used for removing strategies and their associated weights from the @@ -174,10 +170,14 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { function delegation() external view returns (IDelegationManager); /// @notice In order to register for a quorum i, an operator must have at least `minimumStakeForQuorum[i]` - function minimumStakeForQuorum(uint8 quorumNumber) external view returns (uint96); + function minimumStakeForQuorum( + uint8 quorumNumber + ) external view returns (uint96); /// @notice Returns the length of the dynamic array stored in `strategyParams[quorumNumber]`. - function strategyParamsLength(uint8 quorumNumber) external view returns (uint256); + function strategyParamsLength( + uint8 quorumNumber + ) external view returns (uint256); /// @notice Returns the strategy and weight multiplier for the `index`'th strategy in the quorum `quorumNumber` function strategyParamsByIndex( @@ -189,32 +189,47 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { * @notice This function computes the total weight of the @param operator in the quorum @param quorumNumber. * @dev reverts in the case that `quorumNumber` is greater than or equal to `quorumCount` */ - function weightOfOperatorForQuorum(uint8 quorumNumber, address operator) external view returns (uint96); + function weightOfOperatorForQuorum( + uint8 quorumNumber, + address operator + ) external view returns (uint96); /** * @notice Returns the entire `operatorIdToStakeHistory[operatorId][quorumNumber]` array. * @param operatorId The id of the operator of interest. * @param quorumNumber The quorum number to get the stake for. */ - function getStakeHistory(bytes32 operatorId, uint8 quorumNumber) external view returns (StakeUpdate[] memory); + function getStakeHistory( + bytes32 operatorId, + uint8 quorumNumber + ) external view returns (StakeUpdate[] memory); - function getTotalStakeHistoryLength(uint8 quorumNumber) external view returns (uint256); + function getTotalStakeHistoryLength( + uint8 quorumNumber + ) external view returns (uint256); /** * @notice Returns the `index`-th entry in the dynamic array of total stake, `totalStakeHistory` for quorum `quorumNumber`. * @param quorumNumber The quorum number to get the stake for. * @param index Array index for lookup, within the dynamic array `totalStakeHistory[quorumNumber]`. */ - function getTotalStakeUpdateAtIndex(uint8 quorumNumber, uint256 index) external view returns (StakeUpdate memory); + function getTotalStakeUpdateAtIndex( + uint8 quorumNumber, + uint256 index + ) external view returns (StakeUpdate memory); /// @notice Returns the indices of the operator stakes for the provided `quorumNumber` at the given `blockNumber` - function getStakeUpdateIndexAtBlockNumber(bytes32 operatorId, uint8 quorumNumber, uint32 blockNumber) - external - view - returns (uint32); + function getStakeUpdateIndexAtBlockNumber( + bytes32 operatorId, + uint8 quorumNumber, + uint32 blockNumber + ) external view returns (uint32); /// @notice Returns the indices of the total stakes for the provided `quorumNumbers` at the given `blockNumber` - function getTotalStakeIndicesAtBlockNumber(uint32 blockNumber, bytes calldata quorumNumbers) external view returns(uint32[] memory) ; + function getTotalStakeIndicesAtBlockNumber( + uint32 blockNumber, + bytes calldata quorumNumbers + ) external view returns (uint32[] memory); /** * @notice Returns the `index`-th entry in the `operatorIdToStakeHistory[operatorId][quorumNumber]` array. @@ -223,16 +238,20 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { * @param index Array index for lookup, within the dynamic array `operatorIdToStakeHistory[operatorId][quorumNumber]`. * @dev Function will revert if `index` is out-of-bounds. */ - function getStakeUpdateAtIndex(uint8 quorumNumber, bytes32 operatorId, uint256 index) - external - view - returns (StakeUpdate memory); + function getStakeUpdateAtIndex( + uint8 quorumNumber, + bytes32 operatorId, + uint256 index + ) external view returns (StakeUpdate memory); /** * @notice Returns the most recent stake weight for the `operatorId` for a certain quorum * @dev Function returns an StakeUpdate struct with **every entry equal to 0** in the event that the operator has no stake history */ - function getLatestStakeUpdate(bytes32 operatorId, uint8 quorumNumber) external view returns (StakeUpdate memory); + function getLatestStakeUpdate( + bytes32 operatorId, + uint8 quorumNumber + ) external view returns (StakeUpdate memory); /** * @notice Returns the stake weight corresponding to `operatorId` for quorum `quorumNumber`, at the @@ -245,10 +264,12 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { * @dev Function will revert if `index` is out-of-bounds. * @dev used the BLSSignatureChecker to get past stakes of signing operators */ - function getStakeAtBlockNumberAndIndex(uint8 quorumNumber, uint32 blockNumber, bytes32 operatorId, uint256 index) - external - view - returns (uint96); + function getStakeAtBlockNumberAndIndex( + uint8 quorumNumber, + uint32 blockNumber, + bytes32 operatorId, + uint256 index + ) external view returns (uint96); /** * @notice Returns the total stake weight for quorum `quorumNumber`, at the `index`-th entry in the @@ -260,25 +281,35 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { * @dev Function will revert if `index` is out-of-bounds. * @dev used the BLSSignatureChecker to get past stakes of signing operators */ - function getTotalStakeAtBlockNumberFromIndex(uint8 quorumNumber, uint32 blockNumber, uint256 index) external view returns (uint96); + function getTotalStakeAtBlockNumberFromIndex( + uint8 quorumNumber, + uint32 blockNumber, + uint256 index + ) external view returns (uint96); /** * @notice Returns the most recent stake weight for the `operatorId` for quorum `quorumNumber` * @dev Function returns weight of **0** in the event that the operator has no stake history */ - function getCurrentStake(bytes32 operatorId, uint8 quorumNumber) external view returns (uint96); + function getCurrentStake( + bytes32 operatorId, + uint8 quorumNumber + ) external view returns (uint96); /// @notice Returns the stake of the operator for the provided `quorumNumber` at the given `blockNumber` - function getStakeAtBlockNumber(bytes32 operatorId, uint8 quorumNumber, uint32 blockNumber) - external - view - returns (uint96); + function getStakeAtBlockNumber( + bytes32 operatorId, + uint8 quorumNumber, + uint32 blockNumber + ) external view returns (uint96); /** * @notice Returns the stake weight from the latest entry in `_totalStakeHistory` for quorum `quorumNumber`. * @dev Will revert if `_totalStakeHistory[quorumNumber]` is empty. */ - function getCurrentTotalStake(uint8 quorumNumber) external view returns (uint96); + function getCurrentTotalStake( + uint8 quorumNumber + ) external view returns (uint96); /** * @notice Called by the registry coordinator to update an operator's stake for one diff --git a/src/libraries/BN254.sol b/src/libraries/BN254.sol index dcda7a31..7a167efc 100644 --- a/src/libraries/BN254.sol +++ b/src/libraries/BN254.sol @@ -30,10 +30,10 @@ pragma solidity ^0.8.27; library BN254 { // modulus for the underlying field F_p of the elliptic curve uint256 internal constant FP_MODULUS = - 21888242871839275222246405745257275088696311157297823662689037894645226208583; + 21_888_242_871_839_275_222_246_405_745_257_275_088_696_311_157_297_823_662_689_037_894_645_226_208_583; // modulus for the underlying field F_r of the elliptic curve uint256 internal constant FR_MODULUS = - 21888242871839275222246405745257275088548364400416034343698204186575808495617; + 21_888_242_871_839_275_222_246_405_745_257_275_088_548_364_400_416_034_343_698_204_186_575_808_495_617; struct G1Point { uint256 X; @@ -63,10 +63,14 @@ library BN254 { // generator of group G2 /// @dev Generator point in F_q2 is of the form: (x0 + ix1, y0 + iy1). - uint256 internal constant G2x1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634; - uint256 internal constant G2x0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; - uint256 internal constant G2y1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531; - uint256 internal constant G2y0 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; + uint256 internal constant G2x1 = + 11_559_732_032_986_387_107_991_004_021_392_285_783_925_812_861_821_192_530_917_403_151_452_391_805_634; + uint256 internal constant G2x0 = + 10_857_046_999_023_057_135_944_570_762_232_829_481_370_756_359_578_518_086_990_519_993_285_655_852_781; + uint256 internal constant G2y1 = + 4_082_367_875_863_433_681_332_203_403_145_435_568_316_851_327_593_401_208_105_741_076_214_120_093_531; + uint256 internal constant G2y0 = + 8_495_653_923_123_431_417_604_973_247_489_272_438_418_190_587_263_600_148_770_280_649_306_958_101_930; /// @notice returns the G2 generator /// @dev mind the ordering of the 1s and 0s! @@ -79,10 +83,14 @@ library BN254 { // negation of the generator of group G2 /// @dev Generator point in F_q2 is of the form: (x0 + ix1, y0 + iy1). - uint256 internal constant nG2x1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634; - uint256 internal constant nG2x0 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; - uint256 internal constant nG2y1 = 17805874995975841540914202342111839520379459829704422454583296818431106115052; - uint256 internal constant nG2y0 = 13392588948715843804641432497768002650278120570034223513918757245338268106653; + uint256 internal constant nG2x1 = + 11_559_732_032_986_387_107_991_004_021_392_285_783_925_812_861_821_192_530_917_403_151_452_391_805_634; + uint256 internal constant nG2x0 = + 10_857_046_999_023_057_135_944_570_762_232_829_481_370_756_359_578_518_086_990_519_993_285_655_852_781; + uint256 internal constant nG2y1 = + 17_805_874_995_975_841_540_914_202_342_111_839_520_379_459_829_704_422_454_583_296_818_431_106_115_052; + uint256 internal constant nG2y0 = + 13_392_588_948_715_843_804_641_432_497_768_002_650_278_120_570_034_223_513_918_757_245_338_268_106_653; function negGeneratorG2() internal pure returns (G2Point memory) { return G2Point([nG2x1, nG2x0], [nG2y1, nG2y0]); @@ -95,7 +103,9 @@ library BN254 { * @param p Some point in G1. * @return The negation of `p`, i.e. p.plus(p.negate()) should be zero. */ - function negate(G1Point memory p) internal pure returns (G1Point memory) { + function negate( + G1Point memory p + ) internal pure returns (G1Point memory) { // The prime q in the base field F_q for G1 if (p.X == 0 && p.Y == 0) { return G1Point(0, 0); @@ -120,9 +130,7 @@ library BN254 { success := staticcall(sub(gas(), 2000), 6, input, 0x80, r, 0x40) // Use "invalid" to make gas estimation work switch success - case 0 { - invalid() - } + case 0 { invalid() } } require(success, ECAddFailed()); @@ -134,11 +142,14 @@ library BN254 { * @param s the scalar to multiply by * @dev this function is only safe to use if the scalar is 9 bits or less */ - function scalar_mul_tiny(BN254.G1Point memory p, uint16 s) internal view returns (BN254.G1Point memory) { - require(s < 2**9, ScalarTooLarge()); + function scalar_mul_tiny( + BN254.G1Point memory p, + uint16 s + ) internal view returns (BN254.G1Point memory) { + require(s < 2 ** 9, ScalarTooLarge()); // if s is 1 return p - if(s == 1) { + if (s == 1) { return p; } @@ -152,7 +163,7 @@ library BN254 { uint8 i = 0; //loop until we reach the most significant bit - while(s >= m){ + while (s >= m) { unchecked { // if the current bit is 1, add the 2^n*p to the accumulated product if ((s >> i) & 1 == 1) { @@ -187,9 +198,7 @@ library BN254 { success := staticcall(sub(gas(), 2000), 7, input, 0x60, r, 0x40) // Use "invalid" to make gas estimation work switch success - case 0 { - invalid() - } + case 0 { invalid() } } require(success, ECMulFailed()); } @@ -229,9 +238,7 @@ library BN254 { success := staticcall(sub(gas(), 2000), 8, input, mul(12, 0x20), out, 0x20) // Use "invalid" to make gas estimation work switch success - case 0 { - invalid() - } + case 0 { invalid() } } require(success, ECPairingFailed()); @@ -281,7 +288,9 @@ library BN254 { /// @return hashedG1 the keccak256 hash of the G1 Point /// @dev used for BLS signatures - function hashG1Point(BN254.G1Point memory pk) internal pure returns (bytes32 hashedG1) { + function hashG1Point( + BN254.G1Point memory pk + ) internal pure returns (bytes32 hashedG1) { assembly { mstore(0, mload(pk)) mstore(0x20, mload(add(0x20, pk))) @@ -300,7 +309,9 @@ library BN254 { /** * @notice adapted from https://github.com/HarryR/solcrypto/blob/master/contracts/altbn128.sol */ - function hashToG1(bytes32 _x) internal view returns (G1Point memory) { + function hashToG1( + bytes32 _x + ) internal view returns (G1Point memory) { uint256 beta = 0; uint256 y = 0; @@ -310,7 +321,7 @@ library BN254 { (beta, y) = findYFromX(x); // y^2 == beta - if( beta == mulmod(y, y, FP_MODULUS) ) { + if (beta == mulmod(y, y, FP_MODULUS)) { return G1Point(x, y); } @@ -326,21 +337,29 @@ library BN254 { * * Returns: (x^3 + b), y */ - function findYFromX(uint256 x) internal view returns (uint256, uint256) { + function findYFromX( + uint256 x + ) internal view returns (uint256, uint256) { // beta = (x^3 + b) % p uint256 beta = addmod(mulmod(mulmod(x, x, FP_MODULUS), x, FP_MODULUS), 3, FP_MODULUS); // y^2 = x^3 + b // this acts like: y = sqrt(beta) = beta^((p+1) / 4) - uint256 y = expMod(beta, 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52, FP_MODULUS); + uint256 y = expMod( + beta, 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f52, FP_MODULUS + ); return (beta, y); } - function expMod(uint256 _base, uint256 _exponent, uint256 _modulus) internal view returns (uint256 retval) { + function expMod( + uint256 _base, + uint256 _exponent, + uint256 _modulus + ) internal view returns (uint256 retval) { bool success; uint256[1] memory output; - uint[6] memory input; + uint256[6] memory input; input[0] = 0x20; // baseLen = new(big.Int).SetBytes(getData(input, 0, 32)) input[1] = 0x20; // expLen = new(big.Int).SetBytes(getData(input, 32, 32)) input[2] = 0x20; // modLen = new(big.Int).SetBytes(getData(input, 64, 32)) @@ -351,9 +370,7 @@ library BN254 { success := staticcall(sub(gas(), 2000), 5, input, 0xc0, output, 0x20) // Use "invalid" to make gas estimation work switch success - case 0 { - invalid() - } + case 0 { invalid() } } require(success, ExpModFailed()); return output[0]; diff --git a/src/libraries/BitmapUtils.sol b/src/libraries/BitmapUtils.sol index 3930209a..4e4c9373 100644 --- a/src/libraries/BitmapUtils.sol +++ b/src/libraries/BitmapUtils.sol @@ -29,7 +29,9 @@ library BitmapUtils { * @dev This function will eventually revert in the event that the `orderedBytesArray` is not properly ordered (in ascending order). * @dev This function will also revert if the `orderedBytesArray` input contains any duplicate entries (i.e. duplicate bytes). */ - function orderedBytesArrayToBitmap(bytes memory orderedBytesArray) internal pure returns (uint256) { + function orderedBytesArrayToBitmap( + bytes memory orderedBytesArray + ) internal pure returns (uint256) { // sanity-check on input. a too-long input would fail later on due to having duplicate entry(s) require(orderedBytesArray.length <= MAX_BYTE_ARRAY_LENGTH, BytesArrayLengthTooLong()); @@ -65,7 +67,10 @@ library BitmapUtils { * @param bitUpperBound The exclusive largest bit. Each bit must be strictly less than this value. * @dev Reverts if bitmap contains a bit greater than or equal to `bitUpperBound` */ - function orderedBytesArrayToBitmap(bytes memory orderedBytesArray, uint8 bitUpperBound) internal pure returns (uint256) { + function orderedBytesArrayToBitmap( + bytes memory orderedBytesArray, + uint8 bitUpperBound + ) internal pure returns (uint256) { uint256 bitmap = orderedBytesArrayToBitmap(orderedBytesArray); require((1 << bitUpperBound) > bitmap, BitmapValueTooLarge()); @@ -80,7 +85,9 @@ library BitmapUtils { * @dev This function returns 'true' for the edge case of the `bytesArray` having zero length. * It also returns 'false' early for arrays with length in excess of MAX_BYTE_ARRAY_LENGTH (i.e. so long that they cannot be strictly ordered) */ - function isArrayStrictlyAscendingOrdered(bytes calldata bytesArray) internal pure returns (bool) { + function isArrayStrictlyAscendingOrdered( + bytes calldata bytesArray + ) internal pure returns (bool) { // Return early if the array is too long, or has a length of 0 if (bytesArray.length > MAX_BYTE_ARRAY_LENGTH) { return false; @@ -113,7 +120,9 @@ library BitmapUtils { * @return bytesArray The resulting bitmap array of bytes. * @dev Each byte in the input is processed as indicating a single bit to flip in the bitmap */ - function bitmapToBytesArray(uint256 bitmap) internal pure returns (bytes memory /*bytesArray*/) { + function bitmapToBytesArray( + uint256 bitmap + ) internal pure returns (bytes memory /*bytesArray*/ ) { // initialize an empty uint256 to be used as a bitmask inside the loop uint256 bitMask; // allocate only the needed amount of memory @@ -133,14 +142,18 @@ library BitmapUtils { // if the i-th bit is flipped, then add a byte encoding the value 'i' to the `bytesArray` bytesArray[arrayIndex] = bytes1(uint8(i)); // increment the bytesArray slot since we've assigned one more byte of memory - unchecked{ ++arrayIndex; } + unchecked { + ++arrayIndex; + } } } return bytesArray; } /// @return count number of ones in binary representation of `n` - function countNumOnes(uint256 n) internal pure returns (uint16) { + function countNumOnes( + uint256 n + ) internal pure returns (uint16) { uint16 count = 0; while (n > 0) { n &= (n - 1); // Clear the least significant bit (turn off the rightmost set bit). @@ -167,7 +180,9 @@ library BitmapUtils { /** * @notice Returns true if `bitmap` has no set bits */ - function isEmpty(uint256 bitmap) internal pure returns (bool) { + function isEmpty( + uint256 bitmap + ) internal pure returns (bool) { return bitmap == 0; } diff --git a/src/libraries/LibMergeSort.sol b/src/libraries/LibMergeSort.sol index 11eb91b1..e8d05da2 100644 --- a/src/libraries/LibMergeSort.sol +++ b/src/libraries/LibMergeSort.sol @@ -1,9 +1,10 @@ - // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; library LibMergeSort { - function sort(address[] memory array) internal pure returns (address[] memory) { + function sort( + address[] memory array + ) internal pure returns (address[] memory) { if (array.length <= 1) { return array; } @@ -21,7 +22,11 @@ library LibMergeSort { return mergeSortArrays(sort(left), sort(right)); } - function mergeSortArrays(address[] memory left, address[] memory right) internal pure returns (address[] memory) { + + function mergeSortArrays( + address[] memory left, + address[] memory right + ) internal pure returns (address[] memory) { uint256 leftLength = left.length; uint256 rightLength = right.length; address[] memory merged = new address[](leftLength + rightLength); @@ -53,9 +58,10 @@ library LibMergeSort { } // Resize the merged array to remove unused space - assembly { mstore(merged, k) } + assembly { + mstore(merged, k) + } return merged; } - -} \ No newline at end of file +} diff --git a/src/libraries/QuorumBitmapHistoryLib.sol b/src/libraries/QuorumBitmapHistoryLib.sol index 50f6880b..92848aba 100644 --- a/src/libraries/QuorumBitmapHistoryLib.sol +++ b/src/libraries/QuorumBitmapHistoryLib.sol @@ -93,8 +93,7 @@ library QuorumBitmapHistoryLib { * - the next update block number should be either 0 or strictly greater than blockNumber */ require( - blockNumber >= quorumBitmapUpdate.updateBlockNumber, - BitmapUpdateIsAfterBlockNumber() + blockNumber >= quorumBitmapUpdate.updateBlockNumber, BitmapUpdateIsAfterBlockNumber() ); require( quorumBitmapUpdate.nextUpdateBlockNumber == 0 diff --git a/src/slashers/InstantSlasher.sol b/src/slashers/InstantSlasher.sol index 536259ba..5575525a 100644 --- a/src/slashers/InstantSlasher.sol +++ b/src/slashers/InstantSlasher.sol @@ -2,19 +2,21 @@ pragma solidity ^0.8.27; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; -import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IServiceManager} from "../interfaces/IServiceManager.sol"; import {SlasherBase} from "./base/SlasherBase.sol"; contract InstantSlasher is SlasherBase { - constructor( IAllocationManager _allocationManager, IServiceManager _serviceManager, address _slasher ) SlasherBase(_allocationManager, _serviceManager) {} - function initialize(address _slasher) external initializer { + function initialize( + address _slasher + ) external initializer { __SlasherBase_init(_slasher); } @@ -24,4 +26,4 @@ contract InstantSlasher is SlasherBase { uint256 requestId = nextRequestId++; _fulfillSlashingRequest(requestId, _slashingParams); } -} \ No newline at end of file +} diff --git a/src/slashers/VetoableSlasher.sol b/src/slashers/VetoableSlasher.sol index 37cbb3b9..87112d21 100644 --- a/src/slashers/VetoableSlasher.sol +++ b/src/slashers/VetoableSlasher.sol @@ -2,11 +2,11 @@ pragma solidity ^0.8.27; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; -import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {SlasherBase} from "./base/SlasherBase.sol"; import {IServiceManager} from "../interfaces/IServiceManager.sol"; - contract VetoableSlasher is SlasherBase { uint256 public constant VETO_PERIOD = 3 days; address public vetoCommittee; @@ -24,42 +24,47 @@ contract VetoableSlasher is SlasherBase { address _slasher ) SlasherBase(_allocationManager, _serviceManager) {} - function initialize( - address _vetoCommittee, - address _slasher - ) external virtual initializer { + function initialize(address _vetoCommittee, address _slasher) external virtual initializer { __SlasherBase_init(_slasher); vetoCommittee = _vetoCommittee; } - function queueSlashingRequest(IAllocationManager.SlashingParams memory params) external virtual onlySlasher { + function queueSlashingRequest( + IAllocationManager.SlashingParams memory params + ) external virtual onlySlasher { _queueSlashingRequest(params); } - function cancelSlashingRequest(uint256 requestId) external virtual onlyVetoCommittee { + function cancelSlashingRequest( + uint256 requestId + ) external virtual onlyVetoCommittee { require( block.timestamp < slashingRequests[requestId].requestTimestamp + VETO_PERIOD, VetoPeriodPassed() ); - require(slashingRequests[requestId].status == SlashingStatus.Requested, SlashingRequestNotRequested()); + require( + slashingRequests[requestId].status == SlashingStatus.Requested, + SlashingRequestNotRequested() + ); _cancelSlashingRequest(requestId); } - function fulfillSlashingRequest(uint256 requestId) external virtual onlySlasher { + function fulfillSlashingRequest( + uint256 requestId + ) external virtual onlySlasher { SlashingRequest storage request = slashingRequests[requestId]; require(block.timestamp >= request.requestTimestamp + VETO_PERIOD, VetoPeriodNotPassed()); require(request.status == SlashingStatus.Requested, SlashingRequestIsCancelled()); request.status = SlashingStatus.Completed; - _fulfillSlashingRequest( - requestId, - request.params - ); + _fulfillSlashingRequest(requestId, request.params); } - function _queueSlashingRequest(IAllocationManager.SlashingParams memory params) internal virtual { + function _queueSlashingRequest( + IAllocationManager.SlashingParams memory params + ) internal virtual { uint256 requestId = nextRequestId++; slashingRequests[requestId] = SlashingRequest({ params: params, @@ -67,15 +72,21 @@ contract VetoableSlasher is SlasherBase { status: SlashingStatus.Requested }); - emit SlashingRequested(requestId, params.operator, params.operatorSetId, params.wadsToSlash, params.description); + emit SlashingRequested( + requestId, params.operator, params.operatorSetId, params.wadsToSlash, params.description + ); } - function _cancelSlashingRequest(uint256 requestId) internal virtual { + function _cancelSlashingRequest( + uint256 requestId + ) internal virtual { slashingRequests[requestId].status = SlashingStatus.Cancelled; emit SlashingRequestCancelled(requestId); } - function _checkVetoCommittee(address account) internal view virtual { + function _checkVetoCommittee( + address account + ) internal view virtual { require(account == vetoCommittee, OnlyVetoCommittee()); } } diff --git a/src/slashers/base/SlasherBase.sol b/src/slashers/base/SlasherBase.sol index 30a269f6..370e60b1 100644 --- a/src/slashers/base/SlasherBase.sol +++ b/src/slashers/base/SlasherBase.sol @@ -4,11 +4,13 @@ pragma solidity ^0.8.27; import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; import {IServiceManager} from "../../interfaces/IServiceManager.sol"; import {SlasherStorage} from "./SlasherStorage.sol"; -import {IAllocationManagerTypes, IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import { + IAllocationManagerTypes, + IAllocationManager +} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; abstract contract SlasherBase is Initializable, SlasherStorage { - modifier onlySlasher() { _checkSlasher(msg.sender); _; @@ -21,7 +23,9 @@ abstract contract SlasherBase is Initializable, SlasherStorage { _disableInitializers(); } - function __SlasherBase_init(address _slasher) internal onlyInitializing { + function __SlasherBase_init( + address _slasher + ) internal onlyInitializing { slasher = _slasher; } @@ -29,14 +33,19 @@ abstract contract SlasherBase is Initializable, SlasherStorage { uint256 _requestId, IAllocationManager.SlashingParams memory _params ) internal virtual { - allocationManager.slashOperator({ - avs: address(serviceManager), - params: _params - }); - emit OperatorSlashed(_requestId, _params.operator, _params.operatorSetId, _params.wadsToSlash, _params.description); + allocationManager.slashOperator({avs: address(serviceManager), params: _params}); + emit OperatorSlashed( + _requestId, + _params.operator, + _params.operatorSetId, + _params.wadsToSlash, + _params.description + ); } - function _checkSlasher(address account) internal view virtual { + function _checkSlasher( + address account + ) internal view virtual { require(account == slasher, OnlySlasher()); } } diff --git a/src/slashers/base/SlasherStorage.sol b/src/slashers/base/SlasherStorage.sol index 3e5e9860..1b8d0b1b 100644 --- a/src/slashers/base/SlasherStorage.sol +++ b/src/slashers/base/SlasherStorage.sol @@ -1,24 +1,28 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {ISlasher} from "../../interfaces/ISlasher.sol"; import {IServiceManager} from "../../interfaces/IServiceManager.sol"; -contract SlasherStorage is ISlasher { - /******************************************************************************* - CONSTANTS AND IMMUTABLES - *******************************************************************************/ +contract SlasherStorage is ISlasher { + /** + * + * CONSTANTS AND IMMUTABLES + * + */ /// @notice the AllocationManager that tracks OperatorSets and Slashing in EigenLayer IAllocationManager public immutable allocationManager; /// @notice the ServiceManager for this AVS, which forwards calls onto EigenLayer's core contracts IServiceManager public immutable serviceManager; - /******************************************************************************* - STATE - *******************************************************************************/ - + /** + * + * STATE + * + */ address public slasher; uint256 public nextRequestId; @@ -29,4 +33,4 @@ contract SlasherStorage is ISlasher { } uint256[48] private __gap; -} \ No newline at end of file +} diff --git a/src/unaudited/ECDSAServiceManagerBase.sol b/src/unaudited/ECDSAServiceManagerBase.sol index e9fd55a3..a2fa81b6 100644 --- a/src/unaudited/ECDSAServiceManagerBase.sol +++ b/src/unaudited/ECDSAServiceManagerBase.sol @@ -6,21 +6,19 @@ import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISi import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {IServiceManager} from "../interfaces/IServiceManager.sol"; import {IServiceManagerUI} from "../interfaces/IServiceManagerUI.sol"; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {IDelegationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IStakeRegistry} from "../interfaces/IStakeRegistry.sol"; -import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import {IRewardsCoordinator} from + "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; import {Quorum} from "../interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; import {ECDSAStakeRegistry} from "../unaudited/ECDSAStakeRegistry.sol"; import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; -import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; - - -abstract contract ECDSAServiceManagerBase is - IServiceManager, - OwnableUpgradeable -{ +abstract contract ECDSAServiceManagerBase is IServiceManager, OwnableUpgradeable { /// @notice Address of the stake registry contract, which manages registration and stake recording. address public immutable stakeRegistry; @@ -125,12 +123,7 @@ abstract contract ECDSAServiceManagerBase is } /// @inheritdoc IServiceManagerUI - function getRestakeableStrategies() - external - view - virtual - returns (address[] memory) - { + function getRestakeableStrategies() external view virtual returns (address[] memory) { return _getRestakeableStrategies(); } @@ -162,10 +155,7 @@ abstract contract ECDSAServiceManagerBase is address operator, ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature ) internal virtual { - IAVSDirectory(avsDirectory).registerOperatorToAVS( - operator, - operatorSignature - ); + IAVSDirectory(avsDirectory).registerOperatorToAVS(operator, operatorSignature); } /** @@ -173,7 +163,9 @@ abstract contract ECDSAServiceManagerBase is * @dev This internal function is a proxy to the `deregisterOperatorFromAVS` function of the AVSDirectory contract. * @param operator The address of the operator to deregister. */ - function _deregisterOperatorFromAVS(address operator) internal virtual { + function _deregisterOperatorFromAVS( + address operator + ) internal virtual { IAVSDirectory(avsDirectory).deregisterOperatorFromAVS(operator); } @@ -187,17 +179,12 @@ abstract contract ECDSAServiceManagerBase is ) internal virtual { for (uint256 i = 0; i < rewardsSubmissions.length; ++i) { rewardsSubmissions[i].token.transferFrom( - msg.sender, - address(this), - rewardsSubmissions[i].amount - ); - uint256 allowance = rewardsSubmissions[i].token.allowance( - address(this), - rewardsCoordinator + msg.sender, address(this), rewardsSubmissions[i].amount ); + uint256 allowance = + rewardsSubmissions[i].token.allowance(address(this), rewardsCoordinator); rewardsSubmissions[i].token.approve( - rewardsCoordinator, - rewardsSubmissions[i].amount + allowance + rewardsCoordinator, rewardsSubmissions[i].amount + allowance ); } @@ -209,12 +196,7 @@ abstract contract ECDSAServiceManagerBase is * @dev Fetches the quorum configuration from the ECDSAStakeRegistry and extracts the strategy addresses. * @return strategies An array of addresses representing the strategies in the current quorum. */ - function _getRestakeableStrategies() - internal - view - virtual - returns (address[] memory) - { + function _getRestakeableStrategies() internal view virtual returns (address[] memory) { Quorum memory quorum = ECDSAStakeRegistry(stakeRegistry).quorum(); address[] memory strategies = new address[](quorum.strategies.length); for (uint256 i = 0; i < quorum.strategies.length; i++) { @@ -228,7 +210,9 @@ abstract contract ECDSAServiceManagerBase is * @param registrar The new AVS registrar address * @dev Only callable by the registry coordinator */ - function setAVSRegistrar(IAVSRegistrar registrar) external onlyOwner { + function setAVSRegistrar( + IAVSRegistrar registrar + ) external onlyOwner { IAllocationManager(allocationManager).setAVSRegistrar(address(this), registrar); } @@ -284,7 +268,9 @@ abstract contract ECDSAServiceManagerBase is _setRewardsInitiator(newRewardsInitiator); } - function _setRewardsInitiator(address newRewardsInitiator) internal { + function _setRewardsInitiator( + address newRewardsInitiator + ) internal { emit RewardsInitiatorUpdated(rewardsInitiator, newRewardsInitiator); rewardsInitiator = newRewardsInitiator; } diff --git a/src/unaudited/ECDSAStakeRegistry.sol b/src/unaudited/ECDSAStakeRegistry.sol index 0e341067..edbb6778 100644 --- a/src/unaudited/ECDSAStakeRegistry.sol +++ b/src/unaudited/ECDSAStakeRegistry.sol @@ -3,14 +3,18 @@ pragma solidity ^0.8.27; import {ECDSAStakeRegistryStorage, Quorum, StrategyParams} from "./ECDSAStakeRegistryStorage.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {IDelegationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {IServiceManager} from "../interfaces/IServiceManager.sol"; import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; -import {CheckpointsUpgradeable} from "@openzeppelin-upgrades/contracts/utils/CheckpointsUpgradeable.sol"; -import {SignatureCheckerUpgradeable} from "@openzeppelin-upgrades/contracts/utils/cryptography/SignatureCheckerUpgradeable.sol"; -import {IERC1271Upgradeable} from "@openzeppelin-upgrades/contracts/interfaces/IERC1271Upgradeable.sol"; +import {CheckpointsUpgradeable} from + "@openzeppelin-upgrades/contracts/utils/CheckpointsUpgradeable.sol"; +import {SignatureCheckerUpgradeable} from + "@openzeppelin-upgrades/contracts/utils/cryptography/SignatureCheckerUpgradeable.sol"; +import {IERC1271Upgradeable} from + "@openzeppelin-upgrades/contracts/interfaces/IERC1271Upgradeable.sol"; /// @title ECDSA Stake Registry /// @dev THIS CONTRACT IS NOT AUDITED @@ -63,7 +67,9 @@ contract ECDSAStakeRegistry is * @dev Only callable by the operator themselves * @param _newSigningKey The new signing key to set for the operator */ - function updateOperatorSigningKey(address _newSigningKey) external { + function updateOperatorSigningKey( + address _newSigningKey + ) external { if (!_operatorRegistered[msg.sender]) { revert OperatorNotRegistered(); } @@ -75,7 +81,9 @@ contract ECDSAStakeRegistry is * @dev Queries stakes from the Eigenlayer core DelegationManager contract * @param _operators A list of operator addresses to update */ - function updateOperators(address[] memory _operators) external { + function updateOperators( + address[] memory _operators + ) external { _updateOperators(_operators); } @@ -113,7 +121,9 @@ contract ECDSAStakeRegistry is * cumulative weight that must be met or exceeded by the sum of the stakes of the signatories for * a message to be deemed valid. */ - function updateStakeThreshold(uint256 _thresholdWeight) external onlyOwner { + function updateStakeThreshold( + uint256 _thresholdWeight + ) external onlyOwner { _updateStakeThreshold(_thresholdWeight); } @@ -125,11 +135,8 @@ contract ECDSAStakeRegistry is bytes32 _dataHash, bytes memory _signatureData ) external view returns (bytes4) { - ( - address[] memory operators, - bytes[] memory signatures, - uint32 referenceBlock - ) = abi.decode(_signatureData, (address[], bytes[], uint32)); + (address[] memory operators, bytes[] memory signatures, uint32 referenceBlock) = + abi.decode(_signatureData, (address[], bytes[], uint32)); _checkSignatures(_dataHash, operators, signatures, referenceBlock); return IERC1271Upgradeable.isValidSignature.selector; } @@ -161,14 +168,7 @@ contract ECDSAStakeRegistry is address _operator, uint256 _blockNumber ) external view returns (address) { - return - address( - uint160( - _operatorSigningKeyHistory[_operator].getAtBlock( - _blockNumber - ) - ) - ); + return address(uint160(_operatorSigningKeyHistory[_operator].getAtBlock(_blockNumber))); } /// @notice Retrieves the last recorded weight for a given operator. @@ -188,11 +188,7 @@ contract ECDSAStakeRegistry is /// @notice Retrieves the last recorded threshold weight /// @return uint256 - The latest threshold weight. - function getLastCheckpointThresholdWeight() - external - view - returns (uint256) - { + function getLastCheckpointThresholdWeight() external view returns (uint256) { return _thresholdWeightHistory.latest(); } @@ -248,10 +244,7 @@ contract ECDSAStakeRegistry is for (uint256 i; i < strategyParams.length; i++) { strategies[i] = strategyParams[i].strategy; } - uint256[] memory shares = DELEGATION_MANAGER.getOperatorShares( - _operator, - strategies - ); + uint256[] memory shares = DELEGATION_MANAGER.getOperatorShares(_operator, strategies); for (uint256 i; i < strategyParams.length; i++) { weight += shares[i] * strategyParams[i].multiplier; } @@ -290,7 +283,9 @@ contract ECDSAStakeRegistry is /// @dev Updates the list of operators if the provided list has the correct number of operators. /// Reverts if the provided list of operators does not match the expected total count of operators. /// @param _operators The list of operator addresses to update. - function _updateAllOperators(address[] memory _operators) internal { + function _updateAllOperators( + address[] memory _operators + ) internal { if (_operators.length != _totalOperators) { revert MustUpdateAllOperators(); } @@ -300,7 +295,9 @@ contract ECDSAStakeRegistry is /// @dev Updates the weights for a given list of operator addresses. /// When passing an operator that isn't registered, then 0 is added to their history /// @param _operators An array of addresses for which to update the weights. - function _updateOperators(address[] memory _operators) internal { + function _updateOperators( + address[] memory _operators + ) internal { int256 delta; for (uint256 i; i < _operators.length; i++) { delta += _updateOperatorWeight(_operators[i]); @@ -310,14 +307,18 @@ contract ECDSAStakeRegistry is /// @dev Updates the stake threshold weight and records the history. /// @param _thresholdWeight The new threshold weight to set and record in the history. - function _updateStakeThreshold(uint256 _thresholdWeight) internal { + function _updateStakeThreshold( + uint256 _thresholdWeight + ) internal { _thresholdWeightHistory.push(_thresholdWeight); emit ThresholdWeightUpdated(_thresholdWeight); } /// @dev Updates the weight an operator must have to join the operator set /// @param _newMinimumWeight The new weight an operator must have to join the operator set - function _updateMinimumWeight(uint256 _newMinimumWeight) internal { + function _updateMinimumWeight( + uint256 _newMinimumWeight + ) internal { uint256 oldMinimumWeight = _minimumWeight; _minimumWeight = _newMinimumWeight; emit MinimumWeightUpdated(oldMinimumWeight, _newMinimumWeight); @@ -328,7 +329,9 @@ contract ECDSAStakeRegistry is /// Reverts with `InvalidQuorum` if the new quorum configuration is not valid. /// Emits `QuorumUpdated` event with the old and new quorum configurations. /// @param _newQuorum The new quorum configuration to set. - function _updateQuorumConfig(Quorum memory _newQuorum) internal { + function _updateQuorumConfig( + Quorum memory _newQuorum + ) internal { if (!_isValidQuorum(_newQuorum)) { revert InvalidQuorum(); } @@ -342,7 +345,9 @@ contract ECDSAStakeRegistry is /// @dev Internal function to deregister an operator /// @param _operator The operator's address to deregister - function _deregisterOperator(address _operator) internal { + function _deregisterOperator( + address _operator + ) internal { if (!_operatorRegistered[_operator]) { revert OperatorNotRegistered(); } @@ -370,33 +375,20 @@ contract ECDSAStakeRegistry is int256 delta = _updateOperatorWeight(_operator); _updateTotalWeight(delta); _updateOperatorSigningKey(_operator, _signingKey); - IServiceManager(_serviceManager).registerOperatorToAVS( - _operator, - _operatorSignature - ); + IServiceManager(_serviceManager).registerOperatorToAVS(_operator, _operatorSignature); emit OperatorRegistered(_operator, _serviceManager); } /// @dev Internal function to update an operator's signing key /// @param _operator The address of the operator to update the signing key for /// @param _newSigningKey The new signing key to set for the operator - function _updateOperatorSigningKey( - address _operator, - address _newSigningKey - ) internal { - address oldSigningKey = address( - uint160(_operatorSigningKeyHistory[_operator].latest()) - ); + function _updateOperatorSigningKey(address _operator, address _newSigningKey) internal { + address oldSigningKey = address(uint160(_operatorSigningKeyHistory[_operator].latest())); if (_newSigningKey == oldSigningKey) { return; } _operatorSigningKeyHistory[_operator].push(uint160(_newSigningKey)); - emit SigningKeyUpdate( - _operator, - block.number, - _newSigningKey, - oldSigningKey - ); + emit SigningKeyUpdate(_operator, block.number, _newSigningKey, oldSigningKey); } /// @notice Updates the weight of an operator and returns the previous and current weights. @@ -494,10 +486,7 @@ contract ECDSAStakeRegistry is _validateSignature(signer, _dataHash, _signatures[i]); lastOperator = currentOperator; - uint256 operatorWeight = _getOperatorWeight( - currentOperator, - _referenceBlock - ); + uint256 operatorWeight = _getOperatorWeight(currentOperator, _referenceBlock); signedWeight += operatorWeight; } @@ -522,10 +511,7 @@ contract ECDSAStakeRegistry is /// @notice Ensures that signers are sorted in ascending order by address. /// @param _lastSigner The address of the last signer. /// @param _currentSigner The address of the current signer. - function _validateSortedSigners( - address _lastSigner, - address _currentSigner - ) internal pure { + function _validateSortedSigners(address _lastSigner, address _currentSigner) internal pure { if (_lastSigner >= _currentSigner) { revert NotSorted(); } @@ -556,14 +542,7 @@ contract ECDSAStakeRegistry is if (_referenceBlock >= block.number) { revert InvalidReferenceBlock(); } - return - address( - uint160( - _operatorSigningKeyHistory[_operator].getAtBlock( - _referenceBlock - ) - ) - ); + return address(uint160(_operatorSigningKeyHistory[_operator].getAtBlock(_referenceBlock))); } /// @notice Retrieves the operator weight for a signer, either at the last checkpoint or a specified block. @@ -609,10 +588,7 @@ contract ECDSAStakeRegistry is /// @notice Validates that the cumulative stake of signed messages meets or exceeds the required threshold. /// @param _signedWeight The cumulative weight of the signers that have signed the message. /// @param _referenceBlock The block number to verify the stake threshold for - function _validateThresholdStake( - uint256 _signedWeight, - uint32 _referenceBlock - ) internal view { + function _validateThresholdStake(uint256 _signedWeight, uint32 _referenceBlock) internal view { uint256 totalWeight = _getTotalWeight(_referenceBlock); if (_signedWeight > totalWeight) { revert InvalidSignedWeight(); diff --git a/src/unaudited/ECDSAStakeRegistryStorage.sol b/src/unaudited/ECDSAStakeRegistryStorage.sol index 6509f214..a47701e3 100644 --- a/src/unaudited/ECDSAStakeRegistryStorage.sol +++ b/src/unaudited/ECDSAStakeRegistryStorage.sol @@ -1,13 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; -import {CheckpointsUpgradeable} from "@openzeppelin-upgrades/contracts/utils/CheckpointsUpgradeable.sol"; -import {ECDSAStakeRegistryEventsAndErrors, Quorum, StrategyParams} from "../interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; - -abstract contract ECDSAStakeRegistryStorage is - ECDSAStakeRegistryEventsAndErrors -{ +import {IDelegationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {CheckpointsUpgradeable} from + "@openzeppelin-upgrades/contracts/utils/CheckpointsUpgradeable.sol"; +import { + ECDSAStakeRegistryEventsAndErrors, + Quorum, + StrategyParams +} from "../interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; + +abstract contract ECDSAStakeRegistryStorage is ECDSAStakeRegistryEventsAndErrors { /// @notice Manages staking delegations through the DelegationManager interface IDelegationManager internal immutable DELEGATION_MANAGER; @@ -30,8 +34,7 @@ abstract contract ECDSAStakeRegistryStorage is uint256 internal _stakeExpiry; /// @notice Maps an operator to their signing key history using checkpoints - mapping(address => CheckpointsUpgradeable.History) - internal _operatorSigningKeyHistory; + mapping(address => CheckpointsUpgradeable.History) internal _operatorSigningKeyHistory; /// @notice Tracks the total stake history over time using checkpoints CheckpointsUpgradeable.History internal _totalWeightHistory; @@ -40,14 +43,15 @@ abstract contract ECDSAStakeRegistryStorage is CheckpointsUpgradeable.History internal _thresholdWeightHistory; /// @notice Maps operator addresses to their respective stake histories using checkpoints - mapping(address => CheckpointsUpgradeable.History) - internal _operatorWeightHistory; + mapping(address => CheckpointsUpgradeable.History) internal _operatorWeightHistory; /// @notice Maps an operator to their registration status mapping(address => bool) internal _operatorRegistered; /// @param _delegationManager Connects this registry with the DelegationManager - constructor(IDelegationManager _delegationManager) { + constructor( + IDelegationManager _delegationManager + ) { DELEGATION_MANAGER = _delegationManager; } diff --git a/src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol b/src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol index adfd2751..3edd6278 100644 --- a/src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol +++ b/src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol @@ -3,8 +3,10 @@ pragma solidity ^0.8.27; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {ECDSAStakeRegistryPermissioned} from "./ECDSAStakeRegistryPermissioned.sol"; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; -import {CheckpointsUpgradeable} from "@openzeppelin-upgrades/contracts/utils/CheckpointsUpgradeable.sol"; +import {IDelegationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {CheckpointsUpgradeable} from + "@openzeppelin-upgrades/contracts/utils/CheckpointsUpgradeable.sol"; /// @title ECDSA Stake Registry with Equal Weight /// @dev THIS CONTRACT IS NOT AUDITED @@ -25,16 +27,18 @@ contract ECDSAStakeRegistryEqualWeight is ECDSAStakeRegistryPermissioned { /// @dev Overrides the _updateOperatorWeight function from the parent class to implement equal weighting. /// Emits an OperatorWeightUpdated event upon successful update. /// @param _operator The address of the operator whose weight is being updated. - function _updateOperatorWeight(address _operator) internal override returns (int256){ + function _updateOperatorWeight( + address _operator + ) internal override returns (int256) { uint256 oldWeight; uint256 newWeight; int256 delta; if (_operatorRegistered[_operator]) { - (oldWeight, ) = _operatorWeightHistory[_operator].push(1); - delta = int256(1) - int(oldWeight); // handles if they were already registered + (oldWeight,) = _operatorWeightHistory[_operator].push(1); + delta = int256(1) - int256(oldWeight); // handles if they were already registered } else { - (oldWeight, ) = _operatorWeightHistory[_operator].push(0); - delta = int256(0) - int(oldWeight); + (oldWeight,) = _operatorWeightHistory[_operator].push(0); + delta = int256(0) - int256(oldWeight); } emit OperatorWeightUpdated(_operator, oldWeight, newWeight); return delta; diff --git a/src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol b/src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol index ab0bca02..f6afffdf 100644 --- a/src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol +++ b/src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol @@ -3,7 +3,8 @@ pragma solidity ^0.8.27; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {ECDSAStakeRegistry} from "../ECDSAStakeRegistry.sol"; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {IDelegationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; /// @title ECDSA Stake Registry with an Operator Allowlist /// @dev THIS CONTRACT IS NOT AUDITED @@ -36,27 +37,35 @@ contract ECDSAStakeRegistryPermissioned is ECDSAStakeRegistry { /// @notice Adds an operator to the allowlisted operator set /// @dev An allowlisted operator isn't a part of the operator set. They must subsequently register themselves /// @param _operator The address of the operator to be allowlisted - function permitOperator(address _operator) external onlyOwner { + function permitOperator( + address _operator + ) external onlyOwner { _permitOperator(_operator); } /// @notice Revokes an operator's permission and deregisters them /// @dev Emits the OperatorRevoked event if the operator was previously allowlisted. /// @param _operator The address of the operator to remove from the allowlist and deregistered. - function revokeOperator(address _operator) external onlyOwner { + function revokeOperator( + address _operator + ) external onlyOwner { _revokeOperator(_operator); } /// @notice Directly deregisters an operator without removing from the allowlist /// @dev Does not emit an event because it does not modify the allowlist. /// @param _operator The address of the operator to deregister - function ejectOperator(address _operator) external onlyOwner { + function ejectOperator( + address _operator + ) external onlyOwner { _ejectOperator(_operator); } /// @dev Deregisters and operator from the active operator set /// @param _operator The address of the operator to remove. - function _ejectOperator(address _operator) internal { + function _ejectOperator( + address _operator + ) internal { _deregisterOperator(_operator); emit OperatorEjected(_operator); } @@ -64,7 +73,9 @@ contract ECDSAStakeRegistryPermissioned is ECDSAStakeRegistry { /// @dev Adds an operator to the allowlisted operator set /// Doesn't register the operator into the operator set /// @param _operator The address of the operator to allowlist. - function _permitOperator(address _operator) internal { + function _permitOperator( + address _operator + ) internal { if (allowlistedOperators[_operator]) { revert OperatorAlreadyAllowlisted(); } @@ -75,7 +86,9 @@ contract ECDSAStakeRegistryPermissioned is ECDSAStakeRegistry { /// @dev Removes an operator from the allowlist. /// If the operator is registered, also deregisters the operator. /// @param _operator The address of the operator to be revoked. - function _revokeOperator(address _operator) internal { + function _revokeOperator( + address _operator + ) internal { if (!allowlistedOperators[_operator]) { revert OperatorNotAllowlisted(); } @@ -95,10 +108,6 @@ contract ECDSAStakeRegistryPermissioned is ECDSAStakeRegistry { if (allowlistedOperators[_operator] != true) { revert OperatorNotAllowlisted(); } - super._registerOperatorWithSig( - _operator, - _operatorSignature, - _operatorSigningKey - ); + super._registerOperatorWithSig(_operator, _operatorSignature, _operatorSigningKey); } } diff --git a/test/events/IBLSApkRegistryEvents.sol b/test/events/IBLSApkRegistryEvents.sol index 6921203d..4b5e299f 100644 --- a/test/events/IBLSApkRegistryEvents.sol +++ b/test/events/IBLSApkRegistryEvents.sol @@ -6,19 +6,13 @@ import {BN254} from "../../src/libraries/BN254.sol"; interface IBLSApkRegistryEvents { // EVENTS /// @notice Emitted when `operator` registers with the public keys `pubkeyG1` and `pubkeyG2`. - event NewPubkeyRegistration(address indexed operator, BN254.G1Point pubkeyG1, BN254.G2Point pubkeyG2); + event NewPubkeyRegistration( + address indexed operator, BN254.G1Point pubkeyG1, BN254.G2Point pubkeyG2 + ); // @notice Emitted when a new operator pubkey is registered for a set of quorums - event OperatorAddedToQuorums( - address operator, - bytes32 operatorId, - bytes quorumNumbers - ); + event OperatorAddedToQuorums(address operator, bytes32 operatorId, bytes quorumNumbers); // @notice Emitted when an operator pubkey is removed from a set of quorums - event OperatorRemovedFromQuorums( - address operator, - bytes32 operatorId, - bytes quorumNumbers - ); + event OperatorRemovedFromQuorums(address operator, bytes32 operatorId, bytes quorumNumbers); } diff --git a/test/events/IIndexRegistryEvents.sol b/test/events/IIndexRegistryEvents.sol index 21a0f0f2..6e13714b 100644 --- a/test/events/IIndexRegistryEvents.sol +++ b/test/events/IIndexRegistryEvents.sol @@ -3,5 +3,7 @@ pragma solidity ^0.8.27; interface IIndexRegistryEvents { // emitted when an operator's index in the ordered operator list for the quorum with number `quorumNumber` is updated - event QuorumIndexUpdate(bytes32 indexed operatorId, uint8 quorumNumber, uint32 newOperatorIndex); + event QuorumIndexUpdate( + bytes32 indexed operatorId, uint8 quorumNumber, uint32 newOperatorIndex + ); } diff --git a/test/events/IServiceManagerBaseEvents.sol b/test/events/IServiceManagerBaseEvents.sol index 1efb8fa0..45b12cf5 100644 --- a/test/events/IServiceManagerBaseEvents.sol +++ b/test/events/IServiceManagerBaseEvents.sol @@ -26,13 +26,13 @@ interface IServiceManagerBaseEvents { /// @notice rewardsUpdater is responsible for submiting DistributionRoots, only owner can set rewardsUpdater event RewardsUpdaterSet(address indexed oldRewardsUpdater, address indexed newRewardsUpdater); event RewardsForAllSubmitterSet( - address indexed rewardsForAllSubmitter, - bool indexed oldValue, - bool indexed newValue + address indexed rewardsForAllSubmitter, bool indexed oldValue, bool indexed newValue ); event ActivationDelaySet(uint32 oldActivationDelay, uint32 newActivationDelay); event GlobalCommissionBipsSet(uint16 oldGlobalCommissionBips, uint16 newGlobalCommissionBips); - event ClaimerForSet(address indexed earner, address indexed oldClaimer, address indexed claimer); + event ClaimerForSet( + address indexed earner, address indexed oldClaimer, address indexed claimer + ); /// @notice rootIndex is the specific array index of the newly created root in the storage array event DistributionRootSubmitted( uint32 indexed rootIndex, @@ -50,8 +50,6 @@ interface IServiceManagerBaseEvents { uint256 claimedAmount ); - - /// TOKEN EVENTS FOR TESTING /// /** * @dev Emitted when `value` tokens are moved from one account (`from`) to diff --git a/test/events/IStakeRegistryEvents.sol b/test/events/IStakeRegistryEvents.sol index 1b585ceb..81426dfa 100644 --- a/test/events/IStakeRegistryEvents.sol +++ b/test/events/IStakeRegistryEvents.sol @@ -5,11 +5,7 @@ import {IStakeRegistry, IStrategy} from "src/interfaces/IStakeRegistry.sol"; interface IStakeRegistryEvents { /// @notice emitted whenever the stake of `operator` is updated - event OperatorStakeUpdate( - bytes32 indexed operatorId, - uint8 quorumNumber, - uint96 stake - ); + event OperatorStakeUpdate(bytes32 indexed operatorId, uint8 quorumNumber, uint96 stake); /// @notice emitted when the minimum stake for a quorum is updated event MinimumStakeForQuorumUpdated(uint8 indexed quorumNumber, uint96 minimumStake); /// @notice emitted when a new quorum is created @@ -19,5 +15,7 @@ interface IStakeRegistryEvents { /// @notice emitted when `strategy` has removed from the array at `strategyParams[quorumNumber]` event StrategyRemovedFromQuorum(uint8 indexed quorumNumber, IStrategy strategy); /// @notice emitted when `strategy` has its `multiplier` updated in the array at `strategyParams[quorumNumber]` - event StrategyMultiplierUpdated(uint8 indexed quorumNumber, IStrategy strategy, uint256 multiplier); + event StrategyMultiplierUpdated( + uint8 indexed quorumNumber, IStrategy strategy, uint256 multiplier + ); } diff --git a/test/ffi/BLSPubKeyCompendiumFFI.t.sol b/test/ffi/BLSPubKeyCompendiumFFI.t.sol index 4f3906ba..b2c078b2 100644 --- a/test/ffi/BLSPubKeyCompendiumFFI.t.sol +++ b/test/ffi/BLSPubKeyCompendiumFFI.t.sol @@ -23,28 +23,46 @@ contract BLSApkRegistryFFITests is G2Operations { blsApkRegistry = new BLSApkRegistry(registryCoordinator); } - function testRegisterBLSPublicKey(uint256 _privKey) public { + function testRegisterBLSPublicKey( + uint256 _privKey + ) public { cheats.assume(_privKey != 0); _setKeys(_privKey); pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(alice); vm.prank(address(registryCoordinator)); - blsApkRegistry.registerBLSPublicKey(alice, pubkeyRegistrationParams, registryCoordinator.pubkeyRegistrationMessageHash(alice)); + blsApkRegistry.registerBLSPublicKey( + alice, + pubkeyRegistrationParams, + registryCoordinator.pubkeyRegistrationMessageHash(alice) + ); - assertEq(blsApkRegistry.operatorToPubkeyHash(alice), BN254.hashG1Point(pubkeyRegistrationParams.pubkeyG1), - "pubkey hash not stored correctly"); - assertEq(blsApkRegistry.pubkeyHashToOperator(BN254.hashG1Point(pubkeyRegistrationParams.pubkeyG1)), alice, - "operator address not stored correctly"); + assertEq( + blsApkRegistry.operatorToPubkeyHash(alice), + BN254.hashG1Point(pubkeyRegistrationParams.pubkeyG1), + "pubkey hash not stored correctly" + ); + assertEq( + blsApkRegistry.pubkeyHashToOperator( + BN254.hashG1Point(pubkeyRegistrationParams.pubkeyG1) + ), + alice, + "operator address not stored correctly" + ); } - function _setKeys(uint256 _privKey) internal { + function _setKeys( + uint256 _privKey + ) internal { privKey = _privKey; pubkeyRegistrationParams.pubkeyG1 = BN254.generatorG1().scalar_mul(_privKey); pubkeyRegistrationParams.pubkeyG2 = G2Operations.mul(_privKey); } - function _signMessage(address signer) internal view returns(BN254.G1Point memory) { + function _signMessage( + address signer + ) internal view returns (BN254.G1Point memory) { BN254.G1Point memory messageHash = registryCoordinator.pubkeyRegistrationMessageHash(signer); return BN254.scalar_mul(messageHash, privKey); } diff --git a/test/ffi/BLSSignatureCheckerFFI.t.sol b/test/ffi/BLSSignatureCheckerFFI.t.sol index 16c22ebe..55e6c0c4 100644 --- a/test/ffi/BLSSignatureCheckerFFI.t.sol +++ b/test/ffi/BLSSignatureCheckerFFI.t.sol @@ -8,9 +8,7 @@ import {OperatorStateRetriever} from "../../src/OperatorStateRetriever.sol"; import {BN254} from "../../src/libraries/BN254.sol"; import {BitmapUtils} from "../../src/libraries/BitmapUtils.sol"; - contract BLSSignatureCheckerFFITests is MockAVSDeployer, G2Operations { - using BN254 for BN254.G1Point; bytes32 msgHash = keccak256(abi.encodePacked("hello world")); @@ -21,7 +19,7 @@ contract BLSSignatureCheckerFFITests is MockAVSDeployer, G2Operations { BLSSignatureChecker blsSignatureChecker; - function setUp() virtual public { + function setUp() public virtual { _deployMockEigenLayerAndAVS(); blsSignatureChecker = new BLSSignatureChecker(registryCoordinator); @@ -30,24 +28,27 @@ contract BLSSignatureCheckerFFITests is MockAVSDeployer, G2Operations { // this test checks that a valid signature from maxOperatorsToRegister with a random number of nonsigners is checked // correctly on the BLSSignatureChecker contract when all operators are only regsitered for a single quorum and // the signature is only checked for stakes on that quorum - function testBLSSignatureChecker_SingleQuorum_Valid(uint256 pseudoRandomNumber) public { + function testBLSSignatureChecker_SingleQuorum_Valid( + uint256 pseudoRandomNumber + ) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 1); uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + pseudoRandomNumber, numNonSigners, quorumBitmap + ); uint256 gasBefore = gasleft(); ( BLSSignatureChecker.QuorumStakeTotals memory quorumStakeTotals, /* bytes32 signatoryRecordHash */ ) = blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); uint256 gasAfter = gasleft(); emit log_named_uint("gasUsed", gasBefore - gasAfter); @@ -61,32 +62,37 @@ contract BLSSignatureCheckerFFITests is MockAVSDeployer, G2Operations { // this test checks that a valid signature from maxOperatorsToRegister with a random number of nonsigners is checked // correctly on the BLSSignatureChecker contract when all operators are registered for the first 100 quorums // and the signature is only checked for stakes on those quorums - function testBLSSignatureChecker_100Quorums_Valid(uint256 pseudoRandomNumber) public { + function testBLSSignatureChecker_100Quorums_Valid( + uint256 pseudoRandomNumber + ) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 1); // 100 set bits uint256 quorumBitmap = (1 << 100) - 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + pseudoRandomNumber, numNonSigners, quorumBitmap + ); nonSignerStakesAndSignature.sigma = sigma.scalar_mul(quorumNumbers.length); nonSignerStakesAndSignature.apkG2 = oneHundredQuorumApkG2; uint256 gasBefore = gasleft(); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); uint256 gasAfter = gasleft(); emit log_named_uint("gasUsed", gasBefore - gasAfter); } - function _setAggregatePublicKeysAndSignature(uint256 pseudoRandomNumber) internal { - if(pseudoRandomNumber > type(uint256).max / 100) { + function _setAggregatePublicKeysAndSignature( + uint256 pseudoRandomNumber + ) internal { + if (pseudoRandomNumber > type(uint256).max / 100) { pseudoRandomNumber = type(uint256).max / 100; } aggSignerPrivKey = pseudoRandomNumber; @@ -95,29 +101,45 @@ contract BLSSignatureCheckerFFITests is MockAVSDeployer, G2Operations { sigma = BN254.hashToG1(msgHash).scalar_mul(aggSignerPrivKey); } - function _generateSignerAndNonSignerPrivateKeys(uint256 pseudoRandomNumber, uint256 numSigners, uint256 numNonSigners) internal returns (uint256[] memory, uint256[] memory) { + function _generateSignerAndNonSignerPrivateKeys( + uint256 pseudoRandomNumber, + uint256 numSigners, + uint256 numNonSigners + ) internal returns (uint256[] memory, uint256[] memory) { _setAggregatePublicKeysAndSignature(pseudoRandomNumber); uint256[] memory signerPrivateKeys = new uint256[](numSigners); // generate numSigners numbers that add up to aggSignerPrivKey mod BN254.FR_MODULUS uint256 sum = 0; - for (uint i = 0; i < numSigners - 1; i++) { - signerPrivateKeys[i] = uint256(keccak256(abi.encodePacked("signerPrivateKey", pseudoRandomNumber, i))) % BN254.FR_MODULUS; + for (uint256 i = 0; i < numSigners - 1; i++) { + signerPrivateKeys[i] = uint256( + keccak256(abi.encodePacked("signerPrivateKey", pseudoRandomNumber, i)) + ) % BN254.FR_MODULUS; sum = addmod(sum, signerPrivateKeys[i], BN254.FR_MODULUS); } // signer private keys need to add to aggSignerPrivKey - signerPrivateKeys[numSigners - 1] = addmod(aggSignerPrivKey, BN254.FR_MODULUS - sum % BN254.FR_MODULUS, BN254.FR_MODULUS); + signerPrivateKeys[numSigners - 1] = + addmod(aggSignerPrivKey, BN254.FR_MODULUS - sum % BN254.FR_MODULUS, BN254.FR_MODULUS); uint256[] memory nonSignerPrivateKeys = new uint256[](numNonSigners); - for (uint i = 0; i < numNonSigners; i++) { - nonSignerPrivateKeys[i] = uint256(keccak256(abi.encodePacked("nonSignerPrivateKey", pseudoRandomNumber, i))) % BN254.FR_MODULUS; + for (uint256 i = 0; i < numNonSigners; i++) { + nonSignerPrivateKeys[i] = uint256( + keccak256(abi.encodePacked("nonSignerPrivateKey", pseudoRandomNumber, i)) + ) % BN254.FR_MODULUS; } return (signerPrivateKeys, nonSignerPrivateKeys); } - function _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(uint256 pseudoRandomNumber, uint256 numNonSigners, uint256 quorumBitmap) internal returns(uint32, BLSSignatureChecker.NonSignerStakesAndSignature memory) { - (uint256[] memory signerPrivateKeys, uint256[] memory nonSignerPrivateKeys) = _generateSignerAndNonSignerPrivateKeys(pseudoRandomNumber, maxOperatorsToRegister - numNonSigners, numNonSigners); + function _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + uint256 pseudoRandomNumber, + uint256 numNonSigners, + uint256 quorumBitmap + ) internal returns (uint32, BLSSignatureChecker.NonSignerStakesAndSignature memory) { + (uint256[] memory signerPrivateKeys, uint256[] memory nonSignerPrivateKeys) = + _generateSignerAndNonSignerPrivateKeys( + pseudoRandomNumber, maxOperatorsToRegister - numNonSigners, numNonSigners + ); bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); // randomly combine signer and non-signer private keys @@ -132,15 +154,17 @@ contract BLSSignatureCheckerFFITests is MockAVSDeployer, G2Operations { { uint256 signerIndex = 0; uint256 nonSignerIndex = 0; - for (uint i = 0; i < maxOperatorsToRegister; i++) { + for (uint256 i = 0; i < maxOperatorsToRegister; i++) { uint256 randomSeed = uint256(keccak256(abi.encodePacked("privKeyCombination", i))); if (randomSeed % 2 == 0 && signerIndex < signerPrivateKeys.length) { privateKeys[i] = signerPrivateKeys[signerIndex]; signerIndex++; } else if (nonSignerIndex < nonSignerPrivateKeys.length) { privateKeys[i] = nonSignerPrivateKeys[nonSignerIndex]; - nonSignerStakesAndSignature.nonSignerPubkeys[nonSignerIndex] = BN254.generatorG1().scalar_mul(privateKeys[i]); - nonSignerOperatorIds[nonSignerIndex] = nonSignerStakesAndSignature.nonSignerPubkeys[nonSignerIndex].hashG1Point(); + nonSignerStakesAndSignature.nonSignerPubkeys[nonSignerIndex] = + BN254.generatorG1().scalar_mul(privateKeys[i]); + nonSignerOperatorIds[nonSignerIndex] = + nonSignerStakesAndSignature.nonSignerPubkeys[nonSignerIndex].hashG1Point(); nonSignerIndex++; } else { privateKeys[i] = signerPrivateKeys[signerIndex]; @@ -151,36 +175,37 @@ contract BLSSignatureCheckerFFITests is MockAVSDeployer, G2Operations { pubkeys[i] = BN254.generatorG1().scalar_mul(privateKeys[i]); // add the public key to each quorum - for (uint j = 0; j < nonSignerStakesAndSignature.quorumApks.length; j++) { - nonSignerStakesAndSignature.quorumApks[j] = nonSignerStakesAndSignature.quorumApks[j].plus(pubkeys[i]); + for (uint256 j = 0; j < nonSignerStakesAndSignature.quorumApks.length; j++) { + nonSignerStakesAndSignature.quorumApks[j] = + nonSignerStakesAndSignature.quorumApks[j].plus(pubkeys[i]); } } } // register all operators for the first quorum - for (uint i = 0; i < maxOperatorsToRegister; i++) { + for (uint256 i = 0; i < maxOperatorsToRegister; i++) { cheats.roll(registrationBlockNumber + blocksBetweenRegistrations * i); _registerOperatorWithCoordinator(operators[i], quorumBitmap, pubkeys[i], defaultStake); } - uint32 referenceBlockNumber = registrationBlockNumber + blocksBetweenRegistrations * uint32(maxOperatorsToRegister) + 1; + uint32 referenceBlockNumber = registrationBlockNumber + + blocksBetweenRegistrations * uint32(maxOperatorsToRegister) + 1; cheats.roll(referenceBlockNumber + 100); - OperatorStateRetriever.CheckSignaturesIndices memory checkSignaturesIndices = operatorStateRetriever.getCheckSignaturesIndices( - registryCoordinator, - referenceBlockNumber, - quorumNumbers, - nonSignerOperatorIds + OperatorStateRetriever.CheckSignaturesIndices memory checkSignaturesIndices = + operatorStateRetriever.getCheckSignaturesIndices( + registryCoordinator, referenceBlockNumber, quorumNumbers, nonSignerOperatorIds ); - nonSignerStakesAndSignature.nonSignerQuorumBitmapIndices = checkSignaturesIndices.nonSignerQuorumBitmapIndices; + nonSignerStakesAndSignature.nonSignerQuorumBitmapIndices = + checkSignaturesIndices.nonSignerQuorumBitmapIndices; nonSignerStakesAndSignature.apkG2 = aggSignerApkG2; nonSignerStakesAndSignature.sigma = sigma; nonSignerStakesAndSignature.quorumApkIndices = checkSignaturesIndices.quorumApkIndices; nonSignerStakesAndSignature.totalStakeIndices = checkSignaturesIndices.totalStakeIndices; - nonSignerStakesAndSignature.nonSignerStakeIndices = checkSignaturesIndices.nonSignerStakeIndices; + nonSignerStakesAndSignature.nonSignerStakeIndices = + checkSignaturesIndices.nonSignerStakeIndices; return (referenceBlockNumber, nonSignerStakesAndSignature); } - } diff --git a/test/ffi/UpdateOperators.t.sol b/test/ffi/UpdateOperators.t.sol index 64e3ecbc..b7bba5b0 100644 --- a/test/ffi/UpdateOperators.t.sol +++ b/test/ffi/UpdateOperators.t.sol @@ -10,7 +10,1008 @@ contract Integration_AVS_Sync_GasCosts_FFI is IntegrationChecks { using BitmapUtils for *; // Private keys sorted by operatorIds. - uint256[] public privateKeys = [853, 690, 815, 398, 987, 432, 946, 717, 760, 840, 719, 714, 11, 554, 528, 368, 160, 22, 562, 266, 827, 488, 335, 566, 365, 54, 6, 733, 835, 656, 496, 472, 126, 50, 643, 632, 421, 797, 610, 737, 154, 918, 819, 694, 556, 608, 203, 521, 188, 908, 400, 349, 290, 463, 680, 973, 204, 439, 822, 799, 795, 251, 482, 326, 411, 839, 851, 652, 458, 108, 92, 278, 8, 773, 302, 699, 936, 427, 321, 700, 683, 36, 828, 732, 963, 664, 776, 161, 460, 426, 878, 96, 572, 678, 898, 372, 764, 579, 215, 507, 533, 965, 72, 708, 706, 334, 722, 665, 446, 397, 151, 802, 224, 753, 206, 190, 569, 253, 735, 578, 859, 711, 135, 944, 344, 655, 202, 743, 292, 176, 262, 961, 270, 117, 502, 546, 247, 31, 663, 515, 850, 509, 728, 424, 197, 239, 905, 545, 121, 438, 513, 881, 233, 221, 593, 831, 491, 282, 979, 410, 873, 316, 210, 371, 40, 255, 329, 483, 975, 742, 214, 813, 691, 467, 830, 808, 951, 924, 147, 705, 772, 30, 486, 576, 469, 331, 27, 313, 849, 805, 499, 404, 178, 10, 399, 485, 627, 60, 709, 570, 97, 894, 88, 264, 245, 129, 818, 218, 395, 387, 110, 455, 695, 199, 648, 444, 435, 230, 84, 489, 649, 385, 274, 95, 442, 899, 999, 651, 310, 227, 823, 538, 345, 229, 551, 24, 686, 877, 707, 671, 585, 530, 952, 28, 692, 336, 673, 777, 789, 366, 781, 872, 386, 64, 342, 244, 445, 816, 332, 436, 596, 148, 425, 863, 967, 611, 153, 749, 940, 150, 280, 634, 631, 954, 891, 666, 319, 93, 807, 82, 79, 91, 146, 291, 78, 923, 910, 320, 529, 857, 945, 205, 602, 974, 41, 503, 868, 783, 303, 536, 523, 357, 409, 832, 474, 862, 516, 140, 617, 543, 356, 77, 328, 976, 46, 834, 750, 99, 633, 949, 568, 636, 766, 363, 174, 138, 112, 574, 541, 703, 81, 412, 98, 477, 452, 755, 598, 464, 880, 884, 418, 829, 645, 607, 279, 820, 66, 416, 517, 384, 29, 192, 59, 15, 573, 94, 383, 981, 889, 914, 172, 322, 248, 845, 775, 1000, 854, 817, 668, 724, 786, 575, 710, 825, 407, 592, 890, 911, 641, 544, 989, 347, 196, 125, 370, 459, 803, 454, 564, 939, 658, 624, 996, 142, 514, 758, 848, 980, 955, 855, 298, 119, 391, 341, 130, 577, 798, 323, 986, 58, 171, 14, 959, 234, 838, 811, 958, 715, 902, 846, 571, 456, 268, 882, 257, 591, 497, 630, 20, 136, 672, 621, 744, 791, 314, 252, 367, 833, 23, 693, 726, 595, 276, 620, 167, 325, 401, 481, 63, 730, 771, 613, 614, 943, 526, 604, 104, 932, 856, 263, 650, 590, 232, 462, 931, 236, 915, 402, 644, 315, 213, 249, 869, 179, 312, 718, 675, 493, 903, 542, 287, 752, 285, 487, 661, 616, 182, 888, 929, 842, 364, 720, 935, 396, 763, 235, 226, 879, 346, 916, 615, 800, 972, 906, 547, 997, 198, 500, 39, 193, 864, 837, 301, 484, 362, 836, 293, 913, 324, 269, 520, 25, 169, 745, 960, 883, 61, 741, 382, 115, 220, 953, 612, 970, 207, 796, 901, 865, 53, 275, 408, 639, 875, 265, 756, 887, 133, 586, 296, 450, 433, 200, 49, 662, 2, 4, 183, 697, 222, 479, 429, 747, 143, 713, 784, 982, 539, 380, 75, 667, 601, 992, 457, 70, 103, 587, 785, 107, 186, 679, 804, 821, 567, 201, 928, 461, 413, 120, 67, 164, 441, 89, 962, 738, 801, 242, 740, 373, 759, 68, 490, 43, 358, 677, 937, 778, 589, 947, 565, 414, 861, 712, 299, 83, 904, 978, 886, 969, 701, 453, 933, 757, 76, 721, 286, 311, 968, 156, 184, 998, 994, 921, 159, 790, 934, 12, 128, 519, 307, 809, 687, 228, 393, 52, 912, 217, 113, 736, 195, 858, 925, 21, 170, 305, 892, 977, 360, 139, 810, 71, 727, 669, 622, 919, 32, 173, 208, 34, 535, 957, 782, 792, 874, 48, 132, 177, 57, 13, 475, 243, 647, 352, 5, 494, 277, 681, 580, 338, 158, 920, 350, 300, 284, 626, 297, 369, 806, 470, 895, 603, 420, 768, 761, 33, 191, 449, 359, 375, 844, 561, 86, 355, 606, 676, 734, 271, 381, 716, 767, 337, 688, 938, 746, 540, 942, 209, 451, 267, 907, 731, 674, 180, 619, 166, 893, 100, 704, 993, 294, 583, 770, 739, 256, 508, 495, 440, 289, 145, 237, 557, 109, 187, 102, 80, 843, 273, 37, 38, 354, 584, 794, 134, 194, 927, 922, 885, 118, 65, 684, 45, 431, 419, 281, 582, 531, 504, 471, 900, 51, 896, 124, 216, 466, 26, 378, 9, 137, 116, 588, 988, 423, 729, 157, 600, 152, 698, 106, 774, 448, 950, 56, 876, 379, 956, 163, 702, 511, 69, 3, 473, 990, 181, 555, 563, 165, 549, 447, 560, 510, 552, 304, 629, 930, 518, 826, 991, 17, 16, 35, 505, 723, 480, 478, 841, 254, 640, 405, 867, 522, 175, 468, 926, 852, 241, 860, 74, 443, 501, 769, 394, 246, 225, 966, 388, 111, 272, 259, 376, 985, 765, 984, 231, 597, 548, 374, 295, 870, 917, 897, 725, 642, 780, 422, 283, 971, 415, 240, 787, 238, 340, 149, 527, 550, 377, 964, 558, 144, 553, 788, 618, 351, 330, 525, 685, 625, 85, 42, 465, 941, 762, 47, 476, 751, 871, 189, 212, 754, 824, 223, 748, 7, 532, 670, 162, 403, 1, 659, 306, 657, 317, 623, 318, 605, 537, 131, 689, 308, 430, 168, 309, 599, 682, 654, 866, 90, 327, 581, 909, 635, 114, 559, 123, 127, 660, 646, 288, 19, 389, 793, 406, 638, 812, 343, 62, 498, 437, 44, 260, 122, 101, 628, 779, 417, 847, 696, 492, 211, 434, 339, 594, 333, 219, 348, 18, 250, 105, 512, 185, 524, 506, 155, 948, 141, 55, 428, 637, 392, 609, 995, 361, 983, 261, 653, 258, 87, 353, 390, 73, 534, 814]; + uint256[] public privateKeys = [ + 853, + 690, + 815, + 398, + 987, + 432, + 946, + 717, + 760, + 840, + 719, + 714, + 11, + 554, + 528, + 368, + 160, + 22, + 562, + 266, + 827, + 488, + 335, + 566, + 365, + 54, + 6, + 733, + 835, + 656, + 496, + 472, + 126, + 50, + 643, + 632, + 421, + 797, + 610, + 737, + 154, + 918, + 819, + 694, + 556, + 608, + 203, + 521, + 188, + 908, + 400, + 349, + 290, + 463, + 680, + 973, + 204, + 439, + 822, + 799, + 795, + 251, + 482, + 326, + 411, + 839, + 851, + 652, + 458, + 108, + 92, + 278, + 8, + 773, + 302, + 699, + 936, + 427, + 321, + 700, + 683, + 36, + 828, + 732, + 963, + 664, + 776, + 161, + 460, + 426, + 878, + 96, + 572, + 678, + 898, + 372, + 764, + 579, + 215, + 507, + 533, + 965, + 72, + 708, + 706, + 334, + 722, + 665, + 446, + 397, + 151, + 802, + 224, + 753, + 206, + 190, + 569, + 253, + 735, + 578, + 859, + 711, + 135, + 944, + 344, + 655, + 202, + 743, + 292, + 176, + 262, + 961, + 270, + 117, + 502, + 546, + 247, + 31, + 663, + 515, + 850, + 509, + 728, + 424, + 197, + 239, + 905, + 545, + 121, + 438, + 513, + 881, + 233, + 221, + 593, + 831, + 491, + 282, + 979, + 410, + 873, + 316, + 210, + 371, + 40, + 255, + 329, + 483, + 975, + 742, + 214, + 813, + 691, + 467, + 830, + 808, + 951, + 924, + 147, + 705, + 772, + 30, + 486, + 576, + 469, + 331, + 27, + 313, + 849, + 805, + 499, + 404, + 178, + 10, + 399, + 485, + 627, + 60, + 709, + 570, + 97, + 894, + 88, + 264, + 245, + 129, + 818, + 218, + 395, + 387, + 110, + 455, + 695, + 199, + 648, + 444, + 435, + 230, + 84, + 489, + 649, + 385, + 274, + 95, + 442, + 899, + 999, + 651, + 310, + 227, + 823, + 538, + 345, + 229, + 551, + 24, + 686, + 877, + 707, + 671, + 585, + 530, + 952, + 28, + 692, + 336, + 673, + 777, + 789, + 366, + 781, + 872, + 386, + 64, + 342, + 244, + 445, + 816, + 332, + 436, + 596, + 148, + 425, + 863, + 967, + 611, + 153, + 749, + 940, + 150, + 280, + 634, + 631, + 954, + 891, + 666, + 319, + 93, + 807, + 82, + 79, + 91, + 146, + 291, + 78, + 923, + 910, + 320, + 529, + 857, + 945, + 205, + 602, + 974, + 41, + 503, + 868, + 783, + 303, + 536, + 523, + 357, + 409, + 832, + 474, + 862, + 516, + 140, + 617, + 543, + 356, + 77, + 328, + 976, + 46, + 834, + 750, + 99, + 633, + 949, + 568, + 636, + 766, + 363, + 174, + 138, + 112, + 574, + 541, + 703, + 81, + 412, + 98, + 477, + 452, + 755, + 598, + 464, + 880, + 884, + 418, + 829, + 645, + 607, + 279, + 820, + 66, + 416, + 517, + 384, + 29, + 192, + 59, + 15, + 573, + 94, + 383, + 981, + 889, + 914, + 172, + 322, + 248, + 845, + 775, + 1000, + 854, + 817, + 668, + 724, + 786, + 575, + 710, + 825, + 407, + 592, + 890, + 911, + 641, + 544, + 989, + 347, + 196, + 125, + 370, + 459, + 803, + 454, + 564, + 939, + 658, + 624, + 996, + 142, + 514, + 758, + 848, + 980, + 955, + 855, + 298, + 119, + 391, + 341, + 130, + 577, + 798, + 323, + 986, + 58, + 171, + 14, + 959, + 234, + 838, + 811, + 958, + 715, + 902, + 846, + 571, + 456, + 268, + 882, + 257, + 591, + 497, + 630, + 20, + 136, + 672, + 621, + 744, + 791, + 314, + 252, + 367, + 833, + 23, + 693, + 726, + 595, + 276, + 620, + 167, + 325, + 401, + 481, + 63, + 730, + 771, + 613, + 614, + 943, + 526, + 604, + 104, + 932, + 856, + 263, + 650, + 590, + 232, + 462, + 931, + 236, + 915, + 402, + 644, + 315, + 213, + 249, + 869, + 179, + 312, + 718, + 675, + 493, + 903, + 542, + 287, + 752, + 285, + 487, + 661, + 616, + 182, + 888, + 929, + 842, + 364, + 720, + 935, + 396, + 763, + 235, + 226, + 879, + 346, + 916, + 615, + 800, + 972, + 906, + 547, + 997, + 198, + 500, + 39, + 193, + 864, + 837, + 301, + 484, + 362, + 836, + 293, + 913, + 324, + 269, + 520, + 25, + 169, + 745, + 960, + 883, + 61, + 741, + 382, + 115, + 220, + 953, + 612, + 970, + 207, + 796, + 901, + 865, + 53, + 275, + 408, + 639, + 875, + 265, + 756, + 887, + 133, + 586, + 296, + 450, + 433, + 200, + 49, + 662, + 2, + 4, + 183, + 697, + 222, + 479, + 429, + 747, + 143, + 713, + 784, + 982, + 539, + 380, + 75, + 667, + 601, + 992, + 457, + 70, + 103, + 587, + 785, + 107, + 186, + 679, + 804, + 821, + 567, + 201, + 928, + 461, + 413, + 120, + 67, + 164, + 441, + 89, + 962, + 738, + 801, + 242, + 740, + 373, + 759, + 68, + 490, + 43, + 358, + 677, + 937, + 778, + 589, + 947, + 565, + 414, + 861, + 712, + 299, + 83, + 904, + 978, + 886, + 969, + 701, + 453, + 933, + 757, + 76, + 721, + 286, + 311, + 968, + 156, + 184, + 998, + 994, + 921, + 159, + 790, + 934, + 12, + 128, + 519, + 307, + 809, + 687, + 228, + 393, + 52, + 912, + 217, + 113, + 736, + 195, + 858, + 925, + 21, + 170, + 305, + 892, + 977, + 360, + 139, + 810, + 71, + 727, + 669, + 622, + 919, + 32, + 173, + 208, + 34, + 535, + 957, + 782, + 792, + 874, + 48, + 132, + 177, + 57, + 13, + 475, + 243, + 647, + 352, + 5, + 494, + 277, + 681, + 580, + 338, + 158, + 920, + 350, + 300, + 284, + 626, + 297, + 369, + 806, + 470, + 895, + 603, + 420, + 768, + 761, + 33, + 191, + 449, + 359, + 375, + 844, + 561, + 86, + 355, + 606, + 676, + 734, + 271, + 381, + 716, + 767, + 337, + 688, + 938, + 746, + 540, + 942, + 209, + 451, + 267, + 907, + 731, + 674, + 180, + 619, + 166, + 893, + 100, + 704, + 993, + 294, + 583, + 770, + 739, + 256, + 508, + 495, + 440, + 289, + 145, + 237, + 557, + 109, + 187, + 102, + 80, + 843, + 273, + 37, + 38, + 354, + 584, + 794, + 134, + 194, + 927, + 922, + 885, + 118, + 65, + 684, + 45, + 431, + 419, + 281, + 582, + 531, + 504, + 471, + 900, + 51, + 896, + 124, + 216, + 466, + 26, + 378, + 9, + 137, + 116, + 588, + 988, + 423, + 729, + 157, + 600, + 152, + 698, + 106, + 774, + 448, + 950, + 56, + 876, + 379, + 956, + 163, + 702, + 511, + 69, + 3, + 473, + 990, + 181, + 555, + 563, + 165, + 549, + 447, + 560, + 510, + 552, + 304, + 629, + 930, + 518, + 826, + 991, + 17, + 16, + 35, + 505, + 723, + 480, + 478, + 841, + 254, + 640, + 405, + 867, + 522, + 175, + 468, + 926, + 852, + 241, + 860, + 74, + 443, + 501, + 769, + 394, + 246, + 225, + 966, + 388, + 111, + 272, + 259, + 376, + 985, + 765, + 984, + 231, + 597, + 548, + 374, + 295, + 870, + 917, + 897, + 725, + 642, + 780, + 422, + 283, + 971, + 415, + 240, + 787, + 238, + 340, + 149, + 527, + 550, + 377, + 964, + 558, + 144, + 553, + 788, + 618, + 351, + 330, + 525, + 685, + 625, + 85, + 42, + 465, + 941, + 762, + 47, + 476, + 751, + 871, + 189, + 212, + 754, + 824, + 223, + 748, + 7, + 532, + 670, + 162, + 403, + 1, + 659, + 306, + 657, + 317, + 623, + 318, + 605, + 537, + 131, + 689, + 308, + 430, + 168, + 309, + 599, + 682, + 654, + 866, + 90, + 327, + 581, + 909, + 635, + 114, + 559, + 123, + 127, + 660, + 646, + 288, + 19, + 389, + 793, + 406, + 638, + 812, + 343, + 62, + 498, + 437, + 44, + 260, + 122, + 101, + 628, + 779, + 417, + 847, + 696, + 492, + 211, + 434, + 339, + 594, + 333, + 219, + 348, + 18, + 250, + 105, + 512, + 185, + 524, + 506, + 155, + 948, + 141, + 55, + 428, + 637, + 392, + 609, + 995, + 361, + 983, + 261, + 653, + 258, + 87, + 353, + 390, + 73, + 534, + 814 + ]; bytes32[] public operatorIds; address[] public operatorAddresses; @@ -29,31 +1030,19 @@ contract Integration_AVS_Sync_GasCosts_FFI is IntegrationChecks { IBLSApkRegistry.PubkeyRegistrationParams memory pubkey; uint256 privateKey = privateKeys[i]; // G1 - pubkey.pubkeyG1.X = stdJson.readUint( - config_data, - string.concat(".G1x[", vm.toString(i), "]") - ); - pubkey.pubkeyG1.Y = stdJson.readUint( - config_data, - string.concat(".G1y[", vm.toString(i), "]") - ); + pubkey.pubkeyG1.X = + stdJson.readUint(config_data, string.concat(".G1x[", vm.toString(i), "]")); + pubkey.pubkeyG1.Y = + stdJson.readUint(config_data, string.concat(".G1y[", vm.toString(i), "]")); // G2 - pubkey.pubkeyG2.X[1] = stdJson.readUint( - config_data, - string.concat(".G2x1[", vm.toString(i), "]") - ); - pubkey.pubkeyG2.Y[1] = stdJson.readUint( - config_data, - string.concat(".G2y1[", vm.toString(i), "]") - ); - pubkey.pubkeyG2.X[0] = stdJson.readUint( - config_data, - string.concat(".G2x0[", vm.toString(i), "]") - ); - pubkey.pubkeyG2.Y[0] = stdJson.readUint( - config_data, - string.concat(".G2y0[", vm.toString(i), "]") - ); + pubkey.pubkeyG2.X[1] = + stdJson.readUint(config_data, string.concat(".G2x1[", vm.toString(i), "]")); + pubkey.pubkeyG2.Y[1] = + stdJson.readUint(config_data, string.concat(".G2y1[", vm.toString(i), "]")); + pubkey.pubkeyG2.X[0] = + stdJson.readUint(config_data, string.concat(".G2x0[", vm.toString(i), "]")); + pubkey.pubkeyG2.Y[0] = + stdJson.readUint(config_data, string.concat(".G2y0[", vm.toString(i), "]")); privKeys.push(privateKey); pubkeys.push(pubkey); } @@ -146,11 +1135,13 @@ contract Integration_AVS_Sync_GasCosts_FFI is IntegrationChecks { console.log("Gas used for updateOperatorsForQuorum: ", gasBefore - gasAfter); } - function _sortArray(address[] memory arr) internal pure returns (address[] memory) { + function _sortArray( + address[] memory arr + ) internal pure returns (address[] memory) { uint256 l = arr.length; - for(uint i = 0; i < l; i++) { - for(uint j = i+1; j < l ;j++) { - if(arr[i] > arr[j]) { + for (uint256 i = 0; i < l; i++) { + for (uint256 j = i + 1; j < l; j++) { + if (arr[i] > arr[j]) { address temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; diff --git a/test/ffi/util/G2Operations.sol b/test/ffi/util/G2Operations.sol index 016011da..52127f9a 100644 --- a/test/ffi/util/G2Operations.sol +++ b/test/ffi/util/G2Operations.sol @@ -8,7 +8,9 @@ import "../../../src/libraries/BN254.sol"; contract G2Operations is Test { using Strings for uint256; - function mul(uint256 x) public returns (BN254.G2Point memory g2Point) { + function mul( + uint256 x + ) public returns (BN254.G2Point memory g2Point) { string[] memory inputs = new string[](5); inputs[0] = "go"; inputs[1] = "run"; @@ -31,5 +33,4 @@ contract G2Operations is Test { res = vm.ffi(inputs); g2Point.Y[0] = abi.decode(res, (uint256)); } - } diff --git a/test/harnesses/AVSDirectoryHarness.sol b/test/harnesses/AVSDirectoryHarness.sol index 995f62a6..d452da82 100644 --- a/test/harnesses/AVSDirectoryHarness.sol +++ b/test/harnesses/AVSDirectoryHarness.sol @@ -8,5 +8,5 @@ import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPa // wrapper around the AVSDirectory contract that exposes internal functionality, for unit testing contract AVSDirectoryHarness is AVSDirectory { - constructor(IDelegationManager _dm, IPauserRegistry _pauser)AVSDirectory(_dm, _pauser){} -} \ No newline at end of file + constructor(IDelegationManager _dm, IPauserRegistry _pauser) AVSDirectory(_dm, _pauser) {} +} diff --git a/test/harnesses/BLSApkRegistryHarness.sol b/test/harnesses/BLSApkRegistryHarness.sol index 7cc8ec60..1ee7df30 100644 --- a/test/harnesses/BLSApkRegistryHarness.sol +++ b/test/harnesses/BLSApkRegistryHarness.sol @@ -5,13 +5,11 @@ import "../../src/BLSApkRegistry.sol"; // wrapper around the BLSApkRegistry contract that exposes internal functionality, for unit testing _other functionality_. contract BLSApkRegistryHarness is BLSApkRegistry { - constructor( IRegistryCoordinator _registryCoordinator ) BLSApkRegistry(_registryCoordinator) {} function setBLSPublicKey(address account, BN254.G1Point memory pk) external { - bytes32 pubkeyHash = BN254.hashG1Point(pk); // store updates operatorToPubkeyHash[account] = pubkeyHash; diff --git a/test/harnesses/BitmapUtilsWrapper.sol b/test/harnesses/BitmapUtilsWrapper.sol index 95322d21..982d2e1a 100644 --- a/test/harnesses/BitmapUtilsWrapper.sol +++ b/test/harnesses/BitmapUtilsWrapper.sol @@ -5,19 +5,27 @@ import "../../src/libraries/BitmapUtils.sol"; // wrapper around the BitmapUtils library that exposes the internal functions contract BitmapUtilsWrapper { - function orderedBytesArrayToBitmap(bytes calldata orderedBytesArray) external pure returns (uint256) { + function orderedBytesArrayToBitmap( + bytes calldata orderedBytesArray + ) external pure returns (uint256) { return BitmapUtils.orderedBytesArrayToBitmap(orderedBytesArray); } - function isArrayStrictlyAscendingOrdered(bytes calldata bytesArray) external pure returns (bool) { + function isArrayStrictlyAscendingOrdered( + bytes calldata bytesArray + ) external pure returns (bool) { return BitmapUtils.isArrayStrictlyAscendingOrdered(bytesArray); } - function bitmapToBytesArray(uint256 bitmap) external pure returns (bytes memory bytesArray) { + function bitmapToBytesArray( + uint256 bitmap + ) external pure returns (bytes memory bytesArray) { return BitmapUtils.bitmapToBytesArray(bitmap); } - function countNumOnes(uint256 n) external pure returns (uint16) { + function countNumOnes( + uint256 n + ) external pure returns (uint16) { return BitmapUtils.countNumOnes(n); } @@ -29,7 +37,9 @@ contract BitmapUtilsWrapper { return BitmapUtils.setBit(bitmap, bit); } - function isEmpty(uint256 bitmap) external pure returns (bool) { + function isEmpty( + uint256 bitmap + ) external pure returns (bool) { return BitmapUtils.isEmpty(bitmap); } diff --git a/test/harnesses/RegistryCoordinatorHarness.t.sol b/test/harnesses/RegistryCoordinatorHarness.t.sol index c1006682..c6b6cb3b 100644 --- a/test/harnesses/RegistryCoordinatorHarness.t.sol +++ b/test/harnesses/RegistryCoordinatorHarness.t.sol @@ -14,11 +14,22 @@ contract RegistryCoordinatorHarness is RegistryCoordinator, Test { IIndexRegistry _indexRegistry, IAllocationManager _allocationManager, IPauserRegistry _pauserRegistry - ) RegistryCoordinator(_serviceManager, _stakeRegistry, _blsApkRegistry, _indexRegistry, _allocationManager, _pauserRegistry) { + ) + RegistryCoordinator( + _serviceManager, + _stakeRegistry, + _blsApkRegistry, + _indexRegistry, + _allocationManager, + _pauserRegistry + ) + { _transferOwnership(msg.sender); } - function setQuorumCount(uint8 count) external { + function setQuorumCount( + uint8 count + ) external { quorumCount = count; } @@ -38,10 +49,7 @@ contract RegistryCoordinatorHarness is RegistryCoordinator, Test { } // @notice exposes the internal `_deregisterOperator` function, overriding all access controls - function _deregisterOperatorExternal( - address operator, - bytes calldata quorumNumbers - ) external { + function _deregisterOperatorExternal(address operator, bytes calldata quorumNumbers) external { _deregisterOperator(operator, quorumNumbers); } diff --git a/test/harnesses/StakeRegistryHarness.sol b/test/harnesses/StakeRegistryHarness.sol index 38ee15e8..4e156aac 100644 --- a/test/harnesses/StakeRegistryHarness.sol +++ b/test/harnesses/StakeRegistryHarness.sol @@ -11,10 +11,21 @@ contract StakeRegistryHarness is StakeRegistry { IAVSDirectory _avsDirectory, IAllocationManager _allocationManager, IServiceManager _serviceManager - ) StakeRegistry(_registryCoordinator, _delegationManager, _avsDirectory, _allocationManager, _serviceManager) { - } + ) + StakeRegistry( + _registryCoordinator, + _delegationManager, + _avsDirectory, + _allocationManager, + _serviceManager + ) + {} - function recordOperatorStakeUpdate(bytes32 operatorId, uint8 quorumNumber, uint96 newStake) external returns(int256) { + function recordOperatorStakeUpdate( + bytes32 operatorId, + uint8 quorumNumber, + uint96 newStake + ) external returns (int256) { return _recordOperatorStakeUpdate(operatorId, quorumNumber, newStake); } diff --git a/test/integration/CoreRegistration.t.sol b/test/integration/CoreRegistration.t.sol index 68f586a9..6599af9c 100644 --- a/test/integration/CoreRegistration.t.sol +++ b/test/integration/CoreRegistration.t.sol @@ -2,14 +2,22 @@ pragma solidity ^0.8.27; import "../utils/MockAVSDeployer.sol"; -import { AVSDirectory } from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; -import { IAVSDirectory, IAVSDirectoryTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; -import { IStrategyManager } from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; -import { DelegationManager } from "eigenlayer-contracts/src/contracts/core/DelegationManager.sol"; -import { IDelegationManager, IDelegationManagerTypes } from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; -import { RewardsCoordinator } from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; -import { IRewardsCoordinator } from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; -import { PermissionController } from "eigenlayer-contracts/src/contracts/permissions/PermissionController.sol"; +import {AVSDirectory} from "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; +import { + IAVSDirectory, + IAVSDirectoryTypes +} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; +import {DelegationManager} from "eigenlayer-contracts/src/contracts/core/DelegationManager.sol"; +import { + IDelegationManager, + IDelegationManagerTypes +} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {RewardsCoordinator} from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; +import {IRewardsCoordinator} from + "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import {PermissionController} from + "eigenlayer-contracts/src/contracts/permissions/PermissionController.sol"; contract Test_CoreRegistration is MockAVSDeployer { // Contracts @@ -49,7 +57,7 @@ contract Test_CoreRegistration is MockAVSDeployer { address(this), pauserRegistry, 0, // 0 is initialPausedStatus - 50400, // Initial withdrawal delay blocks + 50_400, // Initial withdrawal delay blocks initializeStrategiesToSetDelayBlocks, initializeWithdrawalDelayBlocks ) @@ -58,7 +66,8 @@ contract Test_CoreRegistration is MockAVSDeployer { ); // Deploy New AVS Directory - AVSDirectory avsDirectoryImplementation = new AVSDirectory(delegationManager, pauserRegistry); // TODO: Fix Config + AVSDirectory avsDirectoryImplementation = + new AVSDirectory(delegationManager, pauserRegistry); // TODO: Fix Config avsDirectory = AVSDirectory( address( new TransparentUpgradeableProxy( @@ -122,7 +131,7 @@ contract Test_CoreRegistration is MockAVSDeployer { // Set operator weight in single quorum bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(MAX_QUORUM_BITMAP); - for (uint i = 0; i < quorumNumbers.length; i++) { + for (uint256 i = 0; i < quorumNumbers.length; i++) { _setOperatorWeight(operator, uint8(quorumNumbers[i]), defaultStake); } } @@ -132,11 +141,7 @@ contract Test_CoreRegistration is MockAVSDeployer { // Get operator signature ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature = _getOperatorSignature( - operatorPrivateKey, - operator, - address(serviceManager), - emptySalt, - maxExpiry + operatorPrivateKey, operator, address(serviceManager), emptySalt, maxExpiry ); // set operator as registered in Eigenlayer @@ -144,11 +149,17 @@ contract Test_CoreRegistration is MockAVSDeployer { // Register operator cheats.prank(operator); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, operatorSignature); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, operatorSignature + ); // Check operator is registered - IAVSDirectoryTypes.OperatorAVSRegistrationStatus operatorStatus = avsDirectory.avsOperatorStatus(address(serviceManager), operator); - assertEq(uint8(operatorStatus), uint8(IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED)); + IAVSDirectoryTypes.OperatorAVSRegistrationStatus operatorStatus = + avsDirectory.avsOperatorStatus(address(serviceManager), operator); + assertEq( + uint8(operatorStatus), + uint8(IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED) + ); } function test_deregisterOperator_coreStateChanges() public { @@ -161,8 +172,12 @@ contract Test_CoreRegistration is MockAVSDeployer { registryCoordinator.deregisterOperator(quorumNumbers); // Check operator is deregistered - IAVSDirectoryTypes.OperatorAVSRegistrationStatus operatorStatus = avsDirectory.avsOperatorStatus(address(serviceManager), operator); - assertEq(uint8(operatorStatus), uint8(IAVSDirectoryTypes.OperatorAVSRegistrationStatus.UNREGISTERED)); + IAVSDirectoryTypes.OperatorAVSRegistrationStatus operatorStatus = + avsDirectory.avsOperatorStatus(address(serviceManager), operator); + assertEq( + uint8(operatorStatus), + uint8(IAVSDirectoryTypes.OperatorAVSRegistrationStatus.UNREGISTERED) + ); } function test_deregisterOperator_notGloballyDeregistered() public { @@ -177,8 +192,12 @@ contract Test_CoreRegistration is MockAVSDeployer { registryCoordinator.deregisterOperator(quorumNumbers); // Check operator is still registered - IAVSDirectoryTypes.OperatorAVSRegistrationStatus operatorStatus = avsDirectory.avsOperatorStatus(address(serviceManager), operator); - assertEq(uint8(operatorStatus), uint8(IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED)); + IAVSDirectoryTypes.OperatorAVSRegistrationStatus operatorStatus = + avsDirectory.avsOperatorStatus(address(serviceManager), operator); + assertEq( + uint8(operatorStatus), + uint8(IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED) + ); } function test_setMetadataURI_fail_notServiceManagerOwner() public { @@ -199,14 +218,12 @@ contract Test_CoreRegistration is MockAVSDeployer { } // Utils - function _registerOperator(bytes memory quorumNumbers) internal { + function _registerOperator( + bytes memory quorumNumbers + ) internal { // Get operator signature ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature = _getOperatorSignature( - operatorPrivateKey, - operator, - address(serviceManager), - emptySalt, - maxExpiry + operatorPrivateKey, operator, address(serviceManager), emptySalt, maxExpiry ); // set operator as registered in Eigenlayer @@ -214,7 +231,9 @@ contract Test_CoreRegistration is MockAVSDeployer { // Register operator cheats.prank(operator); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, operatorSignature); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, operatorSignature + ); } function _getOperatorSignature( @@ -227,11 +246,12 @@ contract Test_CoreRegistration is MockAVSDeployer { operatorSignature.salt = salt; operatorSignature.expiry = expiry; { - bytes32 digestHash = avsDirectory.calculateOperatorAVSRegistrationDigestHash(operatorToSign, avs, salt, expiry); + bytes32 digestHash = avsDirectory.calculateOperatorAVSRegistrationDigestHash( + operatorToSign, avs, salt, expiry + ); (uint8 v, bytes32 r, bytes32 s) = cheats.sign(_operatorPrivateKey, digestHash); operatorSignature.signature = abi.encodePacked(r, s, v); } return operatorSignature; } - } diff --git a/test/integration/IntegrationBase.t.sol b/test/integration/IntegrationBase.t.sol index 0baf32b4..15371667 100644 --- a/test/integration/IntegrationBase.t.sol +++ b/test/integration/IntegrationBase.t.sol @@ -14,7 +14,6 @@ import "test/integration/TimeMachine.t.sol"; import "test/integration/User.t.sol"; abstract contract IntegrationBase is IntegrationConfig { - using Strings for *; using BitmapUtils for *; using BN254 for *; @@ -37,13 +36,15 @@ abstract contract IntegrationBase is IntegrationConfig { } function assert_HasRegisteredStatus(User user, string memory err) internal { - IRegistryCoordinator.OperatorStatus status = registryCoordinator.getOperatorStatus(address(user)); + IRegistryCoordinator.OperatorStatus status = + registryCoordinator.getOperatorStatus(address(user)); assertTrue(status == IRegistryCoordinator.OperatorStatus.REGISTERED, err); } function assert_HasDeregisteredStatus(User user, string memory err) internal { - IRegistryCoordinator.OperatorStatus status = registryCoordinator.getOperatorStatus(address(user)); + IRegistryCoordinator.OperatorStatus status = + registryCoordinator.getOperatorStatus(address(user)); assertTrue(status == IRegistryCoordinator.OperatorStatus.DEREGISTERED, err); } @@ -54,10 +55,14 @@ abstract contract IntegrationBase is IntegrationConfig { assertTrue(bitmap == 0, err); } - function assert_NotRegisteredForQuorums(User user, bytes memory quorums, string memory err) internal { + function assert_NotRegisteredForQuorums( + User user, + bytes memory quorums, + string memory err + ) internal { uint192 bitmap = registryCoordinator.getCurrentQuorumBitmap(user.operatorId()); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { uint8 quorum = uint8(quorums[i]); assertFalse(bitmap.isSet(quorum), err); @@ -65,7 +70,11 @@ abstract contract IntegrationBase is IntegrationConfig { } /// @dev Checks that the user's current bitmap includes ALL of these quorums - function assert_IsRegisteredForQuorums(User user, bytes memory quorums, string memory err) internal { + function assert_IsRegisteredForQuorums( + User user, + bytes memory quorums, + string memory err + ) internal { uint192 currentBitmap = registryCoordinator.getCurrentQuorumBitmap(user.operatorId()); uint192 subsetBitmap = uint192(quorums.orderedBytesArrayToBitmap()); @@ -75,7 +84,7 @@ abstract contract IntegrationBase is IntegrationConfig { /// @dev Checks whether each of the quorums has been initialized in the RegistryCoordinator function assert_QuorumsExist(bytes memory quorums, string memory err) internal { uint8 count = registryCoordinator.quorumCount(); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { uint8 quorum = uint8(quorums[i]); assertTrue(quorum < count, err); @@ -85,7 +94,7 @@ abstract contract IntegrationBase is IntegrationConfig { /// BLSApkRegistry: function assert_NoRegisteredPubkey(User user, string memory err) internal { - (uint pubkeyX, uint pubkeyY) = blsApkRegistry.operatorToPubkey(address(user)); + (uint256 pubkeyX, uint256 pubkeyY) = blsApkRegistry.operatorToPubkey(address(user)); bytes32 pubkeyHash = blsApkRegistry.operatorToPubkeyHash(address(user)); assertEq(pubkeyX, 0, err); @@ -95,7 +104,7 @@ abstract contract IntegrationBase is IntegrationConfig { function assert_HasRegisteredPubkey(User user, string memory err) internal { BN254.G1Point memory expectedPubkey = user.pubkeyG1(); - (uint actualPkX, uint actualPkY) = blsApkRegistry.operatorToPubkey(address(user)); + (uint256 actualPkX, uint256 actualPkY) = blsApkRegistry.operatorToPubkey(address(user)); bytes32 expectedHash = expectedPubkey.hashG1Point(); bytes32 actualHash = blsApkRegistry.operatorToPubkeyHash(address(user)); @@ -113,7 +122,7 @@ abstract contract IntegrationBase is IntegrationConfig { function assert_NoExistingStake(User user, bytes memory quorums, string memory err) internal { bytes32 operatorId = user.operatorId(); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { uint8 quorum = uint8(quorums[i]); uint96 curStake = stakeRegistry.getCurrentStake(operatorId, quorum); @@ -123,8 +132,12 @@ abstract contract IntegrationBase is IntegrationConfig { } /// @dev Checks that the user meets the minimum weight required for each quorum - function assert_MeetsMinimumWeight(User user, bytes memory quorums, string memory err) internal { - for (uint i = 0; i < quorums.length; i++) { + function assert_MeetsMinimumWeight( + User user, + bytes memory quorums, + string memory err + ) internal { + for (uint256 i = 0; i < quorums.length; i++) { uint8 quorum = uint8(quorums[i]); uint96 minimum = stakeRegistry.minimumStakeForQuorum(quorum); @@ -135,10 +148,14 @@ abstract contract IntegrationBase is IntegrationConfig { } /// @dev Checks that the user meets the minimum stake required for each quorum - function assert_HasAtLeastMinimumStake(User user, bytes memory quorums, string memory err) internal { + function assert_HasAtLeastMinimumStake( + User user, + bytes memory quorums, + string memory err + ) internal { bytes32 operatorId = user.operatorId(); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { uint8 quorum = uint8(quorums[i]); uint96 minimum = stakeRegistry.minimumStakeForQuorum(quorum); @@ -153,10 +170,11 @@ abstract contract IntegrationBase is IntegrationConfig { /// @dev Checks that we're specifically UNDER the max operator count, i.e. we are allowing /// at least one more operator to register function assert_BelowMaxOperators(bytes memory quorums, string memory err) internal { - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { uint8 quorum = uint8(quorums[i]); - uint32 maxOperatorCount = registryCoordinator.getOperatorSetParams(quorum).maxOperatorCount; + uint32 maxOperatorCount = + registryCoordinator.getOperatorSetParams(quorum).maxOperatorCount; uint32 curOperatorCount = indexRegistry.totalOperatorsForQuorum(quorum); assertTrue(curOperatorCount < maxOperatorCount, err); @@ -166,27 +184,35 @@ abstract contract IntegrationBase is IntegrationConfig { /// AVSDirectory: function assert_NotRegisteredToAVS(User operator, string memory err) internal { - IAVSDirectoryTypes.OperatorAVSRegistrationStatus status = avsDirectory.avsOperatorStatus(address(serviceManager), address(operator)); + IAVSDirectoryTypes.OperatorAVSRegistrationStatus status = + avsDirectory.avsOperatorStatus(address(serviceManager), address(operator)); assertTrue(status == IAVSDirectoryTypes.OperatorAVSRegistrationStatus.UNREGISTERED, err); } function assert_IsRegisteredToAVS(User operator, string memory err) internal { - IAVSDirectory.OperatorAVSRegistrationStatus status = avsDirectory.avsOperatorStatus(address(serviceManager), address(operator)); + IAVSDirectory.OperatorAVSRegistrationStatus status = + avsDirectory.avsOperatorStatus(address(serviceManager), address(operator)); assertTrue(status == IAVSDirectoryTypes.OperatorAVSRegistrationStatus.REGISTERED, err); } - /******************************************************************************* - SNAPSHOT ASSERTIONS (MIDDLEWARE) - TIME TRAVELERS ONLY BEYOND THIS POINT - *******************************************************************************/ + /** + * + * SNAPSHOT ASSERTIONS (MIDDLEWARE) + * TIME TRAVELERS ONLY BEYOND THIS POINT + * + */ /// @dev Checks that `quorums` were added to the user's registered quorums /// NOTE: This means curBitmap - prevBitmap = quorums - function assert_Snap_Registered_ForQuorums(User user, bytes memory quorums, string memory err) internal { + function assert_Snap_Registered_ForQuorums( + User user, + bytes memory quorums, + string memory err + ) internal { bytes32 operatorId = user.operatorId(); - uint quorumsAdded = quorums.orderedBytesArrayToBitmap(); + uint256 quorumsAdded = quorums.orderedBytesArrayToBitmap(); uint192 curBitmap = _getQuorumBitmap(operatorId); uint192 prevBitmap = _getPrevQuorumBitmap(operatorId); @@ -195,9 +221,13 @@ abstract contract IntegrationBase is IntegrationConfig { assertTrue(curBitmap == prevBitmap.plus(quorumsAdded), err); } - function assert_Snap_Deregistered_FromQuorums(User user, bytes memory quorums, string memory err) internal { + function assert_Snap_Deregistered_FromQuorums( + User user, + bytes memory quorums, + string memory err + ) internal { bytes32 operatorId = user.operatorId(); - uint quorumsRemoved = quorums.orderedBytesArrayToBitmap(); + uint256 quorumsRemoved = quorums.orderedBytesArrayToBitmap(); uint192 curBitmap = _getQuorumBitmap(operatorId); uint192 prevBitmap = _getPrevQuorumBitmap(operatorId); @@ -230,26 +260,34 @@ abstract contract IntegrationBase is IntegrationConfig { } /// @dev Check that the user's pubkey was added to each quorum's apk - function assert_Snap_Added_QuorumApk(User user, bytes memory quorums, string memory err) internal { + function assert_Snap_Added_QuorumApk( + User user, + bytes memory quorums, + string memory err + ) internal { BN254.G1Point memory userPubkey = user.pubkeyG1(); BN254.G1Point[] memory curApks = _getQuorumApks(quorums); BN254.G1Point[] memory prevApks = _getPrevQuorumApks(quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { BN254.G1Point memory expectedApk = prevApks[i].plus(userPubkey); assertEq(expectedApk.X, curApks[i].X, err); assertEq(expectedApk.Y, curApks[i].Y, err); } } - function assert_Snap_Removed_QuorumApk(User user, bytes memory quorums, string memory err) internal { + function assert_Snap_Removed_QuorumApk( + User user, + bytes memory quorums, + string memory err + ) internal { BN254.G1Point memory userPubkey = user.pubkeyG1(); BN254.G1Point[] memory curApks = _getQuorumApks(quorums); BN254.G1Point[] memory prevApks = _getPrevQuorumApks(quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { BN254.G1Point memory expectedApk = prevApks[i].plus(userPubkey.negate()); assertEq(expectedApk.X, curApks[i].X, err); assertEq(expectedApk.Y, curApks[i].Y, err); @@ -260,7 +298,7 @@ abstract contract IntegrationBase is IntegrationConfig { BN254.G1Point[] memory curApks = _getQuorumApks(quorums); BN254.G1Point[] memory prevApks = _getPrevQuorumApks(quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { assertEq(curApks[i].X, prevApks[i].X, err); assertEq(curApks[i].Y, prevApks[i].Y, err); } @@ -275,7 +313,11 @@ abstract contract IntegrationBase is IntegrationConfig { string memory err ) internal { // Sanity check input lengths - assertEq(churnedOperators.length, churnedQuorums.length, "assert_Snap_Churned_QuorumApk: input length mismatch"); + assertEq( + churnedOperators.length, + churnedQuorums.length, + "assert_Snap_Churned_QuorumApk: input length mismatch" + ); BN254.G1Point memory incomingPubkey = incomingOperator.pubkeyG1(); @@ -285,13 +327,11 @@ abstract contract IntegrationBase is IntegrationConfig { // For each churned quorum, check: // - that the corresponding churned operator pubkey was removed // - ... AND that the incomingOperator pubkey was added - for (uint i = 0; i < churnedQuorums.length; i++) { + for (uint256 i = 0; i < churnedQuorums.length; i++) { BN254.G1Point memory churnedPubkey = churnedOperators[i].pubkeyG1(); - BN254.G1Point memory expectedApk - = prevApks[i] - .plus(churnedPubkey.negate()) - .plus(incomingPubkey); + BN254.G1Point memory expectedApk = + prevApks[i].plus(churnedPubkey.negate()).plus(incomingPubkey); assertEq(expectedApk.X, curApks[i].X, err); assertEq(expectedApk.Y, curApks[i].Y, err); @@ -311,7 +351,7 @@ abstract contract IntegrationBase is IntegrationConfig { uint96[] memory curTotalStakes = _getTotalStakes(quorums); uint96[] memory prevTotalStakes = _getPrevTotalStakes(quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { assertEq(curOperatorStakes[i], prevOperatorStakes[i] + addedWeights[i], err); assertEq(curTotalStakes[i], prevTotalStakes[i] + addedWeights[i], err); } @@ -338,12 +378,16 @@ abstract contract IntegrationBase is IntegrationConfig { string memory err ) internal { // Sanity check input lengths - assertEq(churnedOperators.length, churnedQuorums.length, "assert_Snap_Churned_OperatorWeight: input length mismatch"); + assertEq( + churnedOperators.length, + churnedQuorums.length, + "assert_Snap_Churned_OperatorWeight: input length mismatch" + ); // Get weights added and removed for each quorum uint96[] memory addedWeights = _getWeights(incomingOperator, churnedQuorums); uint96[] memory removedWeights = new uint96[](churnedOperators.length); - for (uint i = 0; i < churnedOperators.length; i++) { + for (uint256 i = 0; i < churnedOperators.length; i++) { removedWeights[i] = _getWeight(uint8(churnedQuorums[i]), churnedOperators[i]); } @@ -355,9 +399,11 @@ abstract contract IntegrationBase is IntegrationConfig { // For each quorum, check that the incoming operator's individual stake was increased by addedWeights // and that the total stake is plus addedWeights and minus removedWeights - for (uint i = 0; i < churnedQuorums.length; i++) { + for (uint256 i = 0; i < churnedQuorums.length; i++) { assertEq(curIncomingOpStakes[i], prevIncomingOpStakes[i] + addedWeights[i], err); - assertEq(curTotalStakes[i], prevTotalStakes[i] + addedWeights[i] - removedWeights[i], err); + assertEq( + curTotalStakes[i], prevTotalStakes[i] + addedWeights[i] - removedWeights[i], err + ); } } @@ -369,7 +415,7 @@ abstract contract IntegrationBase is IntegrationConfig { uint96[] memory curStakes = _getStakes(user, quorums); uint96[] memory prevStakes = _getPrevStakes(user, quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { assertEq(curStakes[i], prevStakes[i], err); } } @@ -383,7 +429,7 @@ abstract contract IntegrationBase is IntegrationConfig { uint96[] memory curWeights = _getWeights(user, quorums); uint96[] memory prevWeights = _getPrevWeights(user, quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { assertTrue(curWeights[i] >= prevWeights[i], err); } } @@ -397,7 +443,7 @@ abstract contract IntegrationBase is IntegrationConfig { uint96[] memory curWeights = _getWeights(user, quorums); uint96[] memory prevWeights = _getPrevWeights(user, quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { assertTrue(curWeights[i] <= prevWeights[i], err); } } @@ -410,7 +456,7 @@ abstract contract IntegrationBase is IntegrationConfig { uint96[] memory curWeights = _getWeights(user, quorums); uint96[] memory prevWeights = _getPrevWeights(user, quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { assertEq(curWeights[i], prevWeights[i], err); } } @@ -425,7 +471,7 @@ abstract contract IntegrationBase is IntegrationConfig { uint96[] memory curTotalStakes = _getTotalStakes(quorums); uint96[] memory prevTotalStakes = _getPrevTotalStakes(quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { assertEq(curTotalStakes[i], prevTotalStakes[i] + addedWeights[i], err); } } @@ -441,19 +487,16 @@ abstract contract IntegrationBase is IntegrationConfig { uint96[] memory curTotalStakes = _getTotalStakes(quorums); uint96[] memory prevTotalStakes = _getPrevTotalStakes(quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { assertEq(curTotalStakes[i], prevTotalStakes[i] - prevOperatorStakes[i], err); } } - function assert_Snap_Unchanged_TotalStake( - bytes memory quorums, - string memory err - ) internal { + function assert_Snap_Unchanged_TotalStake(bytes memory quorums, string memory err) internal { uint96[] memory curTotalStakes = _getTotalStakes(quorums); uint96[] memory prevTotalStakes = _getPrevTotalStakes(quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { assertEq(curTotalStakes[i], prevTotalStakes[i], err); } } @@ -463,7 +506,7 @@ abstract contract IntegrationBase is IntegrationConfig { uint32[] memory curOperatorCounts = _getOperatorCounts(quorums); uint32[] memory prevOperatorCounts = _getPrevOperatorCounts(quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { assertEq(curOperatorCounts[i], prevOperatorCounts[i] + 1, err); } } @@ -472,16 +515,19 @@ abstract contract IntegrationBase is IntegrationConfig { uint32[] memory curOperatorCounts = _getOperatorCounts(quorums); uint32[] memory prevOperatorCounts = _getPrevOperatorCounts(quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { assertEq(curOperatorCounts[i], prevOperatorCounts[i] - 1, err); } } - function assert_Snap_Unchanged_OperatorCount(bytes memory quorums, string memory err) internal { + function assert_Snap_Unchanged_OperatorCount( + bytes memory quorums, + string memory err + ) internal { uint32[] memory curOperatorCounts = _getOperatorCounts(quorums); uint32[] memory prevOperatorCounts = _getPrevOperatorCounts(quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { assertEq(curOperatorCounts[i], prevOperatorCounts[i], err); } } @@ -497,7 +543,7 @@ abstract contract IntegrationBase is IntegrationConfig { bytes32[][] memory curOperatorLists = _getOperatorLists(quorums); bytes32[][] memory prevOperatorLists = _getPrevOperatorLists(quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { assertEq(curOperatorLists[i].length, prevOperatorLists[i].length + 1, err); assertTrue(_contains(curOperatorLists[i], operator), err); @@ -516,7 +562,7 @@ abstract contract IntegrationBase is IntegrationConfig { bytes32[][] memory curOperatorLists = _getOperatorLists(quorums); bytes32[][] memory prevOperatorLists = _getPrevOperatorLists(quorums); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { assertEq(curOperatorLists[i].length, prevOperatorLists[i].length - 1, err); assertFalse(_contains(curOperatorLists[i], operator), err); @@ -524,7 +570,10 @@ abstract contract IntegrationBase is IntegrationConfig { } } - function assert_Snap_Unchanged_OperatorListEntry(bytes memory quorums, string memory err) internal { + function assert_Snap_Unchanged_OperatorListEntry( + bytes memory quorums, + string memory err + ) internal { bytes32[][] memory curOperatorLists = _getOperatorLists(quorums); bytes32[][] memory prevOperatorLists = _getPrevOperatorLists(quorums); @@ -545,12 +594,16 @@ abstract contract IntegrationBase is IntegrationConfig { string memory err ) internal { // Sanity check input lengths - assertEq(churnedOperators.length, churnedQuorums.length, "assert_Snap_Replaced_OperatorListEntries: input length mismatch"); + assertEq( + churnedOperators.length, + churnedQuorums.length, + "assert_Snap_Replaced_OperatorListEntries: input length mismatch" + ); bytes32[][] memory curOperatorLists = _getOperatorLists(churnedQuorums); bytes32[][] memory prevOperatorLists = _getPrevOperatorLists(churnedQuorums); - for (uint i = 0; i < churnedQuorums.length; i++) { + for (uint256 i = 0; i < churnedQuorums.length; i++) { assertEq(curOperatorLists[i].length, prevOperatorLists[i].length, err); // check incomingOperator was added @@ -563,25 +616,27 @@ abstract contract IntegrationBase is IntegrationConfig { } } - /******************************************************************************* - SNAPSHOT ASSERTIONS (CORE) - TIME TRAVELERS ONLY BEYOND THIS POINT - *******************************************************************************/ + /** + * + * SNAPSHOT ASSERTIONS (CORE) + * TIME TRAVELERS ONLY BEYOND THIS POINT + * + */ /// @dev Check that the operator has `addedShares` additional operator shares // for each strategy since the last snapshot function assert_Snap_Added_OperatorShares( User operator, IStrategy[] memory strategies, - uint[] memory addedShares, + uint256[] memory addedShares, string memory err ) internal { - uint[] memory curShares = _getOperatorShares(operator, strategies); + uint256[] memory curShares = _getOperatorShares(operator, strategies); // Use timewarp to get previous operator shares - uint[] memory prevShares = _getPrevOperatorShares(operator, strategies); + uint256[] memory prevShares = _getPrevOperatorShares(operator, strategies); // For each strategy, check (prev + added == cur) - for (uint i = 0; i < strategies.length; i++) { + for (uint256 i = 0; i < strategies.length; i++) { assertEq(prevShares[i] + addedShares[i], curShares[i], err); } } @@ -594,12 +649,12 @@ abstract contract IntegrationBase is IntegrationConfig { uint256[] memory removedShares, string memory err ) internal { - uint[] memory curShares = _getOperatorShares(operator, strategies); + uint256[] memory curShares = _getOperatorShares(operator, strategies); // Use timewarp to get previous operator shares - uint[] memory prevShares = _getPrevOperatorShares(operator, strategies); + uint256[] memory prevShares = _getPrevOperatorShares(operator, strategies); // For each strategy, check (prev - removed == cur) - for (uint i = 0; i < strategies.length; i++) { + for (uint256 i = 0; i < strategies.length; i++) { assertEq(prevShares[i] - removedShares[i], curShares[i], err); } } @@ -609,15 +664,15 @@ abstract contract IntegrationBase is IntegrationConfig { function assert_Snap_Added_StakerShares( User staker, IStrategy[] memory strategies, - uint[] memory addedShares, + uint256[] memory addedShares, string memory err ) internal { - uint[] memory curShares = _getStakerShares(staker, strategies); + uint256[] memory curShares = _getStakerShares(staker, strategies); // Use timewarp to get previous staker shares - uint[] memory prevShares = _getPrevStakerShares(staker, strategies); + uint256[] memory prevShares = _getPrevStakerShares(staker, strategies); // For each strategy, check (prev + added == cur) - for (uint i = 0; i < strategies.length; i++) { + for (uint256 i = 0; i < strategies.length; i++) { assertEq(prevShares[i] + addedShares[i], curShares[i], err); } } @@ -627,15 +682,15 @@ abstract contract IntegrationBase is IntegrationConfig { function assert_Snap_Removed_StakerShares( User staker, IStrategy[] memory strategies, - uint[] memory removedShares, + uint256[] memory removedShares, string memory err ) internal { - uint[] memory curShares = _getStakerShares(staker, strategies); + uint256[] memory curShares = _getStakerShares(staker, strategies); // Use timewarp to get previous staker shares - uint[] memory prevShares = _getPrevStakerShares(staker, strategies); + uint256[] memory prevShares = _getPrevStakerShares(staker, strategies); // For each strategy, check (prev - removed == cur) - for (uint i = 0; i < strategies.length; i++) { + for (uint256 i = 0; i < strategies.length; i++) { assertEq(prevShares[i] - removedShares[i], curShares[i], err); } } @@ -645,41 +700,45 @@ abstract contract IntegrationBase is IntegrationConfig { IDelegationManager.Withdrawal[] memory withdrawals, string memory err ) internal { - uint curQueuedWithdrawals = _getCumulativeWithdrawals(staker); + uint256 curQueuedWithdrawals = _getCumulativeWithdrawals(staker); // Use timewarp to get previous cumulative withdrawals - uint prevQueuedWithdrawals = _getPrevCumulativeWithdrawals(staker); + uint256 prevQueuedWithdrawals = _getPrevCumulativeWithdrawals(staker); assertEq(prevQueuedWithdrawals + withdrawals.length, curQueuedWithdrawals, err); } - function assert_Snap_Added_QueuedWithdrawal( - User staker, - string memory err - ) internal { - uint curQueuedWithdrawal = _getCumulativeWithdrawals(staker); + function assert_Snap_Added_QueuedWithdrawal(User staker, string memory err) internal { + uint256 curQueuedWithdrawal = _getCumulativeWithdrawals(staker); // Use timewarp to get previous cumulative withdrawals - uint prevQueuedWithdrawal = _getPrevCumulativeWithdrawals(staker); + uint256 prevQueuedWithdrawal = _getPrevCumulativeWithdrawals(staker); assertEq(prevQueuedWithdrawal + 1, curQueuedWithdrawal, err); } - /******************************************************************************* - UTILITY METHODS - *******************************************************************************/ - - function _calcRemaining(bytes memory start, bytes memory removed) internal pure returns (bytes memory) { - uint startBM = start.orderedBytesArrayToBitmap(); - uint removeBM = removed.orderedBytesArrayToBitmap(); + /** + * + * UTILITY METHODS + * + */ + function _calcRemaining( + bytes memory start, + bytes memory removed + ) internal pure returns (bytes memory) { + uint256 startBM = start.orderedBytesArrayToBitmap(); + uint256 removeBM = removed.orderedBytesArrayToBitmap(); return startBM.minus(removeBM).bitmapToBytesArray(); } /// @dev For some strategies/underlying token balances, calculate the expected shares received /// from depositing all tokens - function _calculateExpectedShares(IStrategy[] memory strategies, uint[] memory tokenBalances) internal returns (uint[] memory) { - uint[] memory expectedShares = new uint[](strategies.length); + function _calculateExpectedShares( + IStrategy[] memory strategies, + uint256[] memory tokenBalances + ) internal returns (uint256[] memory) { + uint256[] memory expectedShares = new uint256[](strategies.length); - for (uint i = 0; i < strategies.length; i++) { + for (uint256 i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; expectedShares[i] = strat.underlyingToShares(tokenBalances[i]); @@ -690,10 +749,13 @@ abstract contract IntegrationBase is IntegrationConfig { /// @dev For some strategies/underlying token balances, calculate the expected shares received /// from depositing all tokens - function _calculateExpectedTokens(IStrategy[] memory strategies, uint[] memory shares) internal returns (uint[] memory) { - uint[] memory expectedTokens = new uint[](strategies.length); + function _calculateExpectedTokens( + IStrategy[] memory strategies, + uint256[] memory shares + ) internal returns (uint256[] memory) { + uint256[] memory expectedTokens = new uint256[](strategies.length); - for (uint i = 0; i < strategies.length; i++) { + for (uint256 i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; expectedTokens[i] = strat.sharesToUnderlying(shares[i]); @@ -703,10 +765,12 @@ abstract contract IntegrationBase is IntegrationConfig { } /// @dev Converts a list of strategies to underlying tokens - function _getUnderlyingTokens(IStrategy[] memory strategies) internal view returns (IERC20[] memory) { + function _getUnderlyingTokens( + IStrategy[] memory strategies + ) internal view returns (IERC20[] memory) { IERC20[] memory tokens = new IERC20[](strategies.length); - for (uint i = 0; i < tokens.length; i++) { + for (uint256 i = 0; i < tokens.length; i++) { IStrategy strat = strategies[i]; tokens[i] = strat.underlyingToken(); @@ -718,7 +782,7 @@ abstract contract IntegrationBase is IntegrationConfig { function _contains(bytes32[] memory operatorIds, User operator) internal view returns (bool) { bytes32 checkId = operator.operatorId(); - for (uint i = 0; i < operatorIds.length; i++) { + for (uint256 i = 0; i < operatorIds.length; i++) { if (operatorIds[i] == checkId) { return true; } @@ -727,12 +791,13 @@ abstract contract IntegrationBase is IntegrationConfig { return false; } - /******************************************************************************* - TIMEWARP GETTERS - *******************************************************************************/ - + /** + * + * TIMEWARP GETTERS + * + */ modifier timewarp() { - uint curState = timeMachine.warpToLast(); + uint256 curState = timeMachine.warpToLast(); _; timeMachine.warpToPresent(curState); } @@ -743,15 +808,18 @@ abstract contract IntegrationBase is IntegrationConfig { function _getPrevOperatorShares( User operator, IStrategy[] memory strategies - ) internal timewarp() returns (uint[] memory) { + ) internal timewarp returns (uint256[] memory) { return _getOperatorShares(operator, strategies); } /// @dev Looks up each strategy and returns a list of the operator's shares - function _getOperatorShares(User operator, IStrategy[] memory strategies) internal view returns (uint[] memory) { - uint[] memory curShares = new uint[](strategies.length); + function _getOperatorShares( + User operator, + IStrategy[] memory strategies + ) internal view returns (uint256[] memory) { + uint256[] memory curShares = new uint256[](strategies.length); - for (uint i = 0; i < strategies.length; i++) { + for (uint256 i = 0; i < strategies.length; i++) { curShares[i] = delegationManager.operatorShares(address(operator), strategies[i]); } @@ -762,15 +830,18 @@ abstract contract IntegrationBase is IntegrationConfig { function _getPrevStakerShares( User staker, IStrategy[] memory strategies - ) internal timewarp() returns (uint[] memory) { + ) internal timewarp returns (uint256[] memory) { return _getStakerShares(staker, strategies); } /// @dev Looks up each strategy and returns a list of the staker's shares - function _getStakerShares(User staker, IStrategy[] memory strategies) internal view returns (uint[] memory) { - uint[] memory curShares = new uint[](strategies.length); + function _getStakerShares( + User staker, + IStrategy[] memory strategies + ) internal view returns (uint256[] memory) { + uint256[] memory curShares = new uint256[](strategies.length); - for (uint i = 0; i < strategies.length; i++) { + for (uint256 i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; curShares[i] = strategyManager.stakerDepositShares(address(staker), strat); @@ -779,45 +850,61 @@ abstract contract IntegrationBase is IntegrationConfig { return curShares; } - function _getPrevCumulativeWithdrawals(User staker) internal timewarp() returns (uint) { + function _getPrevCumulativeWithdrawals( + User staker + ) internal timewarp returns (uint256) { return _getCumulativeWithdrawals(staker); } - function _getCumulativeWithdrawals(User staker) internal view returns (uint) { + function _getCumulativeWithdrawals( + User staker + ) internal view returns (uint256) { return delegationManager.cumulativeWithdrawalsQueued(address(staker)); } /// RegistryCoordinator: - function _getOperatorInfo(User user) internal view returns (IRegistryCoordinator.OperatorInfo memory) { + function _getOperatorInfo( + User user + ) internal view returns (IRegistryCoordinator.OperatorInfo memory) { return registryCoordinator.getOperator(address(user)); } - function _getPrevOperatorInfo(User user) internal timewarp() returns (IRegistryCoordinator.OperatorInfo memory) { + function _getPrevOperatorInfo( + User user + ) internal timewarp returns (IRegistryCoordinator.OperatorInfo memory) { return _getOperatorInfo(user); } - function _getQuorumBitmap(bytes32 operatorId) internal view returns (uint192) { + function _getQuorumBitmap( + bytes32 operatorId + ) internal view returns (uint192) { return registryCoordinator.getCurrentQuorumBitmap(operatorId); } - function _getPrevQuorumBitmap(bytes32 operatorId) internal timewarp() returns (uint192) { + function _getPrevQuorumBitmap( + bytes32 operatorId + ) internal timewarp returns (uint192) { return _getQuorumBitmap(operatorId); } /// BLSApkRegistry: - function _getQuorumApks(bytes memory quorums) internal view returns (BN254.G1Point[] memory) { + function _getQuorumApks( + bytes memory quorums + ) internal view returns (BN254.G1Point[] memory) { BN254.G1Point[] memory apks = new BN254.G1Point[](quorums.length); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { apks[i] = blsApkRegistry.getApk(uint8(quorums[i])); } return apks; } - function _getPrevQuorumApks(bytes memory quorums) internal timewarp() returns (BN254.G1Point[] memory) { + function _getPrevQuorumApks( + bytes memory quorums + ) internal timewarp returns (BN254.G1Point[] memory) { return _getQuorumApks(quorums); } @@ -827,28 +914,34 @@ abstract contract IntegrationBase is IntegrationConfig { bytes32 operatorId = user.operatorId(); uint96[] memory stakes = new uint96[](quorums.length); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { stakes[i] = stakeRegistry.getCurrentStake(operatorId, uint8(quorums[i])); } return stakes; } - function _getPrevStakes(User user, bytes memory quorums) internal timewarp() returns (uint96[] memory) { + function _getPrevStakes( + User user, + bytes memory quorums + ) internal timewarp returns (uint96[] memory) { return _getStakes(user, quorums); } function _getWeights(User user, bytes memory quorums) internal view returns (uint96[] memory) { uint96[] memory weights = new uint96[](quorums.length); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { weights[i] = stakeRegistry.weightOfOperatorForQuorum(uint8(quorums[i]), address(user)); } return weights; } - function _getPrevWeights(User user, bytes memory quorums) internal timewarp() returns (uint96[] memory) { + function _getPrevWeights( + User user, + bytes memory quorums + ) internal timewarp returns (uint96[] memory) { return _getWeights(user, quorums); } @@ -860,7 +953,7 @@ abstract contract IntegrationBase is IntegrationConfig { uint96[] memory addedWeights = new uint96[](quorums.length); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { uint96 curWeight = curWeights[i]; uint96 prevWeight = prevWeights[i]; @@ -874,47 +967,60 @@ abstract contract IntegrationBase is IntegrationConfig { return addedWeights; } - function _getTotalStakes(bytes memory quorums) internal view returns (uint96[] memory) { + function _getTotalStakes( + bytes memory quorums + ) internal view returns (uint96[] memory) { uint96[] memory stakes = new uint96[](quorums.length); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { stakes[i] = stakeRegistry.getCurrentTotalStake(uint8(quorums[i])); } return stakes; } - function _getPrevTotalStakes(bytes memory quorums) internal timewarp() returns (uint96[] memory) { + function _getPrevTotalStakes( + bytes memory quorums + ) internal timewarp returns (uint96[] memory) { return _getTotalStakes(quorums); } /// IndexRegistry: - function _getOperatorCounts(bytes memory quorums) internal view returns (uint32[] memory) { + function _getOperatorCounts( + bytes memory quorums + ) internal view returns (uint32[] memory) { uint32[] memory operatorCounts = new uint32[](quorums.length); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { operatorCounts[i] = indexRegistry.totalOperatorsForQuorum(uint8(quorums[i])); } return operatorCounts; } - function _getPrevOperatorCounts(bytes memory quorums) internal timewarp() returns (uint32[] memory) { + function _getPrevOperatorCounts( + bytes memory quorums + ) internal timewarp returns (uint32[] memory) { return _getOperatorCounts(quorums); } - function _getOperatorLists(bytes memory quorums) internal view returns (bytes32[][] memory) { + function _getOperatorLists( + bytes memory quorums + ) internal view returns (bytes32[][] memory) { bytes32[][] memory operatorLists = new bytes32[][](quorums.length); - for (uint i = 0; i < quorums.length; i++) { - operatorLists[i] = indexRegistry.getOperatorListAtBlockNumber(uint8(quorums[i]), uint32(block.number)); + for (uint256 i = 0; i < quorums.length; i++) { + operatorLists[i] = + indexRegistry.getOperatorListAtBlockNumber(uint8(quorums[i]), uint32(block.number)); } return operatorLists; } - function _getPrevOperatorLists(bytes memory quorums) internal timewarp() returns (bytes32[][] memory) { + function _getPrevOperatorLists( + bytes memory quorums + ) internal timewarp returns (bytes32[][] memory) { return _getOperatorLists(quorums); } } diff --git a/test/integration/IntegrationChecks.t.sol b/test/integration/IntegrationChecks.t.sol index 0f2de79c..ba9c3d23 100644 --- a/test/integration/IntegrationChecks.t.sol +++ b/test/integration/IntegrationChecks.t.sol @@ -6,74 +6,75 @@ import "test/integration/User.t.sol"; /// @notice Contract that provides utility functions to reuse common test blocks & checks contract IntegrationChecks is IntegrationBase { - using BitmapUtils for *; - /******************************************************************************* - PRE-REGISTER CHECKS - *******************************************************************************/ - + /** + * + * PRE-REGISTER CHECKS + * + */ function check_Never_Registered( User operator ) internal { - _log("check_Never_Registered", operator); + _log("check_Never_Registered", operator); // RegistryCoordinator - assert_HasNoOperatorInfo(operator, - "operator should have empty id and NEVER_REGISTERED status"); - assert_EmptyQuorumBitmap(operator, - "operator already has bits in quorum bitmap"); + assert_HasNoOperatorInfo( + operator, "operator should have empty id and NEVER_REGISTERED status" + ); + assert_EmptyQuorumBitmap(operator, "operator already has bits in quorum bitmap"); // BLSApkRegistry - assert_NoRegisteredPubkey(operator, - "operator already has a registered pubkey"); + assert_NoRegisteredPubkey(operator, "operator already has a registered pubkey"); // DelegationManager - assert_NotRegisteredToAVS(operator, - "operator should not be registered to the AVS"); + assert_NotRegisteredToAVS(operator, "operator should not be registered to the AVS"); } - /******************************************************************************* - POST-REGISTER CHECKS - *******************************************************************************/ - - function check_Register_State( - User operator, - bytes memory quorums - ) internal { + /** + * + * POST-REGISTER CHECKS + * + */ + function check_Register_State(User operator, bytes memory quorums) internal { _log("check_Register_State", operator); // RegistryCoordinator - assert_HasOperatorInfoWithId(operator, - "operatorInfo should have operatorId"); - assert_HasRegisteredStatus(operator, - "operatorInfo status should be REGISTERED"); - assert_IsRegisteredForQuorums(operator, quorums, - "current operator bitmap should include quorums"); - assert_Snap_Registered_ForQuorums(operator, quorums, - "operator did not register for all quorums"); + assert_HasOperatorInfoWithId(operator, "operatorInfo should have operatorId"); + assert_HasRegisteredStatus(operator, "operatorInfo status should be REGISTERED"); + assert_IsRegisteredForQuorums( + operator, quorums, "current operator bitmap should include quorums" + ); + assert_Snap_Registered_ForQuorums( + operator, quorums, "operator did not register for all quorums" + ); // BLSApkRegistry - assert_HasRegisteredPubkey(operator, - "operator should have registered a pubkey"); - assert_Snap_Added_QuorumApk(operator, quorums, - "operator pubkey should have been added to each quorum apk"); + assert_HasRegisteredPubkey(operator, "operator should have registered a pubkey"); + assert_Snap_Added_QuorumApk( + operator, quorums, "operator pubkey should have been added to each quorum apk" + ); // StakeRegistry - assert_HasAtLeastMinimumStake(operator, quorums, - "operator should have at least the minimum stake in each quorum"); - assert_Snap_Added_OperatorWeight(operator, quorums, - "failed to add operator weight to operator and total stake in each quorum"); + assert_HasAtLeastMinimumStake( + operator, quorums, "operator should have at least the minimum stake in each quorum" + ); + assert_Snap_Added_OperatorWeight( + operator, + quorums, + "failed to add operator weight to operator and total stake in each quorum" + ); // IndexRegistry - assert_Snap_Added_OperatorCount(quorums, - "total operator count should have increased for each quorum"); - assert_Snap_Added_OperatorListEntry(operator, quorums, - "operator list should have one more entry"); + assert_Snap_Added_OperatorCount( + quorums, "total operator count should have increased for each quorum" + ); + assert_Snap_Added_OperatorListEntry( + operator, quorums, "operator list should have one more entry" + ); // AVSDirectory - assert_IsRegisteredToAVS(operator, - "operator should be registered to AVS"); + assert_IsRegisteredToAVS(operator, "operator should be registered to AVS"); } /// @dev Combines many checks of check_Register_State and check_Deregister_State @@ -86,80 +87,115 @@ contract IntegrationChecks is IntegrationBase { ) internal { _log("check_Churned_State", incomingOperator); - bytes memory combinedQuorums = - churnedQuorums - .orderedBytesArrayToBitmap() - .plus(standardQuorums.orderedBytesArrayToBitmap()) - .bitmapToBytesArray(); + bytes memory combinedQuorums = churnedQuorums.orderedBytesArrayToBitmap().plus( + standardQuorums.orderedBytesArrayToBitmap() + ).bitmapToBytesArray(); // RegistryCoordinator - assert_HasOperatorInfoWithId(incomingOperator, - "operatorInfo should have operatorId"); - assert_HasRegisteredStatus(incomingOperator, - "operatorInfo status should be REGISTERED"); - assert_IsRegisteredForQuorums(incomingOperator, combinedQuorums, - "current operator bitmap should include quorums"); - assert_Snap_Registered_ForQuorums(incomingOperator, combinedQuorums, - "operator did not register for all quorums"); + assert_HasOperatorInfoWithId(incomingOperator, "operatorInfo should have operatorId"); + assert_HasRegisteredStatus(incomingOperator, "operatorInfo status should be REGISTERED"); + assert_IsRegisteredForQuorums( + incomingOperator, combinedQuorums, "current operator bitmap should include quorums" + ); + assert_Snap_Registered_ForQuorums( + incomingOperator, combinedQuorums, "operator did not register for all quorums" + ); // BLSApkRegistry - assert_HasRegisteredPubkey(incomingOperator, - "operator should have registered a pubkey"); - assert_Snap_Added_QuorumApk(incomingOperator, standardQuorums, - "operator pubkey should have been added to standardQuorums apks"); - assert_Snap_Churned_QuorumApk(incomingOperator, churnedOperators, churnedQuorums, - "operator pubkey should have been added and churned operator pubkeys should have been removed from apks"); + assert_HasRegisteredPubkey(incomingOperator, "operator should have registered a pubkey"); + assert_Snap_Added_QuorumApk( + incomingOperator, + standardQuorums, + "operator pubkey should have been added to standardQuorums apks" + ); + assert_Snap_Churned_QuorumApk( + incomingOperator, + churnedOperators, + churnedQuorums, + "operator pubkey should have been added and churned operator pubkeys should have been removed from apks" + ); // StakeRegistry - assert_HasAtLeastMinimumStake(incomingOperator, combinedQuorums, - "operator should have at least the minimum stake in each quorum"); - assert_Snap_Added_OperatorWeight(incomingOperator, standardQuorums, - "failed to add operator weight to operator and total stake in standardQuorums"); - assert_Snap_Churned_OperatorWeight(incomingOperator, churnedOperators, churnedQuorums, - "failed to add operator weight and remove churned weight from each quorum"); + assert_HasAtLeastMinimumStake( + incomingOperator, + combinedQuorums, + "operator should have at least the minimum stake in each quorum" + ); + assert_Snap_Added_OperatorWeight( + incomingOperator, + standardQuorums, + "failed to add operator weight to operator and total stake in standardQuorums" + ); + assert_Snap_Churned_OperatorWeight( + incomingOperator, + churnedOperators, + churnedQuorums, + "failed to add operator weight and remove churned weight from each quorum" + ); // IndexRegistry - assert_Snap_Added_OperatorCount(standardQuorums, - "total operator count should have increased for standardQuorums"); - assert_Snap_Unchanged_OperatorCount(churnedQuorums, - "total operator count should be the same for churnedQuorums"); - assert_Snap_Added_OperatorListEntry(incomingOperator, standardQuorums, - "operator list should have one more entry in standardQuorums"); - assert_Snap_Replaced_OperatorListEntries(incomingOperator, churnedOperators, churnedQuorums, - "operator list should contain incoming operator and should not contain churned operators"); + assert_Snap_Added_OperatorCount( + standardQuorums, "total operator count should have increased for standardQuorums" + ); + assert_Snap_Unchanged_OperatorCount( + churnedQuorums, "total operator count should be the same for churnedQuorums" + ); + assert_Snap_Added_OperatorListEntry( + incomingOperator, + standardQuorums, + "operator list should have one more entry in standardQuorums" + ); + assert_Snap_Replaced_OperatorListEntries( + incomingOperator, + churnedOperators, + churnedQuorums, + "operator list should contain incoming operator and should not contain churned operators" + ); // AVSDirectory - assert_IsRegisteredToAVS(incomingOperator, - "operator should be registered to AVS"); + assert_IsRegisteredToAVS(incomingOperator, "operator should be registered to AVS"); // Check that churnedOperators are deregistered from churnedQuorums - for (uint i = 0; i < churnedOperators.length; i++) { + for (uint256 i = 0; i < churnedOperators.length; i++) { User churnedOperator = churnedOperators[i]; bytes memory churnedQuorum = new bytes(1); churnedQuorum[0] = churnedQuorums[i]; // RegistryCoordinator - assert_HasOperatorInfoWithId(churnedOperator, - "churned operatorInfo should still have operatorId"); - assert_NotRegisteredForQuorums(churnedOperator, churnedQuorum, - "churned operator bitmap should not include churned quorums"); - assert_Snap_Deregistered_FromQuorums(churnedOperator, churnedQuorum, - "churned operator did not deregister from churned quorum"); + assert_HasOperatorInfoWithId( + churnedOperator, "churned operatorInfo should still have operatorId" + ); + assert_NotRegisteredForQuorums( + churnedOperator, + churnedQuorum, + "churned operator bitmap should not include churned quorums" + ); + assert_Snap_Deregistered_FromQuorums( + churnedOperator, + churnedQuorum, + "churned operator did not deregister from churned quorum" + ); // BLSApkRegistry - assert_HasRegisteredPubkey(churnedOperator, - "churned operator should still have a registered pubkey"); + assert_HasRegisteredPubkey( + churnedOperator, "churned operator should still have a registered pubkey" + ); // StakeRegistry - assert_NoExistingStake(churnedOperator, churnedQuorum, - "operator should no longer have stake in any quorums"); + assert_NoExistingStake( + churnedOperator, + churnedQuorum, + "operator should no longer have stake in any quorums" + ); } } - /******************************************************************************* - BALANCE UPDATE CHECKS - *******************************************************************************/ + /** + * + * BALANCE UPDATE CHECKS + * + */ /// @dev Validate state directly after the operator deposits into Eigenlayer core /// We're mostly checking that nothing in the middleware contracts has changed, @@ -168,37 +204,34 @@ contract IntegrationChecks is IntegrationBase { User operator, bytes memory quorums, IStrategy[] memory strategies, - uint[] memory tokenBalances + uint256[] memory tokenBalances ) internal { _log("check_Deposit_State", operator); // RegistryCoordinator - assert_Snap_Unchanged_OperatorInfo(operator, - "operator info should not have changed"); - assert_Snap_Unchanged_QuorumBitmap(operator, - "operators quorum bitmap should not have changed"); + assert_Snap_Unchanged_OperatorInfo(operator, "operator info should not have changed"); + assert_Snap_Unchanged_QuorumBitmap( + operator, "operators quorum bitmap should not have changed" + ); // BLSApkRegistry - assert_Snap_Unchanged_QuorumApk(quorums, - "quorum apks should not have changed"); + assert_Snap_Unchanged_QuorumApk(quorums, "quorum apks should not have changed"); // StakeRegistry - assert_Snap_Increased_OperatorWeight(operator, quorums, - "operator weight should not have decreased after deposit"); - assert_Snap_Unchanged_OperatorStake(operator, quorums, - "operator stake should be unchanged"); - assert_Snap_Unchanged_TotalStake(quorums, - "total stake should be unchanged"); + assert_Snap_Increased_OperatorWeight( + operator, quorums, "operator weight should not have decreased after deposit" + ); + assert_Snap_Unchanged_OperatorStake(operator, quorums, "operator stake should be unchanged"); + assert_Snap_Unchanged_TotalStake(quorums, "total stake should be unchanged"); // IndexRegistry - assert_Snap_Unchanged_OperatorCount(quorums, - "operator counts should not have changed"); - assert_Snap_Unchanged_OperatorListEntry(quorums, - "operator list should not have changed"); + assert_Snap_Unchanged_OperatorCount(quorums, "operator counts should not have changed"); + assert_Snap_Unchanged_OperatorListEntry(quorums, "operator list should not have changed"); // Core - assert_Snap_Added_OperatorShares(operator, strategies, tokenBalances, - "operator should have additional stake"); + assert_Snap_Added_OperatorShares( + operator, strategies, tokenBalances, "operator should have additional stake" + ); } /// @dev Checks that an operator's stake was successfully increased @@ -212,32 +245,38 @@ contract IntegrationChecks is IntegrationBase { _log("check_DepositUpdate_State", operator); // RegistryCoordinator - assert_Snap_Unchanged_OperatorInfo(operator, - "operator info should not have changed"); - assert_Snap_Unchanged_QuorumBitmap(operator, - "operators quorum bitmap should not have changed"); + assert_Snap_Unchanged_OperatorInfo(operator, "operator info should not have changed"); + assert_Snap_Unchanged_QuorumBitmap( + operator, "operators quorum bitmap should not have changed" + ); // BLSApkRegistry - assert_Snap_Unchanged_QuorumApk(quorums, - "quorum apks should not have changed"); + assert_Snap_Unchanged_QuorumApk(quorums, "quorum apks should not have changed"); // StakeRegistry - assert_HasAtLeastMinimumStake(operator, quorums, - "operator should have at least the minimum stake in each quorum"); - assert_Snap_Unchanged_OperatorWeight(operator, quorums, - "updateOperators should not effect operator weight calculation"); - assert_Snap_AddedWeightToStakes(operator, quorums, addedWeights, - "weights should have been added to operator and total stakes"); + assert_HasAtLeastMinimumStake( + operator, quorums, "operator should have at least the minimum stake in each quorum" + ); + assert_Snap_Unchanged_OperatorWeight( + operator, quorums, "updateOperators should not effect operator weight calculation" + ); + assert_Snap_AddedWeightToStakes( + operator, + quorums, + addedWeights, + "weights should have been added to operator and total stakes" + ); // IndexRegistry - assert_Snap_Unchanged_OperatorCount(quorums, - "total operator count should be unchanged for each quorum"); - assert_Snap_Unchanged_OperatorListEntry(quorums, - "operator list should be unchanged for each quorum"); + assert_Snap_Unchanged_OperatorCount( + quorums, "total operator count should be unchanged for each quorum" + ); + assert_Snap_Unchanged_OperatorListEntry( + quorums, "operator list should be unchanged for each quorum" + ); // AVSDirectory - assert_IsRegisteredToAVS(operator, - "operator should be registered to AVS"); + assert_IsRegisteredToAVS(operator, "operator should be registered to AVS"); } /// @dev Validate state directly after the operator exits from Eigenlayer core (by queuing withdrawals) @@ -250,144 +289,140 @@ contract IntegrationChecks is IntegrationBase { _log("check_Withdraw_State", operator); // RegistryCoordinator - assert_Snap_Unchanged_OperatorInfo(operator, - "operator info should not have changed"); - assert_Snap_Unchanged_QuorumBitmap(operator, - "operators quorum bitmap should not have changed"); + assert_Snap_Unchanged_OperatorInfo(operator, "operator info should not have changed"); + assert_Snap_Unchanged_QuorumBitmap( + operator, "operators quorum bitmap should not have changed" + ); // BLSApkRegistry - assert_Snap_Unchanged_QuorumApk(quorums, - "quorum apks should not have changed"); + assert_Snap_Unchanged_QuorumApk(quorums, "quorum apks should not have changed"); // StakeRegistry - assert_Snap_Decreased_OperatorWeight(operator, quorums, - "operator weight should not have increased after deposit"); - assert_Snap_Unchanged_OperatorStake(operator, quorums, - "operator stake should be unchanged"); - assert_Snap_Unchanged_TotalStake(quorums, - "total stake should be unchanged"); + assert_Snap_Decreased_OperatorWeight( + operator, quorums, "operator weight should not have increased after deposit" + ); + assert_Snap_Unchanged_OperatorStake(operator, quorums, "operator stake should be unchanged"); + assert_Snap_Unchanged_TotalStake(quorums, "total stake should be unchanged"); // IndexRegistry - assert_Snap_Unchanged_OperatorCount(quorums, - "operator counts should not have changed"); - assert_Snap_Unchanged_OperatorListEntry(quorums, - "operator list should not have changed"); + assert_Snap_Unchanged_OperatorCount(quorums, "operator counts should not have changed"); + assert_Snap_Unchanged_OperatorListEntry(quorums, "operator list should not have changed"); // Core - assert_Snap_Removed_OperatorShares(operator, strategies, shares, - "operator should have reduced stake"); + assert_Snap_Removed_OperatorShares( + operator, strategies, shares, "operator should have reduced stake" + ); } /// @dev Validate state when, after exiting from the core contracts, updateOperators is called /// We expect that the operator is completely deregistered. /// NOTE: This is a combination of check_Deregister_State and check_CompleteDeregister_State - function check_WithdrawUpdate_State( - User operator, - bytes memory quorums - ) internal { + function check_WithdrawUpdate_State(User operator, bytes memory quorums) internal { _log("check_WithdrawUpdate_State", operator); // RegistryCoordinator - assert_HasOperatorInfoWithId(operator, - "operatorInfo should still have operatorId"); - assert_EmptyQuorumBitmap(operator, - "operator should not have any bits in bitmap"); - assert_HasDeregisteredStatus(operator, - "operatorInfo status should be DEREGISTERED"); - assert_Snap_Deregistered_FromQuorums(operator, quorums, - "operator did not deregister from all quorums"); + assert_HasOperatorInfoWithId(operator, "operatorInfo should still have operatorId"); + assert_EmptyQuorumBitmap(operator, "operator should not have any bits in bitmap"); + assert_HasDeregisteredStatus(operator, "operatorInfo status should be DEREGISTERED"); + assert_Snap_Deregistered_FromQuorums( + operator, quorums, "operator did not deregister from all quorums" + ); // BLSApkRegistry - assert_HasRegisteredPubkey(operator, - "operator should still have a registered pubkey"); - assert_Snap_Removed_QuorumApk(operator, quorums, - "operator pubkey should have been subtracted from each quorum apk"); + assert_HasRegisteredPubkey(operator, "operator should still have a registered pubkey"); + assert_Snap_Removed_QuorumApk( + operator, quorums, "operator pubkey should have been subtracted from each quorum apk" + ); // StakeRegistry - assert_NoExistingStake(operator, quorums, - "operator should no longer have stake in any quorums"); - assert_Snap_Removed_TotalStake(operator, quorums, - "failed to remove operator weight from total stake for each quorum"); + assert_NoExistingStake( + operator, quorums, "operator should no longer have stake in any quorums" + ); + assert_Snap_Removed_TotalStake( + operator, quorums, "failed to remove operator weight from total stake for each quorum" + ); // IndexRegistry - assert_Snap_Reduced_OperatorCount(quorums, - "total operator count should have decreased for each quorum"); - assert_Snap_Removed_OperatorListEntry(operator, quorums, - "operator list should have one fewer entry"); + assert_Snap_Reduced_OperatorCount( + quorums, "total operator count should have decreased for each quorum" + ); + assert_Snap_Removed_OperatorListEntry( + operator, quorums, "operator list should have one fewer entry" + ); // AVSDirectory - assert_NotRegisteredToAVS(operator, - "operator should not be registered to the AVS"); + assert_NotRegisteredToAVS(operator, "operator should not be registered to the AVS"); } /// @dev Used to validate a stake update after NO core balance changes occured - function check_NoUpdate_State( - User operator, - bytes memory quorums - ) internal { + function check_NoUpdate_State(User operator, bytes memory quorums) internal { _log("check_NoChangeUpdate_State", operator); // RegistryCoordinator - assert_Snap_Unchanged_OperatorInfo(operator, - "operator info should not have changed"); - assert_Snap_Unchanged_QuorumBitmap(operator, - "operators quorum bitmap should not have changed"); + assert_Snap_Unchanged_OperatorInfo(operator, "operator info should not have changed"); + assert_Snap_Unchanged_QuorumBitmap( + operator, "operators quorum bitmap should not have changed" + ); // BLSApkRegistry - assert_Snap_Unchanged_QuorumApk(quorums, - "quorum apks should not have changed"); + assert_Snap_Unchanged_QuorumApk(quorums, "quorum apks should not have changed"); // StakeRegistry - assert_Snap_Unchanged_OperatorWeight(operator, quorums, - "operator weight should be unchanged"); - assert_Snap_Unchanged_OperatorStake(operator, quorums, - "operator stake should be unchanged"); - assert_Snap_Unchanged_TotalStake(quorums, - "total stake should be unchanged"); + assert_Snap_Unchanged_OperatorWeight( + operator, quorums, "operator weight should be unchanged" + ); + assert_Snap_Unchanged_OperatorStake(operator, quorums, "operator stake should be unchanged"); + assert_Snap_Unchanged_TotalStake(quorums, "total stake should be unchanged"); // IndexRegistry - assert_Snap_Unchanged_OperatorCount(quorums, - "total operator count should be unchanged for each quorum"); - assert_Snap_Unchanged_OperatorListEntry(quorums, - "operator list should be unchanged for each quorum"); + assert_Snap_Unchanged_OperatorCount( + quorums, "total operator count should be unchanged for each quorum" + ); + assert_Snap_Unchanged_OperatorListEntry( + quorums, "operator list should be unchanged for each quorum" + ); } - /******************************************************************************* - POST-DEREGISTER CHECKS - *******************************************************************************/ + /** + * + * POST-DEREGISTER CHECKS + * + */ /// @dev Check that the operator correctly deregistered from some quorums - function check_Deregister_State( - User operator, - bytes memory quorums - ) internal { + function check_Deregister_State(User operator, bytes memory quorums) internal { _log("check_Deregister_State", operator); // RegistryCoordinator - assert_HasOperatorInfoWithId(operator, - "operatorInfo should still have operatorId"); - assert_NotRegisteredForQuorums(operator, quorums, - "current operator bitmap should not include quorums"); - assert_Snap_Deregistered_FromQuorums(operator, quorums, - "operator did not deregister from all quorums"); + assert_HasOperatorInfoWithId(operator, "operatorInfo should still have operatorId"); + assert_NotRegisteredForQuorums( + operator, quorums, "current operator bitmap should not include quorums" + ); + assert_Snap_Deregistered_FromQuorums( + operator, quorums, "operator did not deregister from all quorums" + ); // BLSApkRegistry - assert_HasRegisteredPubkey(operator, - "operator should still have a registered pubkey"); - assert_Snap_Removed_QuorumApk(operator, quorums, - "operator pubkey should have been subtracted from each quorum apk"); + assert_HasRegisteredPubkey(operator, "operator should still have a registered pubkey"); + assert_Snap_Removed_QuorumApk( + operator, quorums, "operator pubkey should have been subtracted from each quorum apk" + ); // StakeRegistry - assert_NoExistingStake(operator, quorums, - "operator should no longer have stake in any quorums"); - assert_Snap_Removed_TotalStake(operator, quorums, - "failed to remove operator weight from total stake for each quorum"); + assert_NoExistingStake( + operator, quorums, "operator should no longer have stake in any quorums" + ); + assert_Snap_Removed_TotalStake( + operator, quorums, "failed to remove operator weight from total stake for each quorum" + ); // IndexRegistry - assert_Snap_Reduced_OperatorCount(quorums, - "total operator count should have decreased for each quorum"); - assert_Snap_Removed_OperatorListEntry(operator, quorums, - "operator list should have one fewer entry"); + assert_Snap_Reduced_OperatorCount( + quorums, "total operator count should have decreased for each quorum" + ); + assert_Snap_Removed_OperatorListEntry( + operator, quorums, "operator list should have one fewer entry" + ); } /// @dev Check that the operator correctly deregistered from ALL their quorums @@ -397,21 +432,19 @@ contract IntegrationChecks is IntegrationBase { _log("check_CompleteDeregister_State", operator); // RegistryCoordinator - assert_EmptyQuorumBitmap(operator, - "operator should not have any bits in bitmap"); - assert_HasOperatorInfoWithId(operator, - "operatorInfo should still have operatorId"); - assert_HasDeregisteredStatus(operator, - "operatorInfo status should be DEREGISTERED"); + assert_EmptyQuorumBitmap(operator, "operator should not have any bits in bitmap"); + assert_HasOperatorInfoWithId(operator, "operatorInfo should still have operatorId"); + assert_HasDeregisteredStatus(operator, "operatorInfo status should be DEREGISTERED"); // AVSDirectory - assert_NotRegisteredToAVS(operator, - "operator should not be registered to the AVS"); + assert_NotRegisteredToAVS(operator, "operator should not be registered to the AVS"); } - /******************************************************************************* - UTIL METHODS - *******************************************************************************/ + /** + * + * UTIL METHODS + * + */ /// example output: /// - check_Register_State(Operator0) diff --git a/test/integration/IntegrationConfig.t.sol b/test/integration/IntegrationConfig.t.sol index f3231ac3..e04a7204 100644 --- a/test/integration/IntegrationConfig.t.sol +++ b/test/integration/IntegrationConfig.t.sol @@ -8,7 +8,6 @@ import "test/ffi/util/G2Operations.sol"; import "test/integration/utils/BitmapStrings.t.sol"; contract Constants { - /// Quorum Config: /// @dev Default OperatorSetParam values used to initialize quorums @@ -16,22 +15,21 @@ contract Constants { /// This is a low number because each operator receives its own BLS keypair, which /// is very slow to generate. uint32 constant MAX_OPERATOR_COUNT = 5; - uint16 constant KICK_BIPS_OPERATOR_STAKE = 15000; + uint16 constant KICK_BIPS_OPERATOR_STAKE = 15_000; uint16 constant KICK_BIPS_TOTAL_STAKE = 150; /// Other: /// @dev Number of BLS keypairs to pregenerate. This is a slow operation, /// so I've set this to a low number. - uint constant NUM_GENERATED_OPERATORS = MAX_OPERATOR_COUNT + 5; + uint256 constant NUM_GENERATED_OPERATORS = MAX_OPERATOR_COUNT + 5; - uint constant MAX_QUORUM_COUNT = 192; // From RegistryCoordinator.MAX_QUORUM_COUNT + uint256 constant MAX_QUORUM_COUNT = 192; // From RegistryCoordinator.MAX_QUORUM_COUNT - uint16 internal constant BIPS_DENOMINATOR = 10000; + uint16 internal constant BIPS_DENOMINATOR = 10_000; } contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { - using BitmapStrings for *; using Strings for *; using BN254 for *; @@ -48,42 +46,42 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { bytes minStakeFlags; bytes fillTypeFlags; - uint constant FLAG = 1; + uint256 constant FLAG = 1; /// @dev Flags for userTypes - uint constant DEFAULT = (FLAG << 0); - uint constant ALT_METHODS = (FLAG << 1); + uint256 constant DEFAULT = (FLAG << 0); + uint256 constant ALT_METHODS = (FLAG << 1); /// @dev Flags for numQuorums and numStrategies - uint constant ONE = (FLAG << 0); - uint constant TWO = (FLAG << 1); - uint constant MANY = (FLAG << 2); - uint constant FIFTEEN = (FLAG << 3); - uint constant TWENTY = (FLAG << 4); - uint constant TWENTYFIVE = (FLAG << 5); + uint256 constant ONE = (FLAG << 0); + uint256 constant TWO = (FLAG << 1); + uint256 constant MANY = (FLAG << 2); + uint256 constant FIFTEEN = (FLAG << 3); + uint256 constant TWENTY = (FLAG << 4); + uint256 constant TWENTYFIVE = (FLAG << 5); /// @dev Flags for minimumStake - uint constant NO_MINIMUM = (FLAG << 0); - uint constant HAS_MINIMUM = (FLAG << 1); + uint256 constant NO_MINIMUM = (FLAG << 0); + uint256 constant HAS_MINIMUM = (FLAG << 1); /// @dev Flags for fillTypes - uint constant EMPTY = (FLAG << 0); - uint constant SOME_FILL = (FLAG << 1); - uint constant FULL = (FLAG << 2); + uint256 constant EMPTY = (FLAG << 0); + uint256 constant SOME_FILL = (FLAG << 1); + uint256 constant FULL = (FLAG << 2); /// @dev Tracking variables for pregenerated BLS keypairs: /// (See _fetchKeypair) - uint fetchIdx = 0; - uint[] privKeys; + uint256 fetchIdx = 0; + uint256[] privKeys; IBLSApkRegistry.PubkeyRegistrationParams[] pubkeys; /// @dev Current initialized quorums are tracked here: - uint quorumCount; + uint256 quorumCount; uint192 quorumBitmap; bytes quorumArray; /// @dev Number of operators generated so far - uint numOperators = 0; + uint256 numOperators = 0; /// @dev current array of operatorIds registered so far per quorum. /// does not update and remove if an operator is deregistered however, used for testing updateOperatorsForQuorum mapping(uint8 => address[]) operatorsForQuorum; @@ -94,9 +92,9 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { * so this is the best way to speed things up when running multiple tests. */ constructor() { - for (uint i = 0; i < NUM_GENERATED_OPERATORS; i++) { + for (uint256 i = 0; i < NUM_GENERATED_OPERATORS; i++) { IBLSApkRegistry.PubkeyRegistrationParams memory pubkey; - uint privKey = uint(keccak256(abi.encodePacked(i + 1))); + uint256 privKey = uint256(keccak256(abi.encodePacked(i + 1))); pubkey.pubkeyG1 = BN254.generatorG1().scalar_mul(privKey); pubkey.pubkeyG2 = G2Operations.mul(privKey); @@ -112,15 +110,15 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { */ struct QuorumConfig { /// @dev The number of quorums created during setup - uint numQuorums; // ONE | TWO | MANY + uint256 numQuorums; // ONE | TWO | MANY /// @dev The number of strategies a quorum will consider - uint numStrategies; // ONE | TWO | MANY + uint256 numStrategies; // ONE | TWO | MANY /// @dev Whether each quorum has a minimum stake /// NOTE: Minimum stake is currently MIN_BALANCE by default - uint minimumStake; // NO_MINIMUM | HAS_MINIMUM + uint256 minimumStake; // NO_MINIMUM | HAS_MINIMUM /// @dev Whether each quorum created is pre-populated with operators /// NOTE: Default - uint fillTypes; // EMPTY | SOME_FILL | FULL + uint256 fillTypes; // EMPTY | SOME_FILL | FULL } /** @@ -131,7 +129,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { */ function _configRand( uint24 _randomSeed, - uint _userTypes, + uint256 _userTypes, QuorumConfig memory _quorumConfig ) internal { emit log_named_uint("_configRand: set random seed to", _randomSeed); @@ -147,7 +145,9 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { // Sanity check config assertTrue(userFlags.length != 0, "_configRand: invalid _userTypes, no flags passed"); assertTrue(numQuorumFlags.length != 0, "_configRand: invalid numQuorums, no flags passed"); - assertTrue(numStrategyFlags.length != 0, "_configRand: invalid numStrategies, no flags passed"); + assertTrue( + numStrategyFlags.length != 0, "_configRand: invalid numStrategies, no flags passed" + ); assertTrue(minStakeFlags.length != 0, "_configRand: invalid minimumStake, no flags passed"); assertTrue(fillTypeFlags.length != 0, "_configRand: invalid fillTypes, no flags passed"); @@ -158,14 +158,15 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { emit log_named_uint("_configRand: number of quorums being initialized", quorumCount); // Default OperatorSetParams for all quorums - IRegistryCoordinator.OperatorSetParam memory operatorSet = IRegistryCoordinator.OperatorSetParam({ + IRegistryCoordinator.OperatorSetParam memory operatorSet = IRegistryCoordinator + .OperatorSetParam({ maxOperatorCount: MAX_OPERATOR_COUNT, kickBIPsOfOperatorStake: KICK_BIPS_OPERATOR_STAKE, kickBIPsOfTotalStake: KICK_BIPS_TOTAL_STAKE }); // Initialize each quorum - for (uint i = 0; i < quorumCount; i++) { + for (uint256 i = 0; i < quorumCount; i++) { IStakeRegistry.StrategyParams[] memory strategyParams = _randStrategyParams(); uint96 minimumStake = _randMinStake(); @@ -183,15 +184,19 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { } // Decide how many operators to register for each quorum initially - uint initialOperators = _randInitialOperators(operatorSet); - emit log(string.concat("Registering ", initialOperators.toString(), " initial operators in each quorum")); + uint256 initialOperators = _randInitialOperators(operatorSet); + emit log( + string.concat( + "Registering ", initialOperators.toString(), " initial operators in each quorum" + ) + ); // For each initial operator, register for all quorums - for (uint j = 0; j < initialOperators; j++) { + for (uint256 j = 0; j < initialOperators; j++) { User operator = _newRandomOperator(); operator.registerOperator(quorumArray); - for (uint k = 0; k < quorumArray.length; k++) { + for (uint256 k = 0; k < quorumArray.length; k++) { uint8 quorum = uint8(quorumArray[k]); operatorsForQuorum[quorum].push(address(operator)); } @@ -205,29 +210,34 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /** * Gen/Init methods: */ - function _newRandomOperator() internal returns (User) { string memory operatorName = string.concat("Operator", numOperators.toString()); numOperators++; - (User operator, IStrategy[] memory strategies, uint[] memory tokenBalances) = _randUser(operatorName); + (User operator, IStrategy[] memory strategies, uint256[] memory tokenBalances) = + _randUser(operatorName); operator.registerAsOperator(); operator.depositIntoEigenlayer(strategies, tokenBalances); - assertTrue(delegationManager.isOperator(address(operator)), "_newRandomOperator: operator should be registered"); + assertTrue( + delegationManager.isOperator(address(operator)), + "_newRandomOperator: operator should be registered" + ); return operator; } /// @dev Create a new user with token balances in ALL core-whitelisted strategies - function _randUser(string memory name) internal returns (User, IStrategy[] memory, uint[] memory) { + function _randUser( + string memory name + ) internal returns (User, IStrategy[] memory, uint256[] memory) { // Create User contract and give it a unique BLS keypair - (uint privKey, IBLSApkRegistry.PubkeyRegistrationParams memory pubkey) = _fetchKeypair(); + (uint256 privKey, IBLSApkRegistry.PubkeyRegistrationParams memory pubkey) = _fetchKeypair(); // Use userFlags to pick the kind of user to generate User user; - uint userType = _randValue(userFlags); + uint256 userType = _randValue(userFlags); if (userType == DEFAULT) { user = new User(name, privKey, pubkey); @@ -238,21 +248,23 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { emit log_named_string("_randUser: Created user", user.NAME()); - (IStrategy[] memory strategies, uint[] memory balances) = _dealRandTokens(user); + (IStrategy[] memory strategies, uint256[] memory balances) = _dealRandTokens(user); return (user, strategies, balances); } - function _dealRandTokens(User user) internal returns (IStrategy[] memory, uint[] memory) { + function _dealRandTokens( + User user + ) internal returns (IStrategy[] memory, uint256[] memory) { IStrategy[] memory strategies = new IStrategy[](allStrats.length); - uint[] memory balances = new uint[](allStrats.length); + uint256[] memory balances = new uint256[](allStrats.length); emit log_named_string("_dealRandTokens: dealing assets to", user.NAME()); // Deal the user a random balance between [MIN_BALANCE, MAX_BALANCE] for each existing strategy - for (uint i = 0; i < allStrats.length; i++) { + for (uint256 i = 0; i < allStrats.length; i++) { IStrategy strat = allStrats[i]; IERC20 underlyingToken = strat.underlyingToken(); - uint balance = _randUint({ min: MIN_BALANCE, max: MAX_BALANCE }); + uint256 balance = _randUint({min: MIN_BALANCE, max: MAX_BALANCE}); StdCheats.deal(address(underlyingToken), address(user), balance); strategies[i] = strat; @@ -262,17 +274,19 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { return (strategies, balances); } - function _dealMaxTokens(User user) internal returns (IStrategy[] memory, uint[] memory) { + function _dealMaxTokens( + User user + ) internal returns (IStrategy[] memory, uint256[] memory) { IStrategy[] memory strategies = new IStrategy[](allStrats.length); - uint[] memory balances = new uint[](allStrats.length); + uint256[] memory balances = new uint256[](allStrats.length); emit log_named_string("_dealMaxTokens: dealing assets to", user.NAME()); // Deal the user the 100 * MAX_BALANCE for each existing strategy - for (uint i = 0; i < allStrats.length; i++) { + for (uint256 i = 0; i < allStrats.length; i++) { IStrategy strat = allStrats[i]; IERC20 underlyingToken = strat.underlyingToken(); - uint balance = 100 * MAX_BALANCE; + uint256 balance = 100 * MAX_BALANCE; StdCheats.deal(address(underlyingToken), address(user), balance); strategies[i] = strat; @@ -301,32 +315,45 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { // For each churn quorum, select operators as churn targets User[] memory churnTargets = new User[](churnQuorums.length); - for (uint i = 0; i < churnQuorums.length; i++) { + for (uint256 i = 0; i < churnQuorums.length; i++) { uint8 quorum = uint8(churnQuorums[i]); - IRegistryCoordinator.OperatorSetParam memory params - = registryCoordinator.getOperatorSetParams(quorum); + IRegistryCoordinator.OperatorSetParam memory params = + registryCoordinator.getOperatorSetParams(quorum); // Sanity check - make sure we're at the operator cap uint32 curNumOperators = indexRegistry.totalOperatorsForQuorum(quorum); - assertTrue(curNumOperators >= params.maxOperatorCount, "_getChurnTargets: non-full quorum cannot be churned"); + assertTrue( + curNumOperators >= params.maxOperatorCount, + "_getChurnTargets: non-full quorum cannot be churned" + ); // Get a random registered operator churnTargets[i] = _selectRandRegisteredOperator(quorum); emit log_named_string( - string.concat("_getChurnTargets: selected churn target for quorum ", uint(quorum).toString()), - churnTargets[i].NAME()); + string.concat( + "_getChurnTargets: selected churn target for quorum ", + uint256(quorum).toString() + ), + churnTargets[i].NAME() + ); uint96 currentTotalStake = stakeRegistry.getCurrentTotalStake(quorum); - uint96 operatorToChurnStake = stakeRegistry.getCurrentStake(churnTargets[i].operatorId(), quorum); + uint96 operatorToChurnStake = + stakeRegistry.getCurrentStake(churnTargets[i].operatorId(), quorum); // Ensure the incoming operator exceeds the individual stake threshold -- // more stake than the outgoing operator by kickBIPsOfOperatorStake while ( - _getWeight(quorum, incomingOperator) <= _individualKickThreshold(operatorToChurnStake, params) || - operatorToChurnStake >= _totalKickThreshold(currentTotalStake + _getWeight(quorum, incomingOperator), params) + _getWeight(quorum, incomingOperator) + <= _individualKickThreshold(operatorToChurnStake, params) + || operatorToChurnStake + >= _totalKickThreshold( + currentTotalStake + _getWeight(quorum, incomingOperator), params + ) ) { - (IStrategy[] memory strategies, uint[] memory balances) = _dealMaxTokens(incomingOperator); + (IStrategy[] memory strategies, uint256[] memory balances) = + _dealMaxTokens(incomingOperator); incomingOperator.depositIntoEigenlayer(strategies, balances); } } @@ -351,19 +378,21 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { return totalStake * setParams.kickBIPsOfTotalStake / BIPS_DENOMINATOR; } - function _getWeight( - uint8 quorum, - User operator - ) internal view returns (uint96) { + function _getWeight(uint8 quorum, User operator) internal view returns (uint96) { return stakeRegistry.weightOfOperatorForQuorum(quorum, address(operator)); } - function _makeRoom(bytes memory quorums) private { - emit log_named_string("_getChurnTargets: making room by removing operators from quorums", quorums.toString()); + function _makeRoom( + bytes memory quorums + ) private { + emit log_named_string( + "_getChurnTargets: making room by removing operators from quorums", quorums.toString() + ); - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { uint8 quorum = uint8(quorums[i]); - uint32 maxOperatorCount = registryCoordinator.getOperatorSetParams(quorum).maxOperatorCount; + uint32 maxOperatorCount = + registryCoordinator.getOperatorSetParams(quorum).maxOperatorCount; // Continue deregistering until we're under the cap // This uses while in case we tested a config change that lowered the max count @@ -378,24 +407,31 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { } } - function _selectRandRegisteredOperator(uint8 quorum) internal returns (User) { + function _selectRandRegisteredOperator( + uint8 quorum + ) internal returns (User) { uint32 curNumOperators = indexRegistry.totalOperatorsForQuorum(quorum); bytes32 randId = indexRegistry.getLatestOperatorUpdate({ quorumNumber: quorum, - operatorIndex: uint32(_randUint({ min: 0, max: curNumOperators - 1 })) + operatorIndex: uint32(_randUint({min: 0, max: curNumOperators - 1})) }).operatorId; return User(blsApkRegistry.getOperatorFromPubkeyHash(randId)); } - function _fetchKeypair() internal returns (uint, IBLSApkRegistry.PubkeyRegistrationParams memory) { + function _fetchKeypair() + internal + returns (uint256, IBLSApkRegistry.PubkeyRegistrationParams memory) + { // should probably just generate another keypair at this point if (fetchIdx == privKeys.length) { - revert("_fetchKeypair: not enough generated keys. Check IntegrationDeployer.constructor"); + revert( + "_fetchKeypair: not enough generated keys. Check IntegrationDeployer.constructor" + ); } - uint privKey = privKeys[fetchIdx]; + uint256 privKey = privKeys[fetchIdx]; IBLSApkRegistry.PubkeyRegistrationParams memory pubkey = pubkeys[fetchIdx]; fetchIdx++; @@ -404,12 +440,12 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// @dev Uses `random` to return a random uint, with a range given by `min` and `max` (inclusive) /// @return `min` <= result <= `max` - function _randUint(uint min, uint max) internal returns (uint) { - uint range = max - min + 1; + function _randUint(uint256 min, uint256 max) internal returns (uint256) { + uint256 range = max - min + 1; // calculate the number of bits needed for the range - uint bitsNeeded = 0; - uint tempRange = range; + uint256 bitsNeeded = 0; + uint256 tempRange = range; while (tempRange > 0) { bitsNeeded++; tempRange >>= 1; @@ -417,8 +453,8 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { // create a mask for the required number of bits // and extract the value from the hash - uint mask = (1 << bitsNeeded) - 1; - uint value = uint(random) & mask; + uint256 mask = (1 << bitsNeeded) - 1; + uint256 value = uint256(random) & mask; // in case value is out of range, wrap around or retry while (value >= range) { @@ -431,14 +467,16 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { } function _randBool() internal returns (bool) { - return _randUint({ min: 0, max: 1 }) == 0; + return _randUint({min: 0, max: 1}) == 0; } - function _selectRand(bytes memory quorums) internal returns (bytes memory) { + function _selectRand( + bytes memory quorums + ) internal returns (bytes memory) { assertTrue(quorums.length != 0, "_selectRand: tried to select from empty quorum list"); uint192 result; - for (uint i = 0; i < quorums.length; i++) { + for (uint256 i = 0; i < quorums.length; i++) { if (_randBool()) { result = uint192(result.setBit(uint8(quorums[i]))); } @@ -457,19 +495,21 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { } /// @dev Select a random value from `arr` and return it. Reverts if arr is empty - function _randValue(bytes memory arr) internal returns (uint) { + function _randValue( + bytes memory arr + ) internal returns (uint256) { assertTrue(arr.length > 0, "_randValue: tried to select value from empty array"); - uint idx = _randUint({ min: 0, max: arr.length - 1 }); - return uint(uint8(arr[idx])); + uint256 idx = _randUint({min: 0, max: arr.length - 1}); + return uint256(uint8(arr[idx])); } /// Private _randX methods used by _configRand: /// @dev Select a random number of quorums to initialize /// NOTE: This should only be used when initializing quorums for the first time (in _configRand) - function _randQuorumCount() private returns (uint) { - uint quorumFlag = _randValue(numQuorumFlags); + function _randQuorumCount() private returns (uint256) { + uint256 quorumFlag = _randValue(numQuorumFlags); if (quorumFlag == ONE) { return 1; @@ -478,7 +518,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { } else if (quorumFlag == MANY) { // Ideally this would be MAX_QUORUM_COUNT, but that really slows tests // that have users register for all quorums - return _randUint({ min: 3, max: 10 }); + return _randUint({min: 3, max: 10}); } else { revert("_randQuorumCount: flag not recognized"); } @@ -489,15 +529,15 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// selecting strategies to add after the quorum has been initialized, this is likely to /// return duplicates. function _randStrategyParams() private returns (IStakeRegistry.StrategyParams[] memory) { - uint strategyFlag = _randValue(numStrategyFlags); - uint strategyCount; + uint256 strategyFlag = _randValue(numStrategyFlags); + uint256 strategyCount; if (strategyFlag == ONE) { strategyCount = 1; } else if (strategyFlag == TWO) { strategyCount = 2; } else if (strategyFlag == MANY) { - strategyCount = _randUint({ min: 3, max: allStrats.length - 1 }); + strategyCount = _randUint({min: 3, max: allStrats.length - 1}); } else if (strategyFlag == FIFTEEN) { strategyCount = 15; } else if (strategyFlag == TWENTY) { @@ -508,9 +548,10 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { revert("_randStrategyCount: flag not recognized"); } - IStakeRegistry.StrategyParams[] memory params = new IStakeRegistry.StrategyParams[](strategyCount); + IStakeRegistry.StrategyParams[] memory params = + new IStakeRegistry.StrategyParams[](strategyCount); - for (uint i = 0; i < params.length; i++) { + for (uint256 i = 0; i < params.length; i++) { params[i] = IStakeRegistry.StrategyParams({ strategy: allStrats[i], multiplier: DEFAULT_STRATEGY_MULTIPLIER @@ -524,13 +565,15 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { * @dev Uses _randFillType to determine how many operators to register for a quorum initially * @return The number of operators to register */ - function _randInitialOperators(IRegistryCoordinator.OperatorSetParam memory operatorSet) private returns (uint) { - uint fillTypeFlag = _randValue(fillTypeFlags); + function _randInitialOperators( + IRegistryCoordinator.OperatorSetParam memory operatorSet + ) private returns (uint256) { + uint256 fillTypeFlag = _randValue(fillTypeFlags); if (fillTypeFlag == EMPTY) { return 0; } else if (fillTypeFlag == SOME_FILL) { - return _randUint({ min: 1, max: operatorSet.maxOperatorCount - 1 }); + return _randUint({min: 1, max: operatorSet.maxOperatorCount - 1}); } else if (fillTypeFlag == FULL) { return operatorSet.maxOperatorCount; } else { @@ -540,7 +583,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// @dev Select a random number of quorums to initialize function _randMinStake() private returns (uint96) { - uint minStakeFlag = _randValue(minStakeFlags); + uint256 minStakeFlag = _randValue(minStakeFlags); if (minStakeFlag == NO_MINIMUM) { return 0; @@ -555,10 +598,12 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { * @dev Converts a bitmap into an array of bytes * @dev Each byte in the input is processed as indicating a single bit to flip in the bitmap */ - function _bitmapToBytes(uint bitmap) internal pure returns (bytes memory bytesArray) { - for (uint i = 0; i < 256; ++i) { + function _bitmapToBytes( + uint256 bitmap + ) internal pure returns (bytes memory bytesArray) { + for (uint256 i = 0; i < 256; ++i) { // Mask for i-th bit - uint mask = uint(1 << i); + uint256 mask = uint256(1 << i); // emit log_named_uint("mask: ", mask); diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index acb89afd..5d5ffadd 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -107,7 +107,7 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { /// @notice Upper bound start range is ~1 month into the future, multiple of CALCULATION_INTERVAL_SECONDS uint32 MAX_FUTURE_LENGTH = 28 days; /// @notice absolute min timestamp that a rewards can start at - uint32 GENESIS_REWARDS_TIMESTAMP = 1712188800; + uint32 GENESIS_REWARDS_TIMESTAMP = 1_712_188_800; /// @notice Equivalent to 100%, but in basis points. uint16 internal constant ONE_HUNDRED_IN_BIPS = 10_000; @@ -163,33 +163,41 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { ) ); - permissionController = PermissionController(address(new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), ""))); + permissionController = PermissionController( + address( + new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") + ) + ); rewardsCoordinator = RewardsCoordinator( - address(new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "")) + address( + new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") + ) ); // Deploy EigenPod Contracts - pod = new EigenPod( - ethPOSDeposit, - eigenPodManager, - GENESIS_TIME_LOCAL - ); + pod = new EigenPod(ethPOSDeposit, eigenPodManager, GENESIS_TIME_LOCAL); eigenPodBeacon = new UpgradeableBeacon(address(pod)); PermissionController permissionControllerImplementation = new PermissionController(); // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs - DelegationManager delegationImplementation = - new DelegationManager(strategyManager, eigenPodManager, allocationManager, pauserRegistry, permissionController, 0); + DelegationManager delegationImplementation = new DelegationManager( + strategyManager, + eigenPodManager, + allocationManager, + pauserRegistry, + permissionController, + 0 + ); StrategyManager strategyManagerImplementation = new StrategyManager(delegationManager, pauserRegistry); - EigenPodManager eigenPodManagerImplementation = new EigenPodManager( - ethPOSDeposit, eigenPodBeacon, delegationManager, pauserRegistry - ); + EigenPodManager eigenPodManagerImplementation = + new EigenPodManager(ethPOSDeposit, eigenPodBeacon, delegationManager, pauserRegistry); console.log("HERE Impl"); - AVSDirectory avsDirectoryImplementation = new AVSDirectory(delegationManager, pauserRegistry); + AVSDirectory avsDirectoryImplementation = + new AVSDirectory(delegationManager, pauserRegistry); RewardsCoordinator rewardsCoordinatorImplementation = new RewardsCoordinator( delegationManager, @@ -209,7 +217,7 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { pauserRegistry, permissionController, uint32(7 days), // DEALLOCATION_DELAY - uint32(1 days) // ALLOCATION_CONFIGURATION_DELAY + uint32(1 days) // ALLOCATION_CONFIGURATION_DELAY ); // Third, upgrade the proxy contracts to point to the implementations @@ -332,7 +340,11 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { cheats.stopPrank(); StakeRegistry stakeRegistryImplementation = new StakeRegistry( - IRegistryCoordinator(registryCoordinator), IDelegationManager(delegationManager), IAVSDirectory(avsDirectory), allocationManager, IServiceManager(serviceManager) + IRegistryCoordinator(registryCoordinator), + IDelegationManager(delegationManager), + IAVSDirectory(avsDirectory), + allocationManager, + IServiceManager(serviceManager) ); BLSApkRegistry blsApkRegistryImplementation = new BLSApkRegistry(IRegistryCoordinator(registryCoordinator)); @@ -374,8 +386,14 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { StakeType[] memory quorumStakeTypes = new StakeType[](0); uint32[] memory slashableStakeQuorumLookAheadPeriods = new uint32[](0); - RegistryCoordinator registryCoordinatorImplementation = - new RegistryCoordinator(serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, allocationManager, pauserRegistry); + RegistryCoordinator registryCoordinatorImplementation = new RegistryCoordinator( + serviceManager, + stakeRegistry, + blsApkRegistry, + indexRegistry, + allocationManager, + pauserRegistry + ); proxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(registryCoordinator))), address(registryCoordinatorImplementation), @@ -423,9 +441,7 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { bool[] memory thirdPartyTransfersForbiddenValues = new bool[](1); strategies[0] = strategy; cheats.prank(strategyManager.strategyWhitelister()); - strategyManager.addStrategiesToDepositWhitelist( - strategies - ); + strategyManager.addStrategiesToDepositWhitelist(strategies); // Add to allStrats allStrats.push(strategy); diff --git a/test/integration/TimeMachine.t.sol b/test/integration/TimeMachine.t.sol index b1cffa68..d16e1ac4 100644 --- a/test/integration/TimeMachine.t.sol +++ b/test/integration/TimeMachine.t.sol @@ -4,20 +4,19 @@ pragma solidity ^0.8.27; import "forge-std/Test.sol"; contract TimeMachine is Test { - Vm cheats = Vm(VM_ADDRESS); bool pastExists = false; - uint lastSnapshot; + uint256 lastSnapshot; - function createSnapshot() public returns (uint) { - uint snapshot = cheats.snapshot(); + function createSnapshot() public returns (uint256) { + uint256 snapshot = cheats.snapshot(); lastSnapshot = snapshot; pastExists = true; return snapshot; } - function warpToLast() public returns (uint curState) { + function warpToLast() public returns (uint256 curState) { // Safety check to make sure createSnapshot is called before attempting to warp // so we don't accidentally prevent our own births assertTrue(pastExists, "TimeMachine.warpToLast: invalid usage, past does not exist"); @@ -27,7 +26,9 @@ contract TimeMachine is Test { return curState; } - function warpToPresent(uint curState) public { + function warpToPresent( + uint256 curState + ) public { cheats.revertTo(curState); } } diff --git a/test/integration/User.t.sol b/test/integration/User.t.sol index 23e9ffcc..fbc491f5 100644 --- a/test/integration/User.t.sol +++ b/test/integration/User.t.sol @@ -28,17 +28,15 @@ import "test/integration/TimeMachine.t.sol"; import "test/integration/utils/Sort.t.sol"; import "test/integration/utils/BitmapStrings.t.sol"; - interface IUserDeployer { function registryCoordinator() external view returns (RegistryCoordinator); function avsDirectory() external view returns (AVSDirectory); function timeMachine() external view returns (TimeMachine); - function churnApproverPrivateKey() external view returns (uint); + function churnApproverPrivateKey() external view returns (uint256); function churnApprover() external view returns (address); } contract User is Test { - using BN254 for *; using Strings for *; using BitmapStrings for *; @@ -60,21 +58,25 @@ contract User is Test { TimeMachine timeMachine; - uint churnApproverPrivateKey; + uint256 churnApproverPrivateKey; address churnApprover; string public NAME; bytes32 public operatorId; // BLS keypair: - uint privKey; + uint256 privKey; IBLSApkRegistry.PubkeyRegistrationParams pubkeyParams; // EIP1271 sigs: mapping(bytes32 => bool) digests; - uint salt = 0; + uint256 salt = 0; - constructor(string memory name, uint _privKey, IBLSApkRegistry.PubkeyRegistrationParams memory _pubkeyParams) { + constructor( + string memory name, + uint256 _privKey, + IBLSApkRegistry.PubkeyRegistrationParams memory _pubkeyParams + ) { IUserDeployer deployer = IUserDeployer(msg.sender); registryCoordinator = deployer.registryCoordinator(); @@ -100,7 +102,8 @@ contract User is Test { privKey = _privKey; pubkeyParams = _pubkeyParams; - BN254.G1Point memory registrationMessageHash = registryCoordinator.pubkeyRegistrationMessageHash(address(this)); + BN254.G1Point memory registrationMessageHash = + registryCoordinator.pubkeyRegistrationMessageHash(address(this)); pubkeyParams.pubkeyRegistrationSignature = registrationMessageHash.scalar_mul(privKey); operatorId = pubkeyParams.pubkeyG1.hashG1Point(); @@ -114,8 +117,9 @@ contract User is Test { /** * Middleware contracts: */ - - function registerOperator(bytes calldata quorums) public createSnapshot virtual returns (bytes32) { + function registerOperator( + bytes calldata quorums + ) public virtual createSnapshot returns (bytes32) { _log("registerOperator", quorums); vm.warp(block.timestamp + 1); @@ -136,7 +140,7 @@ contract User is Test { bytes calldata churnQuorums, User[] calldata churnTargets, bytes calldata standardQuorums - ) public createSnapshot virtual { + ) public virtual createSnapshot { _logChurn("registerOperatorWithChurn", churnQuorums, churnTargets, standardQuorums); // Sanity check input: @@ -144,39 +148,41 @@ contract User is Test { // - churnQuorums and standardQuorums should not have any bits in common uint192 churnBitmap = uint192(churnQuorums.orderedBytesArrayToBitmap()); uint192 standardBitmap = uint192(standardQuorums.orderedBytesArrayToBitmap()); - assertEq(churnQuorums.length, churnTargets.length, "User.registerOperatorWithChurn: input length mismatch"); - assertTrue(churnBitmap.noBitsInCommon(standardBitmap), "User.registerOperatorWithChurn: input quorums have common bits"); + assertEq( + churnQuorums.length, + churnTargets.length, + "User.registerOperatorWithChurn: input length mismatch" + ); + assertTrue( + churnBitmap.noBitsInCommon(standardBitmap), + "User.registerOperatorWithChurn: input quorums have common bits" + ); - bytes memory allQuorums = - churnBitmap - .plus(standardBitmap) - .bitmapToBytesArray(); + bytes memory allQuorums = churnBitmap.plus(standardBitmap).bitmapToBytesArray(); - IRegistryCoordinator.OperatorKickParam[] memory kickParams - = new IRegistryCoordinator.OperatorKickParam[](allQuorums.length); + IRegistryCoordinator.OperatorKickParam[] memory kickParams = + new IRegistryCoordinator.OperatorKickParam[](allQuorums.length); // this constructs OperatorKickParam[] in ascending quorum order // (yikes) - uint churnIdx; - uint stdIdx; + uint256 churnIdx; + uint256 stdIdx; while (churnIdx + stdIdx < allQuorums.length) { if (churnIdx == churnQuorums.length) { - kickParams[churnIdx + stdIdx] = IRegistryCoordinator.OperatorKickParam({ - quorumNumber: 0, - operator: address(0) - }); + kickParams[churnIdx + stdIdx] = + IRegistryCoordinator.OperatorKickParam({quorumNumber: 0, operator: address(0)}); stdIdx++; - } else if (stdIdx == standardQuorums.length || churnQuorums[churnIdx] < standardQuorums[stdIdx]) { + } else if ( + stdIdx == standardQuorums.length || churnQuorums[churnIdx] < standardQuorums[stdIdx] + ) { kickParams[churnIdx + stdIdx] = IRegistryCoordinator.OperatorKickParam({ quorumNumber: uint8(churnQuorums[churnIdx]), operator: address(churnTargets[churnIdx]) }); churnIdx++; } else if (standardQuorums[stdIdx] < churnQuorums[churnIdx]) { - kickParams[churnIdx + stdIdx] = IRegistryCoordinator.OperatorKickParam({ - quorumNumber: 0, - operator: address(0) - }); + kickParams[churnIdx + stdIdx] = + IRegistryCoordinator.OperatorKickParam({quorumNumber: 0, operator: address(0)}); stdIdx++; } else { revert("User.registerOperatorWithChurn: malformed input"); @@ -185,7 +191,7 @@ contract User is Test { // Generate churn approver signature bytes32 _salt = keccak256(abi.encodePacked(++salt, address(this))); - uint expiry = type(uint).max; + uint256 expiry = type(uint256).max; bytes32 digest = registryCoordinator.calculateOperatorChurnApprovalDigestHash({ registeringOperator: address(this), registeringOperatorId: operatorId, @@ -203,12 +209,8 @@ contract User is Test { } signature[signature.length - 1] = bytes1(v); - ISignatureUtils.SignatureWithSaltAndExpiry memory churnApproverSignature - = ISignatureUtils.SignatureWithSaltAndExpiry({ - signature: signature, - salt: _salt, - expiry: expiry - }); + ISignatureUtils.SignatureWithSaltAndExpiry memory churnApproverSignature = ISignatureUtils + .SignatureWithSaltAndExpiry({signature: signature, salt: _salt, expiry: expiry}); vm.warp(block.timestamp + 1); registryCoordinator.registerOperatorWithChurn({ @@ -221,14 +223,16 @@ contract User is Test { }); } - function deregisterOperator(bytes calldata quorums) public createSnapshot virtual { + function deregisterOperator( + bytes calldata quorums + ) public virtual createSnapshot { _log("deregisterOperator", quorums); registryCoordinator.deregisterOperator(quorums); } /// @dev Uses updateOperators to update this user's stake - function updateStakes() public createSnapshot virtual { + function updateStakes() public virtual createSnapshot { _log("updateStakes (updateOperators)"); address[] memory addrs = new address[](1); @@ -240,21 +244,23 @@ contract User is Test { /** * Core contracts: */ - - function registerAsOperator() public createSnapshot virtual { + function registerAsOperator() public virtual createSnapshot { _log("registerAsOperator (core)"); /// TODO: check - delegationManager.registerAsOperator(msg.sender,0, NAME); + delegationManager.registerAsOperator(msg.sender, 0, NAME); } // Deposit LSTs into the StrategyManager. This setup does not use the EPMgr or native ETH. - function depositIntoEigenlayer(IStrategy[] memory strategies, uint[] memory tokenBalances) public createSnapshot virtual { + function depositIntoEigenlayer( + IStrategy[] memory strategies, + uint256[] memory tokenBalances + ) public virtual createSnapshot { _log("depositIntoEigenLayer (core)"); - for (uint i = 0; i < strategies.length; i++) { + for (uint256 i = 0; i < strategies.length; i++) { IStrategy strat = strategies[i]; - uint tokenBalance = tokenBalances[i]; + uint256 tokenBalance = tokenBalances[i]; IERC20 underlyingToken = strat.underlyingToken(); underlyingToken.approve(address(strategyManager), tokenBalance); @@ -262,12 +268,19 @@ contract User is Test { } } - function exitEigenlayer() public createSnapshot virtual returns (IStrategy[] memory, uint256[] memory) { + function exitEigenlayer() + public + virtual + createSnapshot + returns (IStrategy[] memory, uint256[] memory) + { _log("exitEigenlayer (core)"); - (IStrategy[] memory strategies, uint256[] memory shares) = delegationManager.getDepositedShares(address(this)); + (IStrategy[] memory strategies, uint256[] memory shares) = + delegationManager.getDepositedShares(address(this)); - IDelegationManagerTypes.QueuedWithdrawalParams[] memory params = new IDelegationManager.QueuedWithdrawalParams[](1); + IDelegationManagerTypes.QueuedWithdrawalParams[] memory params = + new IDelegationManager.QueuedWithdrawalParams[](1); params[0] = IDelegationManagerTypes.QueuedWithdrawalParams({ strategies: strategies, depositShares: shares, @@ -296,8 +309,12 @@ contract User is Test { return pubkeyParams.pubkeyG1; } - function _genAVSRegistrationSig() internal returns (ISignatureUtils.SignatureWithSaltAndExpiry memory) { - ISignatureUtils.SignatureWithSaltAndExpiry memory signature = ISignatureUtils.SignatureWithSaltAndExpiry({ + function _genAVSRegistrationSig() + internal + returns (ISignatureUtils.SignatureWithSaltAndExpiry memory) + { + ISignatureUtils.SignatureWithSaltAndExpiry memory signature = ISignatureUtils + .SignatureWithSaltAndExpiry({ signature: new bytes(0), salt: bytes32(salt++), expiry: type(uint256).max @@ -315,7 +332,9 @@ contract User is Test { } // Operator0.registerOperator - function _log(string memory s) internal virtual { + function _log( + string memory s + ) internal virtual { emit log(string.concat(NAME, ".", s)); } @@ -340,7 +359,7 @@ contract User is Test { emit log_named_string("- churnQuorums", churnQuorums.toString()); string memory targetString = "["; - for (uint i = 0; i < churnTargets.length; i++) { + for (uint256 i = 0; i < churnTargets.length; i++) { if (i == churnTargets.length - 1) { targetString = string.concat(targetString, churnTargets[i].NAME()); } else { @@ -354,7 +373,6 @@ contract User is Test { } contract User_AltMethods is User { - using BitmapUtils for *; modifier createSnapshot() virtual override { @@ -363,12 +381,17 @@ contract User_AltMethods is User { _; } - constructor(string memory name, uint _privKey, IBLSApkRegistry.PubkeyRegistrationParams memory _pubkeyParams) - User(name, _privKey, _pubkeyParams) {} + constructor( + string memory name, + uint256 _privKey, + IBLSApkRegistry.PubkeyRegistrationParams memory _pubkeyParams + ) User(name, _privKey, _pubkeyParams) {} /// @dev Rather than calling deregisterOperator, this pranks the ejector and calls /// ejectOperator - function deregisterOperator(bytes calldata quorums) public createSnapshot virtual override { + function deregisterOperator( + bytes calldata quorums + ) public virtual override createSnapshot { _log("deregisterOperator (eject)", quorums); address ejector = registryCoordinator.ejector(); @@ -378,19 +401,21 @@ contract User_AltMethods is User { } /// @dev Uses updateOperatorsForQuorum to update stakes of all operators in all quorums - function updateStakes() public createSnapshot virtual override { + function updateStakes() public virtual override createSnapshot { _log("updateStakes (updateOperatorsForQuorum)"); - bytes memory allQuorums = ((1 << registryCoordinator.quorumCount()) - 1).bitmapToBytesArray(); + bytes memory allQuorums = + ((1 << registryCoordinator.quorumCount()) - 1).bitmapToBytesArray(); address[][] memory operatorsPerQuorum = new address[][](allQuorums.length); - for (uint i = 0; i < allQuorums.length; i++) { + for (uint256 i = 0; i < allQuorums.length; i++) { uint8 quorum = uint8(allQuorums[i]); - bytes32[] memory operatorIds = indexRegistry.getOperatorListAtBlockNumber(quorum, uint32(block.number)); + bytes32[] memory operatorIds = + indexRegistry.getOperatorListAtBlockNumber(quorum, uint32(block.number)); operatorsPerQuorum[i] = new address[](operatorIds.length); - for (uint j = 0; j < operatorIds.length; j++) { + for (uint256 j = 0; j < operatorIds.length; j++) { operatorsPerQuorum[i][j] = blsApkRegistry.getOperatorFromPubkeyHash(operatorIds[j]); } diff --git a/test/integration/mocks/BeaconChainOracleMock.t.sol b/test/integration/mocks/BeaconChainOracleMock.t.sol index 5c2e4b77..766bb8e7 100644 --- a/test/integration/mocks/BeaconChainOracleMock.t.sol +++ b/test/integration/mocks/BeaconChainOracleMock.t.sol @@ -11,7 +11,9 @@ contract BeaconChainOracleMock { mapping(uint64 => bytes32) blockRoots; - function timestampToBlockRoot(uint256 timestamp) public view returns (bytes32) { + function timestampToBlockRoot( + uint256 timestamp + ) public view returns (bytes32) { return blockRoots[uint64(timestamp)]; } @@ -19,4 +21,3 @@ contract BeaconChainOracleMock { blockRoots[timestamp] = blockRoot; } } - diff --git a/test/integration/tests/Full_Register_Deregister.t.sol b/test/integration/tests/Full_Register_Deregister.t.sol index 2561aa2c..be7f672b 100644 --- a/test/integration/tests/Full_Register_Deregister.t.sol +++ b/test/integration/tests/Full_Register_Deregister.t.sol @@ -6,13 +6,14 @@ import "test/integration/User.t.sol"; import "test/integration/IntegrationChecks.t.sol"; contract Integration_Full_Register_Deregister is IntegrationChecks { - using BitmapUtils for *; // 1. Register for all quorums by churning old operators // 2. Deregister from all quorums // 3. Re-register for all quorums without needing churn - function testFuzz_churnAll_deregisterAll_reregisterAll(uint24 _random) public { + function testFuzz_churnAll_deregisterAll_reregisterAll( + uint24 _random + ) public { _configRand({ _randomSeed: _random, _userTypes: DEFAULT | ALT_METHODS, @@ -60,7 +61,9 @@ contract Integration_Full_Register_Deregister is IntegrationChecks { // 2. Deregister from all quorums // 3. Old operators re-register for quorums // 4. Original operator re-registers for all quorums by churning old operators again - function testFuzz_churnAll_deregisterAll_oldReregisterAll(uint24 _random) public { + function testFuzz_churnAll_deregisterAll_oldReregisterAll( + uint24 _random + ) public { _configRand({ _randomSeed: _random, _userTypes: DEFAULT | ALT_METHODS, @@ -101,7 +104,7 @@ contract Integration_Full_Register_Deregister is IntegrationChecks { // 3. Old operators re-register for quorums // Note: churnTargets.length == quorums.length, so we do these one at a time - for (uint i = 0; i < churnTargets.length; i++) { + for (uint256 i = 0; i < churnTargets.length; i++) { User churnTarget = churnTargets[i]; bytes memory quorum = new bytes(1); quorum[0] = quorums[i]; @@ -123,7 +126,9 @@ contract Integration_Full_Register_Deregister is IntegrationChecks { // 1. Register for *some* quorums with churn, and the rest without churn // 2. Deregister from all quorums // 3. Re-register for all quorums without needing churn - function testFuzz_churnSome_deregisterSome_deregisterRemaining(uint24 _random) public { + function testFuzz_churnSome_deregisterSome_deregisterRemaining( + uint24 _random + ) public { _configRand({ _randomSeed: _random, _userTypes: DEFAULT | ALT_METHODS, @@ -140,11 +145,9 @@ contract Integration_Full_Register_Deregister is IntegrationChecks { // Select some quorums to register using churn, and the rest without churn bytes memory churnQuorums = _selectRand(quorums); - bytes memory standardQuorums = - quorums - .orderedBytesArrayToBitmap() - .minus(churnQuorums.orderedBytesArrayToBitmap()) - .bitmapToBytesArray(); + bytes memory standardQuorums = quorums.orderedBytesArrayToBitmap().minus( + churnQuorums.orderedBytesArrayToBitmap() + ).bitmapToBytesArray(); // Select churnable operators in each quorum. If needed, deals/deposits assets // for the operator, and deregisters operators from standardQuorums to make room diff --git a/test/integration/tests/NonFull_Register_CoreBalanceChange_Update.t.sol b/test/integration/tests/NonFull_Register_CoreBalanceChange_Update.t.sol index d9b74e8d..679ea1b5 100644 --- a/test/integration/tests/NonFull_Register_CoreBalanceChange_Update.t.sol +++ b/test/integration/tests/NonFull_Register_CoreBalanceChange_Update.t.sol @@ -6,12 +6,13 @@ import "test/integration/User.t.sol"; import "test/integration/IntegrationChecks.t.sol"; contract Integration_NonFull_Register_CoreBalanceChange_Update is IntegrationChecks { - // 1. Register for all quorums // 2. (core) Deposit additional tokens // 3. Update stakes // 4. Deregister from all quorums - function testFuzz_registerAll_increaseCoreBalance_update_deregisterAll(uint24 _random) public { + function testFuzz_registerAll_increaseCoreBalance_update_deregisterAll( + uint24 _random + ) public { _configRand({ _randomSeed: _random, _userTypes: DEFAULT | ALT_METHODS, @@ -33,10 +34,7 @@ contract Integration_NonFull_Register_CoreBalanceChange_Update is IntegrationChe check_Register_State(operator, quorums); // Award operator tokens to deposit into core - ( - IStrategy[] memory strategies, - uint[] memory tokenBalances - ) = _dealRandTokens(operator); + (IStrategy[] memory strategies, uint256[] memory tokenBalances) = _dealRandTokens(operator); // 2. (core) Deposit tokens and return the weight added in each initialized quorum operator.depositIntoEigenlayer(strategies, tokenBalances); @@ -56,7 +54,9 @@ contract Integration_NonFull_Register_CoreBalanceChange_Update is IntegrationChe // 1. Register for all quorums // 2. (core) Deposit additional tokens // 3. Deregister from all quorums - function testFuzz_registerAll_increaseCoreBalance_deregisterAll(uint24 _random) public { + function testFuzz_registerAll_increaseCoreBalance_deregisterAll( + uint24 _random + ) public { _configRand({ _randomSeed: _random, _userTypes: DEFAULT | ALT_METHODS, @@ -78,10 +78,7 @@ contract Integration_NonFull_Register_CoreBalanceChange_Update is IntegrationChe check_Register_State(operator, quorums); // Award operator tokens to deposit into core - ( - IStrategy[] memory strategies, - uint[] memory tokenBalances - ) = _dealRandTokens(operator); + (IStrategy[] memory strategies, uint256[] memory tokenBalances) = _dealRandTokens(operator); // 2. (core) Deposit tokens operator.depositIntoEigenlayer(strategies, tokenBalances); @@ -96,7 +93,9 @@ contract Integration_NonFull_Register_CoreBalanceChange_Update is IntegrationChe // 1. Register for all quorums // 2. (core) Queue full withdrawal // 3. updateOperators/updateOperatorsForQuorum - function testFuzz_registerAll_decreaseCoreBalance_update(uint24 _random) public { + function testFuzz_registerAll_decreaseCoreBalance_update( + uint24 _random + ) public { _configRand({ _randomSeed: _random, _userTypes: DEFAULT | ALT_METHODS, @@ -129,7 +128,9 @@ contract Integration_NonFull_Register_CoreBalanceChange_Update is IntegrationChe // 1. Register for all quorums // 2. (core) Queue full withdrawal // 3. Deregister from all quorums - function testFuzz_registerAll_decreaseCoreBalance_deregisterAll(uint24 _random) public { + function testFuzz_registerAll_decreaseCoreBalance_deregisterAll( + uint24 _random + ) public { _configRand({ _randomSeed: _random, _userTypes: DEFAULT | ALT_METHODS, @@ -163,7 +164,9 @@ contract Integration_NonFull_Register_CoreBalanceChange_Update is IntegrationChe // 1. Register for all quorums // 2. updateOperators/updateOperatorsForQuorum // 3. Deregister from all quorums - function testFuzz_registerAll_update_deregisterAll(uint24 _random) public { + function testFuzz_registerAll_update_deregisterAll( + uint24 _random + ) public { _configRand({ _randomSeed: _random, _userTypes: DEFAULT | ALT_METHODS, diff --git a/test/integration/tests/NonFull_Register_Deregister.t.sol b/test/integration/tests/NonFull_Register_Deregister.t.sol index 6acf85cb..5eea66e4 100644 --- a/test/integration/tests/NonFull_Register_Deregister.t.sol +++ b/test/integration/tests/NonFull_Register_Deregister.t.sol @@ -6,12 +6,13 @@ import "test/integration/User.t.sol"; import "test/integration/IntegrationChecks.t.sol"; contract Integration_NonFull_Register_Deregister is IntegrationChecks { - using BitmapUtils for *; // 1. Register for all quorums // 2. Deregister from all quorums - function testFuzz_registerAll_deregisterAll(uint24 _random) public { + function testFuzz_registerAll_deregisterAll( + uint24 _random + ) public { _configRand({ _randomSeed: _random, _userTypes: DEFAULT | ALT_METHODS, @@ -41,7 +42,9 @@ contract Integration_NonFull_Register_Deregister is IntegrationChecks { // 1. Register for some quorums // 2. Deregister from some quorums // 3. Deregister from any remaining quorums - function testFuzz_registerSome_deregisterSome_deregisterRemaining(uint24 _random) public { + function testFuzz_registerSome_deregisterSome_deregisterRemaining( + uint24 _random + ) public { _configRand({ _randomSeed: _random, _userTypes: DEFAULT | ALT_METHODS, @@ -69,7 +72,7 @@ contract Integration_NonFull_Register_Deregister is IntegrationChecks { check_Deregister_State(operator, quorumsToRemove); // 3. Deregister from any remaining quorums - bytes memory quorumsRemaining = _calcRemaining({ start: quorums, removed: quorumsToRemove }); + bytes memory quorumsRemaining = _calcRemaining({start: quorums, removed: quorumsToRemove}); if (quorumsRemaining.length != 0) { operator.deregisterOperator(quorumsRemaining); check_Deregister_State(operator, quorumsRemaining); @@ -80,7 +83,9 @@ contract Integration_NonFull_Register_Deregister is IntegrationChecks { // 1. Register for some quorums // 2. Deregister from some quorums // 3. Reregister for some quorums - function testFuzz_registerSome_deregisterSome_reregisterSome(uint24 _random) public { + function testFuzz_registerSome_deregisterSome_reregisterSome( + uint24 _random + ) public { _configRand({ _randomSeed: _random, _userTypes: DEFAULT | ALT_METHODS, diff --git a/test/integration/utils/BitmapStrings.t.sol b/test/integration/utils/BitmapStrings.t.sol index 2bcec384..7235dab5 100644 --- a/test/integration/utils/BitmapStrings.t.sol +++ b/test/integration/utils/BitmapStrings.t.sol @@ -4,27 +4,21 @@ pragma solidity ^0.8.27; import "@openzeppelin/contracts/utils/Strings.sol"; library BitmapStrings { - using Strings for *; /// @dev Given an input quorum array, returns a nice, readable string: /// e.g. [0, 1, 2, ...] /// (This is way more readable than logging with log_named_bytes) - function toString(bytes memory bitmapArr) internal pure returns (string memory) { + function toString( + bytes memory bitmapArr + ) internal pure returns (string memory) { string memory result = "["; - for (uint i = 0; i < bitmapArr.length; i++) { + for (uint256 i = 0; i < bitmapArr.length; i++) { if (i == bitmapArr.length - 1) { - result = string.concat( - result, - uint(uint8(bitmapArr[i])).toString() - ); + result = string.concat(result, uint256(uint8(bitmapArr[i])).toString()); } else { - result = string.concat( - result, - uint(uint8(bitmapArr[i])).toString(), - ", " - ); + result = string.concat(result, uint256(uint8(bitmapArr[i])).toString(), ", "); } } diff --git a/test/integration/utils/Sort.t.sol b/test/integration/utils/Sort.t.sol index 968400c6..884a02f5 100644 --- a/test/integration/utils/Sort.t.sol +++ b/test/integration/utils/Sort.t.sol @@ -8,7 +8,9 @@ library Sort { * @param addresses The array of addresses to be sorted. * @return sortedAddresses The array of addresses sorted in ascending order. */ - function sortAddresses(address[] memory addresses) internal pure returns (address[] memory) { + function sortAddresses( + address[] memory addresses + ) internal pure returns (address[] memory) { uint256 n = addresses.length; for (uint256 i = 0; i < n; i++) { for (uint256 j = 0; j < n - 1; j++) { diff --git a/test/mocks/AVSDirectoryMock.sol b/test/mocks/AVSDirectoryMock.sol index ca3613ef..0271add0 100644 --- a/test/mocks/AVSDirectoryMock.sol +++ b/test/mocks/AVSDirectoryMock.sol @@ -1,174 +1,154 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IAVSDirectory } from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; +import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; contract AVSDirectoryMock is IAVSDirectory { - function initialize( - address initialOwner, - uint256 initialPausedStatus - ) external {} - - function createOperatorSets( - uint32[] calldata operatorSetIds - ) external {} - - function becomeOperatorSetAVS() external {} - - function migrateOperatorsToOperatorSets( - address[] calldata operators, - uint32[][] calldata operatorSetIds - ) external {} - - function registerOperatorToOperatorSets( - address operator, - uint32[] calldata operatorSetIds, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature - ) external {} - - function forceDeregisterFromOperatorSets( - address operator, - address avs, - uint32[] calldata operatorSetIds, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature - ) external {} - - function deregisterOperatorFromOperatorSets( - address operator, - uint32[] calldata operatorSetIds - ) external {} - - function addStrategiesToOperatorSet( - uint32 operatorSetId, - IStrategy[] calldata strategies - ) external {} - - function removeStrategiesFromOperatorSet( - uint32 operatorSetId, - IStrategy[] calldata strategies - ) external {} - - function updateAVSMetadataURI( - string calldata metadataURI - ) external {} - - function cancelSalt(bytes32 salt) external {} - - function registerOperatorToAVS( - address operator, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature - ) external {} - - function deregisterOperatorFromAVS(address operator) external {} - - function operatorSaltIsSpent( - address operator, - bytes32 salt - ) external view returns (bool) {} - - function isOperatorSetAVS( - address avs - ) external view returns (bool) {} - - function isOperatorSet( - address avs, - uint32 operatorSetId - ) external view returns (bool) {} - - function getNumOperatorSetsOfOperator( - address operator - ) external view returns (uint256) {} - - function inTotalOperatorSets( - address operator - ) external view returns (uint256) {} - - function calculateOperatorAVSRegistrationDigestHash( - address operator, - address avs, - bytes32 salt, - uint256 expiry - ) external view returns (bytes32) {} - - function calculateOperatorSetRegistrationDigestHash( - address avs, - uint32[] calldata operatorSetIds, - bytes32 salt, - uint256 expiry - ) external view returns (bytes32) {} - - function calculateOperatorSetForceDeregistrationTypehash( - address avs, - uint32[] calldata operatorSetIds, - bytes32 salt, - uint256 expiry - ) external view returns (bytes32) {} - - function OPERATOR_AVS_REGISTRATION_TYPEHASH() - external - view - - returns (bytes32) - {} - - function OPERATOR_SET_REGISTRATION_TYPEHASH() - external - view - - returns (bytes32) - {} - - function operatorSetStatus( - address avs, - address operator, - uint32 operatorSetId - ) - external - view - - returns (bool registered, uint32 lastDeregisteredTimestamp) - {} - - function initialize( - address initialOwner, - IPauserRegistry _pauserRegistry, - uint256 initialPausedStatus - ) external {} - - function operatorSetMemberAtIndex( - OperatorSet memory operatorSet, - uint256 index - ) external view returns (address) {} - - function getOperatorsInOperatorSet( - OperatorSet memory operatorSet, - uint256 start, - uint256 length - ) external view returns (address[] memory operators) {} - - function getStrategiesInOperatorSet( - OperatorSet memory operatorSet - ) external view returns (IStrategy[] memory strategies) {} - - function getNumOperatorsInOperatorSet( - OperatorSet memory operatorSet - ) external view returns (uint256) {} - - function isMember( - address operator, - OperatorSet memory operatorSet - ) external view returns (bool) {} - - function isOperatorSlashable( - address operator, - OperatorSet memory operatorSet - ) external view returns (bool) {} - - function isOperatorSetBatch( - OperatorSet[] calldata operatorSets - ) external view returns (bool) {} -} \ No newline at end of file + function initialize(address initialOwner, uint256 initialPausedStatus) external {} + + function createOperatorSets( + uint32[] calldata operatorSetIds + ) external {} + + function becomeOperatorSetAVS() external {} + + function migrateOperatorsToOperatorSets( + address[] calldata operators, + uint32[][] calldata operatorSetIds + ) external {} + + function registerOperatorToOperatorSets( + address operator, + uint32[] calldata operatorSetIds, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external {} + + function forceDeregisterFromOperatorSets( + address operator, + address avs, + uint32[] calldata operatorSetIds, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external {} + + function deregisterOperatorFromOperatorSets( + address operator, + uint32[] calldata operatorSetIds + ) external {} + + function addStrategiesToOperatorSet( + uint32 operatorSetId, + IStrategy[] calldata strategies + ) external {} + + function removeStrategiesFromOperatorSet( + uint32 operatorSetId, + IStrategy[] calldata strategies + ) external {} + + function updateAVSMetadataURI( + string calldata metadataURI + ) external {} + + function cancelSalt( + bytes32 salt + ) external {} + + function registerOperatorToAVS( + address operator, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external {} + + function deregisterOperatorFromAVS( + address operator + ) external {} + + function operatorSaltIsSpent(address operator, bytes32 salt) external view returns (bool) {} + + function isOperatorSetAVS( + address avs + ) external view returns (bool) {} + + function isOperatorSet(address avs, uint32 operatorSetId) external view returns (bool) {} + + function getNumOperatorSetsOfOperator( + address operator + ) external view returns (uint256) {} + + function inTotalOperatorSets( + address operator + ) external view returns (uint256) {} + + function calculateOperatorAVSRegistrationDigestHash( + address operator, + address avs, + bytes32 salt, + uint256 expiry + ) external view returns (bytes32) {} + + function calculateOperatorSetRegistrationDigestHash( + address avs, + uint32[] calldata operatorSetIds, + bytes32 salt, + uint256 expiry + ) external view returns (bytes32) {} + + function calculateOperatorSetForceDeregistrationTypehash( + address avs, + uint32[] calldata operatorSetIds, + bytes32 salt, + uint256 expiry + ) external view returns (bytes32) {} + + function OPERATOR_AVS_REGISTRATION_TYPEHASH() external view returns (bytes32) {} + + function OPERATOR_SET_REGISTRATION_TYPEHASH() external view returns (bytes32) {} + + function operatorSetStatus( + address avs, + address operator, + uint32 operatorSetId + ) external view returns (bool registered, uint32 lastDeregisteredTimestamp) {} + + function initialize( + address initialOwner, + IPauserRegistry _pauserRegistry, + uint256 initialPausedStatus + ) external {} + + function operatorSetMemberAtIndex( + OperatorSet memory operatorSet, + uint256 index + ) external view returns (address) {} + + function getOperatorsInOperatorSet( + OperatorSet memory operatorSet, + uint256 start, + uint256 length + ) external view returns (address[] memory operators) {} + + function getStrategiesInOperatorSet( + OperatorSet memory operatorSet + ) external view returns (IStrategy[] memory strategies) {} + + function getNumOperatorsInOperatorSet( + OperatorSet memory operatorSet + ) external view returns (uint256) {} + + function isMember( + address operator, + OperatorSet memory operatorSet + ) external view returns (bool) {} + + function isOperatorSlashable( + address operator, + OperatorSet memory operatorSet + ) external view returns (bool) {} + + function isOperatorSetBatch( + OperatorSet[] calldata operatorSets + ) external view returns (bool) {} +} diff --git a/test/mocks/AllocationManagerMock.sol b/test/mocks/AllocationManagerMock.sol index b355af95..22b92b74 100644 --- a/test/mocks/AllocationManagerMock.sol +++ b/test/mocks/AllocationManagerMock.sol @@ -1,175 +1,154 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IAllocationManager, OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IAVSRegistrar } from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; +import { + IAllocationManager, + OperatorSet +} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; + contract AllocationManagerIntermediate is IAllocationManager { - function initialize( - address initialOwner, - uint256 initialPausedStatus - ) external virtual {} - - function slashOperator( - address avs, - SlashingParams calldata params - ) external virtual {} - - function modifyAllocations( - address operator, - AllocateParams[] calldata params - ) external virtual {} - - function clearDeallocationQueue( - address operator, - IStrategy[] calldata strategies, - uint16[] calldata numToClear - ) external virtual {} - - function registerForOperatorSets( - address operator, - RegisterParams calldata params - ) external virtual {} - - function deregisterFromOperatorSets( - DeregisterParams calldata params - ) external virtual {} - - function setAllocationDelay( - address operator, - uint32 delay - ) external virtual {} - - function setAVSRegistrar( - address avs, - IAVSRegistrar registrar - ) external virtual {} - - function updateAVSMetadataURI( - address avs, - string calldata metadataURI - ) external virtual {} - - function createOperatorSets( - address avs, - CreateSetParams[] calldata params - ) external virtual {} - - function addStrategiesToOperatorSet( - address avs, - uint32 operatorSetId, - IStrategy[] calldata strategies - ) external virtual {} - - function removeStrategiesFromOperatorSet( - address avs, - uint32 operatorSetId, - IStrategy[] calldata strategies - ) external virtual {} - - function getOperatorSetCount( - address avs - ) external view virtual returns (uint256) {} - - function getAllocatedSets( - address operator - ) external view virtual returns (OperatorSet[] memory) {} - - function getAllocatedStrategies( - address operator, - OperatorSet memory operatorSet - ) external view virtual returns (IStrategy[] memory) {} - - function getAllocation( - address operator, - OperatorSet memory operatorSet, - IStrategy strategy - ) external view virtual returns (Allocation memory) {} - - function getAllocations( - address[] memory operators, - OperatorSet memory operatorSet, - IStrategy strategy - ) external view virtual returns (Allocation[] memory) {} - - function getStrategyAllocations( - address operator, - IStrategy strategy - ) - external - view - virtual - returns (OperatorSet[] memory, Allocation[] memory) - {} - - function getAllocatableMagnitude( - address operator, - IStrategy strategy - ) external view virtual returns (uint64) {} - - function getMaxMagnitude( - address operator, - IStrategy strategy - ) external view virtual returns (uint64) {} - - function getMaxMagnitudes( - address operator, - IStrategy[] calldata strategies - ) external view virtual returns (uint64[] memory) {} - - function getMaxMagnitudes( - address[] calldata operators, - IStrategy strategy - ) external view virtual returns (uint64[] memory) {} - - function getMaxMagnitudesAtBlock( - address operator, - IStrategy[] calldata strategies, - uint32 blockNumber - ) external view virtual returns (uint64[] memory) {} - - function getAllocationDelay( - address operator - ) external view virtual returns (bool isSet, uint32 delay) {} - - function getRegisteredSets( - address operator - ) external view virtual returns (OperatorSet[] memory operatorSets) {} - - function isOperatorSet( - OperatorSet memory operatorSet - ) external view virtual returns (bool) {} - - function getMembers( - OperatorSet memory operatorSet - ) external view virtual returns (address[] memory operators) {} - - function getMemberCount( - OperatorSet memory operatorSet - ) external view virtual returns (uint256) {} - - function getAVSRegistrar( - address avs - ) external view virtual returns (IAVSRegistrar) {} - - function getStrategiesInOperatorSet( - OperatorSet memory operatorSet - ) external view virtual returns (IStrategy[] memory strategies) {} - - function getMinimumSlashableStake( - OperatorSet memory operatorSet, - address[] memory operators, - IStrategy[] memory strategies, - uint32 futureBlock - ) external view virtual returns (uint256[][] memory slashableStake) {} - - function isMemberOfOperatorSet( - address operator, - OperatorSet memory operatorSet - ) external view virtual returns (bool) {} + function initialize(address initialOwner, uint256 initialPausedStatus) external virtual {} + + function slashOperator(address avs, SlashingParams calldata params) external virtual {} + + function modifyAllocations( + address operator, + AllocateParams[] calldata params + ) external virtual {} + + function clearDeallocationQueue( + address operator, + IStrategy[] calldata strategies, + uint16[] calldata numToClear + ) external virtual {} + + function registerForOperatorSets( + address operator, + RegisterParams calldata params + ) external virtual {} + + function deregisterFromOperatorSets( + DeregisterParams calldata params + ) external virtual {} + + function setAllocationDelay(address operator, uint32 delay) external virtual {} + + function setAVSRegistrar(address avs, IAVSRegistrar registrar) external virtual {} + + function updateAVSMetadataURI(address avs, string calldata metadataURI) external virtual {} + + function createOperatorSets(address avs, CreateSetParams[] calldata params) external virtual {} + + function addStrategiesToOperatorSet( + address avs, + uint32 operatorSetId, + IStrategy[] calldata strategies + ) external virtual {} + + function removeStrategiesFromOperatorSet( + address avs, + uint32 operatorSetId, + IStrategy[] calldata strategies + ) external virtual {} + + function getOperatorSetCount( + address avs + ) external view virtual returns (uint256) {} + + function getAllocatedSets( + address operator + ) external view virtual returns (OperatorSet[] memory) {} + + function getAllocatedStrategies( + address operator, + OperatorSet memory operatorSet + ) external view virtual returns (IStrategy[] memory) {} + + function getAllocation( + address operator, + OperatorSet memory operatorSet, + IStrategy strategy + ) external view virtual returns (Allocation memory) {} + + function getAllocations( + address[] memory operators, + OperatorSet memory operatorSet, + IStrategy strategy + ) external view virtual returns (Allocation[] memory) {} + + function getStrategyAllocations( + address operator, + IStrategy strategy + ) external view virtual returns (OperatorSet[] memory, Allocation[] memory) {} + + function getAllocatableMagnitude( + address operator, + IStrategy strategy + ) external view virtual returns (uint64) {} + + function getMaxMagnitude( + address operator, + IStrategy strategy + ) external view virtual returns (uint64) {} + + function getMaxMagnitudes( + address operator, + IStrategy[] calldata strategies + ) external view virtual returns (uint64[] memory) {} + + function getMaxMagnitudes( + address[] calldata operators, + IStrategy strategy + ) external view virtual returns (uint64[] memory) {} + + function getMaxMagnitudesAtBlock( + address operator, + IStrategy[] calldata strategies, + uint32 blockNumber + ) external view virtual returns (uint64[] memory) {} + + function getAllocationDelay( + address operator + ) external view virtual returns (bool isSet, uint32 delay) {} + + function getRegisteredSets( + address operator + ) external view virtual returns (OperatorSet[] memory operatorSets) {} + + function isOperatorSet( + OperatorSet memory operatorSet + ) external view virtual returns (bool) {} + + function getMembers( + OperatorSet memory operatorSet + ) external view virtual returns (address[] memory operators) {} + + function getMemberCount( + OperatorSet memory operatorSet + ) external view virtual returns (uint256) {} + + function getAVSRegistrar( + address avs + ) external view virtual returns (IAVSRegistrar) {} + + function getStrategiesInOperatorSet( + OperatorSet memory operatorSet + ) external view virtual returns (IStrategy[] memory strategies) {} + + function getMinimumSlashableStake( + OperatorSet memory operatorSet, + address[] memory operators, + IStrategy[] memory strategies, + uint32 futureBlock + ) external view virtual returns (uint256[][] memory slashableStake) {} + + function isMemberOfOperatorSet( + address operator, + OperatorSet memory operatorSet + ) external view virtual returns (bool) {} } -contract AllocationManagerMock is AllocationManagerIntermediate { - -} \ No newline at end of file +contract AllocationManagerMock is AllocationManagerIntermediate {} diff --git a/test/mocks/DelegationMock.sol b/test/mocks/DelegationMock.sol index 36f973da..ff04b970 100644 --- a/test/mocks/DelegationMock.sol +++ b/test/mocks/DelegationMock.sol @@ -4,7 +4,8 @@ pragma solidity ^0.8.27; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {console2 as console} from "forge-std/Test.sol"; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {IDelegationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; import {StrategyManager} from "eigenlayer-contracts/src/contracts/core/StrategyManager.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; @@ -13,265 +14,250 @@ import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISi import {SlashingLib} from "eigenlayer-contracts/src/contracts/libraries/SlashingLib.sol"; contract DelegationIntermediate is IDelegationManager { - function initialize( - address initialOwner, - uint256 initialPausedStatus - ) external virtual {} - - function registerAsOperator( - OperatorDetails calldata registeringOperatorDetails, - uint32 allocationDelay, - string calldata metadataURI - ) external virtual {} - - function modifyOperatorDetails( - OperatorDetails calldata newOperatorDetails - ) external virtual {} - - function updateOperatorMetadataURI( - string calldata metadataURI - ) external virtual {} - - function delegateTo( - address operator, - SignatureWithExpiry memory approverSignatureAndExpiry, - bytes32 approverSalt - ) external virtual {} - - function undelegate( - address staker - ) external virtual returns (bytes32[] memory withdrawalRoots) {} - - function queueWithdrawals( - QueuedWithdrawalParams[] calldata params - ) external virtual returns (bytes32[] memory) {} - - function completeQueuedWithdrawals( - IERC20[][] calldata tokens, - bool[] calldata receiveAsTokens, - uint256 numToComplete - ) external virtual {} - - function completeQueuedWithdrawal( - Withdrawal calldata withdrawal, - IERC20[] calldata tokens, - bool receiveAsTokens - ) external virtual {} - - function completeQueuedWithdrawals( - Withdrawal[] calldata withdrawals, - IERC20[][] calldata tokens, - bool[] calldata receiveAsTokens - ) external virtual {} - - function increaseDelegatedShares( - address staker, - IStrategy strategy, - uint256 existingDepositShares, - uint256 addedShares - ) external virtual {} - - function decreaseBeaconChainScalingFactor( - address staker, - uint256 existingShares, - uint64 proportionOfOldBalance - ) external virtual {} - - function burnOperatorShares( - address operator, - IStrategy strategy, - uint64 prevMaxMagnitude, - uint64 newMaxMagnitude - ) external virtual {} - - function completeQueuedWithdrawal( - Withdrawal calldata withdrawal, - IERC20[] calldata tokens, - uint256 middlewareTimesIndex, - bool receiveAsTokens - ) external virtual {} - - function completeQueuedWithdrawals( - Withdrawal[] calldata withdrawals, - IERC20[][] calldata tokens, - uint256[] calldata middlewareTimesIndexes, - bool[] calldata receiveAsTokens - ) external virtual {} - - function delegatedTo( - address staker - ) external view virtual returns (address) {} - - function delegationApproverSaltIsSpent( - address _delegationApprover, - bytes32 salt - ) external view virtual returns (bool) {} - - function cumulativeWithdrawalsQueued( - address staker - ) external view virtual returns (uint256) {} - - function isDelegated(address staker) external view virtual returns (bool) {} - - function isOperator(address operator) external view virtual returns (bool) {} - - function operatorDetails( - address operator - ) external view virtual returns (OperatorDetails memory) {} - - function delegationApprover( - address operator - ) external view virtual returns (address) {} - - function getOperatorShares( - address operator, - IStrategy[] memory strategies - ) external view virtual returns (uint256[] memory) {} - - function getOperatorsShares( - address[] memory operators, - IStrategy[] memory strategies - ) external view virtual returns (uint256[][] memory) {} - - function getSlashableSharesInQueue( - address operator, - IStrategy strategy - ) external view virtual returns (uint256) {} - - function getWithdrawableShares( - address staker, - IStrategy[] memory strategies - ) - external - view - virtual - override - returns ( - uint256[] memory withdrawableShares, - uint256[] memory depositShares + function initialize(address initialOwner, uint256 initialPausedStatus) external virtual {} + + function registerAsOperator( + OperatorDetails calldata registeringOperatorDetails, + uint32 allocationDelay, + string calldata metadataURI + ) external virtual {} + + function modifyOperatorDetails( + OperatorDetails calldata newOperatorDetails + ) external virtual {} + + function updateOperatorMetadataURI( + string calldata metadataURI + ) external virtual {} + + function delegateTo( + address operator, + SignatureWithExpiry memory approverSignatureAndExpiry, + bytes32 approverSalt + ) external virtual {} + + function undelegate( + address staker + ) external virtual returns (bytes32[] memory withdrawalRoots) {} + + function queueWithdrawals( + QueuedWithdrawalParams[] calldata params + ) external virtual returns (bytes32[] memory) {} + + function completeQueuedWithdrawals( + IERC20[][] calldata tokens, + bool[] calldata receiveAsTokens, + uint256 numToComplete + ) external virtual {} + + function completeQueuedWithdrawal( + Withdrawal calldata withdrawal, + IERC20[] calldata tokens, + bool receiveAsTokens + ) external virtual {} + + function completeQueuedWithdrawals( + Withdrawal[] calldata withdrawals, + IERC20[][] calldata tokens, + bool[] calldata receiveAsTokens + ) external virtual {} + + function increaseDelegatedShares( + address staker, + IStrategy strategy, + uint256 existingDepositShares, + uint256 addedShares + ) external virtual {} + + function decreaseBeaconChainScalingFactor( + address staker, + uint256 existingShares, + uint64 proportionOfOldBalance + ) external virtual {} + + function burnOperatorShares( + address operator, + IStrategy strategy, + uint64 prevMaxMagnitude, + uint64 newMaxMagnitude + ) external virtual {} + + function completeQueuedWithdrawal( + Withdrawal calldata withdrawal, + IERC20[] calldata tokens, + uint256 middlewareTimesIndex, + bool receiveAsTokens + ) external virtual {} + + function completeQueuedWithdrawals( + Withdrawal[] calldata withdrawals, + IERC20[][] calldata tokens, + uint256[] calldata middlewareTimesIndexes, + bool[] calldata receiveAsTokens + ) external virtual {} + + function delegatedTo( + address staker + ) external view virtual returns (address) {} + + function delegationApproverSaltIsSpent( + address _delegationApprover, + bytes32 salt + ) external view virtual returns (bool) {} + + function cumulativeWithdrawalsQueued( + address staker + ) external view virtual returns (uint256) {} + + function isDelegated( + address staker + ) external view virtual returns (bool) {} + + function isOperator( + address operator + ) external view virtual returns (bool) {} + + function operatorDetails( + address operator + ) external view virtual returns (OperatorDetails memory) {} + + function delegationApprover( + address operator + ) external view virtual returns (address) {} + + function getOperatorShares( + address operator, + IStrategy[] memory strategies + ) external view virtual returns (uint256[] memory) {} + + function getOperatorsShares( + address[] memory operators, + IStrategy[] memory strategies + ) external view virtual returns (uint256[][] memory) {} + + function getSlashableSharesInQueue( + address operator, + IStrategy strategy + ) external view virtual returns (uint256) {} + + function getWithdrawableShares( + address staker, + IStrategy[] memory strategies + ) + external + view + virtual + override + returns (uint256[] memory withdrawableShares, uint256[] memory depositShares) + {} + + function getDepositedShares( + address staker + ) external view virtual returns (IStrategy[] memory, uint256[] memory) {} + + function depositScalingFactor( + address staker, + IStrategy strategy + ) external view virtual returns (uint256) {} + + function getBeaconChainSlashingFactor( + address staker + ) external view virtual returns (uint64) {} + + function getQueuedWithdrawals( + address staker ) - {} - - function getDepositedShares( - address staker - ) external view virtual returns (IStrategy[] memory, uint256[] memory) {} - - function depositScalingFactor( - address staker, - IStrategy strategy - ) external view virtual returns (uint256) {} - - function getBeaconChainSlashingFactor( - address staker - ) external view virtual returns (uint64) {} - - function getQueuedWithdrawals( - address staker - ) - external - view - virtual - override - returns (Withdrawal[] memory withdrawals, uint256[][] memory shares) - {} - - function calculateWithdrawalRoot( - Withdrawal memory withdrawal - ) external pure virtual returns (bytes32) {} - - function calculateDelegationApprovalDigestHash( - address staker, - address operator, - address _delegationApprover, - bytes32 approverSalt, - uint256 expiry - ) external view virtual returns (bytes32) {} - - function beaconChainETHStrategy() - external - view - virtual - override - returns (IStrategy) - {} - - function DELEGATION_APPROVAL_TYPEHASH() - external - view - virtual - override - returns (bytes32) - {} - - function registerAsOperator( - address initDelegationApprover, - uint32 allocationDelay, - string calldata metadataURI - ) external virtual {} - - function modifyOperatorDetails( - address operator, - address newDelegationApprover - ) external virtual {} - - function updateOperatorMetadataURI( - address operator, - string calldata metadataURI - ) external virtual {} - - function redelegate( - address newOperator, - SignatureWithExpiry memory newOperatorApproverSig, - bytes32 approverSalt - ) external virtual returns (bytes32[] memory withdrawalRoots) {} - - function decreaseDelegatedShares( - address staker, - uint256 curDepositShares, - uint64 prevBeaconChainSlashingFactor, - uint256 wadSlashed - ) external virtual {} - - function decreaseDelegatedShares( - address staker, - uint256 curDepositShares, - uint64 beaconChainSlashingFactorDecrease - ) external virtual {} - - function minWithdrawalDelayBlocks() - external - view - virtual - override - returns (uint32) - {} - - function slashOperatorShares( - address operator, - IStrategy strategy, - uint64 prevMaxMagnitude, - uint64 newMaxMagnitude - ) external override {} - - function getQueuedWithdrawal( - bytes32 withdrawalRoot - ) external view override returns (Withdrawal memory) {} - - function getQueuedWithdrawalRoots( - address staker - ) external view override returns (bytes32[] memory) {} - - function convertToDepositShares( - address staker, - IStrategy[] memory strategies, - uint256[] memory withdrawableShares - ) external view override returns (uint256[] memory) {} + external + view + virtual + override + returns (Withdrawal[] memory withdrawals, uint256[][] memory shares) + {} + + function calculateWithdrawalRoot( + Withdrawal memory withdrawal + ) external pure virtual returns (bytes32) {} + + function calculateDelegationApprovalDigestHash( + address staker, + address operator, + address _delegationApprover, + bytes32 approverSalt, + uint256 expiry + ) external view virtual returns (bytes32) {} + + function beaconChainETHStrategy() external view virtual override returns (IStrategy) {} + + function DELEGATION_APPROVAL_TYPEHASH() external view virtual override returns (bytes32) {} + + function registerAsOperator( + address initDelegationApprover, + uint32 allocationDelay, + string calldata metadataURI + ) external virtual {} + + function modifyOperatorDetails( + address operator, + address newDelegationApprover + ) external virtual {} + + function updateOperatorMetadataURI( + address operator, + string calldata metadataURI + ) external virtual {} + + function redelegate( + address newOperator, + SignatureWithExpiry memory newOperatorApproverSig, + bytes32 approverSalt + ) external virtual returns (bytes32[] memory withdrawalRoots) {} + + function decreaseDelegatedShares( + address staker, + uint256 curDepositShares, + uint64 prevBeaconChainSlashingFactor, + uint256 wadSlashed + ) external virtual {} + + function decreaseDelegatedShares( + address staker, + uint256 curDepositShares, + uint64 beaconChainSlashingFactorDecrease + ) external virtual {} + + function minWithdrawalDelayBlocks() external view virtual override returns (uint32) {} + + function slashOperatorShares( + address operator, + IStrategy strategy, + uint64 prevMaxMagnitude, + uint64 newMaxMagnitude + ) external override {} + + function getQueuedWithdrawal( + bytes32 withdrawalRoot + ) external view override returns (Withdrawal memory) {} + + function getQueuedWithdrawalRoots( + address staker + ) external view override returns (bytes32[] memory) {} + + function convertToDepositShares( + address staker, + IStrategy[] memory strategies, + uint256[] memory withdrawableShares + ) external view override returns (uint256[] memory) {} } contract DelegationMock is DelegationIntermediate { mapping(address => bool) internal _isOperator; mapping(address => mapping(IStrategy => uint256)) internal _weightOf; - function setOperatorShares(address operator, IStrategy strategy, uint256 actualWeight) external { + + function setOperatorShares( + address operator, + IStrategy strategy, + uint256 actualWeight + ) external { _weightOf[operator][strategy] = actualWeight; } @@ -279,7 +265,9 @@ contract DelegationMock is DelegationIntermediate { _isOperator[operator] = isOperator; } - function isOperator(address operator) external view override returns (bool) { + function isOperator( + address operator + ) external view override returns (bool) { return _isOperator[operator]; } @@ -293,7 +281,8 @@ contract DelegationMock is DelegationIntermediate { } return shares; } - function minWithdrawalDelayBlocks() external view override returns (uint32){ - return 10000; + + function minWithdrawalDelayBlocks() external view override returns (uint32) { + return 10_000; } -} \ No newline at end of file +} diff --git a/test/mocks/ECDSAServiceManagerMock.sol b/test/mocks/ECDSAServiceManagerMock.sol index df93cdd1..488e5eef 100644 --- a/test/mocks/ECDSAServiceManagerMock.sol +++ b/test/mocks/ECDSAServiceManagerMock.sol @@ -2,7 +2,8 @@ pragma solidity ^0.8.27; import "../../src/unaudited/ECDSAServiceManagerBase.sol"; -import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManagerTypes} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; contract ECDSAServiceManagerMock is ECDSAServiceManagerBase { constructor( @@ -28,21 +29,19 @@ contract ECDSAServiceManagerMock is ECDSAServiceManagerBase { __ServiceManagerBase_init(initialOwner, rewardsInitiator); } - function addPendingAdmin(address admin) external {} - - function removePendingAdmin(address pendingAdmin) external {} - - function removeAdmin(address admin) external {} + function addPendingAdmin( + address admin + ) external {} - function setAppointee( - address appointee, - address target, - bytes4 selector + function removePendingAdmin( + address pendingAdmin ) external {} - function removeAppointee( - address appointee, - address target, - bytes4 selector + function removeAdmin( + address admin ) external {} + + function setAppointee(address appointee, address target, bytes4 selector) external {} + + function removeAppointee(address appointee, address target, bytes4 selector) external {} } diff --git a/test/mocks/ECDSAStakeRegistryMock.sol b/test/mocks/ECDSAStakeRegistryMock.sol index e2b756be..fb43079b 100644 --- a/test/mocks/ECDSAStakeRegistryMock.sol +++ b/test/mocks/ECDSAStakeRegistryMock.sol @@ -8,7 +8,7 @@ import "../../src/unaudited/ECDSAStakeRegistry.sol"; * @dev This contract is a mock implementation of the ECDSAStakeRegistry for testing purposes. */ contract ECDSAStakeRegistryMock is ECDSAStakeRegistry { - - constructor(IDelegationManager _delegationManager) ECDSAStakeRegistry(_delegationManager) { - } + constructor( + IDelegationManager _delegationManager + ) ECDSAStakeRegistry(_delegationManager) {} } diff --git a/test/mocks/EigenPodManagerMock.sol b/test/mocks/EigenPodManagerMock.sol index 700d1840..dccdbef8 100644 --- a/test/mocks/EigenPodManagerMock.sol +++ b/test/mocks/EigenPodManagerMock.sol @@ -11,11 +11,15 @@ contract EigenPodManagerMock is Test, Pausable, IEigenPodManager { mapping(address => int256) public podShares; - constructor(IPauserRegistry _pauserRegistry) Pausable(_pauserRegistry){ + constructor( + IPauserRegistry _pauserRegistry + ) Pausable(_pauserRegistry) { _setPausedStatus(0); } - function podOwnerShares(address podOwner) external view returns (int256) { + function podOwnerShares( + address podOwner + ) external view returns (int256) { return podShares[podOwner]; } @@ -27,77 +31,82 @@ contract EigenPodManagerMock is Test, Pausable, IEigenPodManager { return type(uint64).max; } - function createPod() external returns (address) { - } + function createPod() external returns (address) {} - function stake(bytes calldata pubkey, bytes calldata signature, bytes32 depositDataRoot) external payable { - } + function stake( + bytes calldata pubkey, + bytes calldata signature, + bytes32 depositDataRoot + ) external payable {} function recordBeaconChainETHBalanceUpdate( address podOwner, int256 sharesDelta, uint64 proportionPodBalanceDecrease - ) external { - } + ) external {} - function ownerToPod(address podOwner) external view returns (IEigenPod) { - } + function ownerToPod( + address podOwner + ) external view returns (IEigenPod) {} - function getPod(address podOwner) external view returns (IEigenPod) { - } + function getPod( + address podOwner + ) external view returns (IEigenPod) {} - function ethPOS() external view returns (IETHPOSDeposit) { - } + function ethPOS() external view returns (IETHPOSDeposit) {} - function eigenPodBeacon() external view returns (IBeacon) { - } + function eigenPodBeacon() external view returns (IBeacon) {} - function strategyManager() external view returns (IStrategyManager) { - } + function strategyManager() external view returns (IStrategyManager) {} - function hasPod(address podOwner) external view returns (bool) { - } + function hasPod( + address podOwner + ) external view returns (bool) {} - function numPods() external view returns (uint256) { - } + function numPods() external view returns (uint256) {} - function podOwnerDepositShares(address podOwner) external view returns (int256) { - } + function podOwnerDepositShares( + address podOwner + ) external view returns (int256) {} - function beaconChainETHStrategy() external view returns (IStrategy) { - } + function beaconChainETHStrategy() external view returns (IStrategy) {} - function removeDepositShares(address staker, IStrategy strategy, uint256 depositSharesToRemove) external { - } + function removeDepositShares( + address staker, + IStrategy strategy, + uint256 depositSharesToRemove + ) external {} - function stakerDepositShares(address user, IStrategy strategy) external view returns (uint256 depositShares) { - } + function stakerDepositShares( + address user, + IStrategy strategy + ) external view returns (uint256 depositShares) {} - function withdrawSharesAsTokens(address staker, IStrategy strategy, IERC20 token, uint256 shares) external{} + function withdrawSharesAsTokens( + address staker, + IStrategy strategy, + IERC20 token, + uint256 shares + ) external {} function addShares( address staker, IStrategy strategy, IERC20 token, uint256 shares - ) external returns (uint256, uint256) { - } + ) external returns (uint256, uint256) {} function beaconChainSlashingFactor( address staker - ) external view returns (uint64) { - } + ) external view returns (uint64) {} function recordBeaconChainETHBalanceUpdate( address podOwner, uint256 prevRestakedBalanceWei, int256 balanceDeltaWei - ) external { - } + ) external {} - function burnableETHShares() external view returns (uint256) { - } + function burnableETHShares() external view returns (uint256) {} - function increaseBurnableShares(IStrategy strategy, uint256 addedSharesToBurn) external { - } -} \ No newline at end of file + function increaseBurnableShares(IStrategy strategy, uint256 addedSharesToBurn) external {} +} diff --git a/test/mocks/PermissionControllerMock.sol b/test/mocks/PermissionControllerMock.sol index 9a9eca00..11452675 100644 --- a/test/mocks/PermissionControllerMock.sol +++ b/test/mocks/PermissionControllerMock.sol @@ -1,73 +1,71 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IPermissionController} from "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; +import {IPermissionController} from + "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; contract PermissionControllerIntermediate is IPermissionController { - function addPendingAdmin(address account, address admin) external virtual {} - - function removePendingAdmin( - address account, - address admin - ) external virtual {} - - function acceptAdmin(address account) external virtual {} - - function removeAdmin(address account, address admin) external virtual {} - - function setAppointee( - address account, - address appointee, - address target, - bytes4 selector - ) external virtual {} - - function removeAppointee( - address account, - address appointee, - address target, - bytes4 selector - ) external virtual {} - - function isAdmin( - address account, - address caller - ) external view virtual returns (bool) {} - - function isPendingAdmin( - address account, - address pendingAdmin - ) external view virtual returns (bool) {} - - function getAdmins( - address account - ) external view virtual returns (address[] memory) {} - - function getPendingAdmins( - address account - ) external view virtual returns (address[] memory) {} - - function canCall( - address account, - address caller, - address target, - bytes4 selector - ) external virtual returns (bool) {} - - function getAppointeePermissions( - address account, - address appointee - ) external virtual returns (address[] memory, bytes4[] memory) {} - - function getAppointees( - address account, - address target, - bytes4 selector - ) external virtual returns (address[] memory) {} + function addPendingAdmin(address account, address admin) external virtual {} + + function removePendingAdmin(address account, address admin) external virtual {} + + function acceptAdmin( + address account + ) external virtual {} + + function removeAdmin(address account, address admin) external virtual {} + + function setAppointee( + address account, + address appointee, + address target, + bytes4 selector + ) external virtual {} + + function removeAppointee( + address account, + address appointee, + address target, + bytes4 selector + ) external virtual {} + + function isAdmin(address account, address caller) external view virtual returns (bool) {} + + function isPendingAdmin( + address account, + address pendingAdmin + ) external view virtual returns (bool) {} + + function getAdmins( + address account + ) external view virtual returns (address[] memory) {} + + function getPendingAdmins( + address account + ) external view virtual returns (address[] memory) {} + + function canCall( + address account, + address caller, + address target, + bytes4 selector + ) external virtual returns (bool) {} + + function getAppointeePermissions( + address account, + address appointee + ) external virtual returns (address[] memory, bytes4[] memory) {} + + function getAppointees( + address account, + address target, + bytes4 selector + ) external virtual returns (address[] memory) {} } contract PermissionControllerMock is PermissionControllerIntermediate { - mapping(address => mapping(address => mapping(address => mapping(bytes4 => bool)))) internal _canCall; + mapping(address => mapping(address => mapping(address => mapping(bytes4 => bool)))) internal + _canCall; function setCanCall( address account, @@ -87,5 +85,4 @@ contract PermissionControllerMock is PermissionControllerIntermediate { if (account == caller) return true; return _canCall[account][caller][target][selector]; } - } diff --git a/test/mocks/RegistryCoordinatorMock.sol b/test/mocks/RegistryCoordinatorMock.sol index 165a649d..d0464db2 100644 --- a/test/mocks/RegistryCoordinatorMock.sol +++ b/test/mocks/RegistryCoordinatorMock.sol @@ -1,19 +1,16 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; - import "../../src/interfaces/IRegistryCoordinator.sol"; - contract RegistryCoordinatorMock is IRegistryCoordinator { function blsApkRegistry() external view returns (IBLSApkRegistry) {} - function ejectOperator( - address operator, - bytes calldata quorumNumbers - ) external {} + function ejectOperator(address operator, bytes calldata quorumNumbers) external {} - function getOperatorSetParams(uint8 quorumNumber) external view returns (OperatorSetParam memory) {} + function getOperatorSetParams( + uint8 quorumNumber + ) external view returns (OperatorSetParam memory) {} function indexRegistry() external view returns (IIndexRegistry) {} @@ -21,61 +18,93 @@ contract RegistryCoordinatorMock is IRegistryCoordinator { function quorumCount() external view returns (uint8) {} /// @notice Returns the bitmap of the quorums the operator is registered for. - function operatorIdToQuorumBitmap(bytes32 pubkeyHash) external view returns (uint256){} + function operatorIdToQuorumBitmap( + bytes32 pubkeyHash + ) external view returns (uint256) {} - function getOperator(address operator) external view returns (OperatorInfo memory){} + function getOperator( + address operator + ) external view returns (OperatorInfo memory) {} /// @notice Returns the stored id for the specified `operator`. - function getOperatorId(address operator) external view returns (bytes32){} + function getOperatorId( + address operator + ) external view returns (bytes32) {} /// @notice Returns the operator address for the given `operatorId` - function getOperatorFromId(bytes32 operatorId) external view returns (address) {} + function getOperatorFromId( + bytes32 operatorId + ) external view returns (address) {} /// @notice Returns the status for the given `operator` - function getOperatorStatus(address operator) external view returns (IRegistryCoordinator.OperatorStatus){} + function getOperatorStatus( + address operator + ) external view returns (IRegistryCoordinator.OperatorStatus) {} /// @notice Returns task number from when `operator` has been registered. - function getFromTaskNumberForOperator(address operator) external view returns (uint32){} + function getFromTaskNumberForOperator( + address operator + ) external view returns (uint32) {} - function getQuorumBitmapIndicesAtBlockNumber(uint32 blockNumber, bytes32[] memory operatorIds) external view returns (uint32[] memory){} + function getQuorumBitmapIndicesAtBlockNumber( + uint32 blockNumber, + bytes32[] memory operatorIds + ) external view returns (uint32[] memory) {} /// @notice Returns the quorum bitmap for the given `operatorId` at the given `blockNumber` via the `index` - function getQuorumBitmapAtBlockNumberByIndex(bytes32 operatorId, uint32 blockNumber, uint256 index) external view returns (uint192) {} + function getQuorumBitmapAtBlockNumberByIndex( + bytes32 operatorId, + uint32 blockNumber, + uint256 index + ) external view returns (uint192) {} /// @notice Returns the `index`th entry in the operator with `operatorId`'s bitmap history - function getQuorumBitmapUpdateByIndex(bytes32 operatorId, uint256 index) external view returns (QuorumBitmapUpdate memory) {} + function getQuorumBitmapUpdateByIndex( + bytes32 operatorId, + uint256 index + ) external view returns (QuorumBitmapUpdate memory) {} /// @notice Returns the current quorum bitmap for the given `operatorId` - function getCurrentQuorumBitmap(bytes32 operatorId) external view returns (uint192) {} + function getCurrentQuorumBitmap( + bytes32 operatorId + ) external view returns (uint192) {} /// @notice Returns the length of the quorum bitmap history for the given `operatorId` - function getQuorumBitmapHistoryLength(bytes32 operatorId) external view returns (uint256) {} + function getQuorumBitmapHistoryLength( + bytes32 operatorId + ) external view returns (uint256) {} - function numRegistries() external view returns (uint256){} + function numRegistries() external view returns (uint256) {} - function registries(uint256) external view returns (address){} + function registries( + uint256 + ) external view returns (address) {} function registerOperator(bytes memory quorumNumbers, bytes calldata) external {} function deregisterOperator(bytes calldata quorumNumbers, bytes calldata) external {} - function pubkeyRegistrationMessageHash(address operator) public view returns (BN254.G1Point memory) { - return BN254.hashToG1( - keccak256(abi.encode(operator)) - ); + function pubkeyRegistrationMessageHash( + address operator + ) public view returns (BN254.G1Point memory) { + return BN254.hashToG1(keccak256(abi.encode(operator))); } - function quorumUpdateBlockNumber(uint8 quorumNumber) external view returns (uint256) {} + function quorumUpdateBlockNumber( + uint8 quorumNumber + ) external view returns (uint256) {} function owner() external view returns (address) {} - function serviceManager() external view returns (IServiceManager){} + function serviceManager() external view returns (IServiceManager) {} - function isM2Quorum(uint8 quorumNumber) external view returns (bool) { + function isM2Quorum( + uint8 quorumNumber + ) external view returns (bool) { return false; } function isOperatorSetAVS() external view returns (bool) { return false; } -} \ No newline at end of file +} diff --git a/test/mocks/RewardsCoordinatorMock.sol b/test/mocks/RewardsCoordinatorMock.sol index 9d992962..b16f7cc5 100644 --- a/test/mocks/RewardsCoordinatorMock.sol +++ b/test/mocks/RewardsCoordinatorMock.sol @@ -4,168 +4,142 @@ pragma solidity ^0.8.27; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; -import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import {IRewardsCoordinator} from + "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; import "./AVSDirectoryMock.sol"; contract RewardsCoordinatorMock is IRewardsCoordinator { - function initialize( - address initialOwner, - uint256 initialPausedStatus, - address _rewardsUpdater, - uint32 _activationDelay, - uint16 _defaultSplitBips - ) external override {} - - function createAVSRewardsSubmission( - RewardsSubmission[] calldata rewardsSubmissions - ) external override {} - - function createRewardsForAllSubmission( - RewardsSubmission[] calldata rewardsSubmissions - ) external override {} - - function createRewardsForAllEarners( - RewardsSubmission[] calldata rewardsSubmissions - ) external override {} - - function createOperatorDirectedAVSRewardsSubmission( - address avs, - OperatorDirectedRewardsSubmission[] - calldata operatorDirectedRewardsSubmissions - ) external override {} - - function processClaim( - RewardsMerkleClaim calldata claim, - address recipient - ) external override {} - - function processClaims( - RewardsMerkleClaim[] calldata claims, - address recipient - ) external override {} - - function submitRoot( - bytes32 root, - uint32 rewardsCalculationEndTimestamp - ) external override {} - - function disableRoot(uint32 rootIndex) external override {} - - function setClaimerFor(address claimer) external override {} - - function setClaimerFor(address earner, address claimer) external override {} - - function setActivationDelay(uint32 _activationDelay) external override {} - - function setDefaultOperatorSplit(uint16 split) external override {} - - function setOperatorAVSSplit( - address operator, - address avs, - uint16 split - ) external override {} - - function setOperatorPISplit( - address operator, - uint16 split - ) external override {} - - function setRewardsUpdater(address _rewardsUpdater) external override {} - - function setRewardsForAllSubmitter( - address _submitter, - bool _newValue - ) external override {} - - function activationDelay() external view override returns (uint32) {} - - function currRewardsCalculationEndTimestamp() - external - view - override - returns (uint32) - {} - - function claimerFor( - address earner - ) external view override returns (address) {} - - function cumulativeClaimed( - address claimer, - IERC20 token - ) external view override returns (uint256) {} - - function defaultOperatorSplitBips() external view override returns (uint16) {} - - function getOperatorAVSSplit( - address operator, - address avs - ) external view override returns (uint16) {} - - function getOperatorPISplit( - address operator - ) external view override returns (uint16) {} - - function calculateEarnerLeafHash( - EarnerTreeMerkleLeaf calldata leaf - ) external pure override returns (bytes32) {} - - function calculateTokenLeafHash( - TokenTreeMerkleLeaf calldata leaf - ) external pure override returns (bytes32) {} - - function checkClaim( - RewardsMerkleClaim calldata claim - ) external view override returns (bool) {} - - function getDistributionRootsLength() - external - view - override - returns (uint256) - {} - - function getDistributionRootAtIndex( - uint256 index - ) external view override returns (DistributionRoot memory) {} - - function getCurrentDistributionRoot() - external - view - override - returns (DistributionRoot memory) - {} - - function getCurrentClaimableDistributionRoot() - external - view - override - returns (DistributionRoot memory) - {} + function initialize( + address initialOwner, + uint256 initialPausedStatus, + address _rewardsUpdater, + uint32 _activationDelay, + uint16 _defaultSplitBips + ) external override {} - function getRootIndexFromHash( - bytes32 rootHash - ) external view override returns (uint32) {} + function createAVSRewardsSubmission( + RewardsSubmission[] calldata rewardsSubmissions + ) external override {} - function rewardsUpdater() external view override returns (address) {} + function createRewardsForAllSubmission( + RewardsSubmission[] calldata rewardsSubmissions + ) external override {} - function CALCULATION_INTERVAL_SECONDS() - external - view - override - returns (uint32) - {} - - function MAX_REWARDS_DURATION() external view override returns (uint32) {} - - function MAX_RETROACTIVE_LENGTH() external view override returns (uint32) {} - - function MAX_FUTURE_LENGTH() external view override returns (uint32) {} - - function GENESIS_REWARDS_TIMESTAMP() - external - view - override - returns (uint32) - {} -} \ No newline at end of file + function createRewardsForAllEarners( + RewardsSubmission[] calldata rewardsSubmissions + ) external override {} + + function createOperatorDirectedAVSRewardsSubmission( + address avs, + OperatorDirectedRewardsSubmission[] calldata operatorDirectedRewardsSubmissions + ) external override {} + + function processClaim(RewardsMerkleClaim calldata claim, address recipient) external override {} + + function processClaims( + RewardsMerkleClaim[] calldata claims, + address recipient + ) external override {} + + function submitRoot(bytes32 root, uint32 rewardsCalculationEndTimestamp) external override {} + + function disableRoot( + uint32 rootIndex + ) external override {} + + function setClaimerFor( + address claimer + ) external override {} + + function setClaimerFor(address earner, address claimer) external override {} + + function setActivationDelay( + uint32 _activationDelay + ) external override {} + + function setDefaultOperatorSplit( + uint16 split + ) external override {} + + function setOperatorAVSSplit(address operator, address avs, uint16 split) external override {} + + function setOperatorPISplit(address operator, uint16 split) external override {} + + function setRewardsUpdater( + address _rewardsUpdater + ) external override {} + + function setRewardsForAllSubmitter(address _submitter, bool _newValue) external override {} + + function activationDelay() external view override returns (uint32) {} + + function currRewardsCalculationEndTimestamp() external view override returns (uint32) {} + + function claimerFor( + address earner + ) external view override returns (address) {} + + function cumulativeClaimed( + address claimer, + IERC20 token + ) external view override returns (uint256) {} + + function defaultOperatorSplitBips() external view override returns (uint16) {} + + function getOperatorAVSSplit( + address operator, + address avs + ) external view override returns (uint16) {} + + function getOperatorPISplit( + address operator + ) external view override returns (uint16) {} + + function calculateEarnerLeafHash( + EarnerTreeMerkleLeaf calldata leaf + ) external pure override returns (bytes32) {} + + function calculateTokenLeafHash( + TokenTreeMerkleLeaf calldata leaf + ) external pure override returns (bytes32) {} + + function checkClaim( + RewardsMerkleClaim calldata claim + ) external view override returns (bool) {} + + function getDistributionRootsLength() external view override returns (uint256) {} + + function getDistributionRootAtIndex( + uint256 index + ) external view override returns (DistributionRoot memory) {} + + function getCurrentDistributionRoot() + external + view + override + returns (DistributionRoot memory) + {} + + function getCurrentClaimableDistributionRoot() + external + view + override + returns (DistributionRoot memory) + {} + + function getRootIndexFromHash( + bytes32 rootHash + ) external view override returns (uint32) {} + + function rewardsUpdater() external view override returns (address) {} + + function CALCULATION_INTERVAL_SECONDS() external view override returns (uint32) {} + + function MAX_REWARDS_DURATION() external view override returns (uint32) {} + + function MAX_RETROACTIVE_LENGTH() external view override returns (uint32) {} + + function MAX_FUTURE_LENGTH() external view override returns (uint32) {} + + function GENESIS_REWARDS_TIMESTAMP() external view override returns (uint32) {} +} diff --git a/test/mocks/StakeRegistryMock.sol b/test/mocks/StakeRegistryMock.sol index 58f46256..a70c8f13 100644 --- a/test/mocks/StakeRegistryMock.sol +++ b/test/mocks/StakeRegistryMock.sol @@ -12,7 +12,9 @@ contract StakeRegistryMock is IStakeRegistry { // bitmap returned by the mocked `updateOperatorStake` function uint192 updateOperatorStakeReturnBitmap; - function set_updateOperatorStakeReturnBitmap(uint192 newValue) external { + function set_updateOperatorStakeReturnBitmap( + uint192 newValue + ) external { updateOperatorStakeReturnBitmap = newValue; } @@ -67,14 +69,15 @@ contract StakeRegistryMock is IStakeRegistry { /** * @notice Initialize a new quorum created by the registry coordinator by setting strategies, weights, and minimum stake */ - function initializeQuorum(uint8 quorumNumber, uint96 minimumStake, StrategyParams[] memory strategyParams) external {} - - /// @notice Adds new strategies and the associated multipliers to the @param quorumNumber. - function addStrategies( + function initializeQuorum( uint8 quorumNumber, + uint96 minimumStake, StrategyParams[] memory strategyParams ) external {} + /// @notice Adds new strategies and the associated multipliers to the @param quorumNumber. + function addStrategies(uint8 quorumNumber, StrategyParams[] memory strategyParams) external {} + /** * @notice This function is used for removing strategies and their associated weights from the * mapping strategiesConsideredAndMultipliers for a specific @param quorumNumber. @@ -100,10 +103,14 @@ contract StakeRegistryMock is IStakeRegistry { function WEIGHTING_DIVISOR() external pure returns (uint256) {} - function strategyParamsLength(uint8 quorumNumber) external view returns (uint256) {} + function strategyParamsLength( + uint8 quorumNumber + ) external view returns (uint256) {} /// @notice In order to register for a quorum i, an operator must have at least `minimumStakeForQuorum[i]` - function minimumStakeForQuorum(uint8 quorumNumber) external view returns (uint96) {} + function minimumStakeForQuorum( + uint8 quorumNumber + ) external view returns (uint96) {} /// @notice Returns the strategy and weight multiplier for the `index`'th strategy in the quorum `quorumNumber` function strategyParamsByIndex( @@ -115,32 +122,47 @@ contract StakeRegistryMock is IStakeRegistry { * @notice This function computes the total weight of the @param operator in the quorum @param quorumNumber. * @dev reverts in the case that `quorumNumber` is greater than or equal to `quorumCount` */ - function weightOfOperatorForQuorum(uint8 quorumNumber, address operator) external view returns (uint96) {} + function weightOfOperatorForQuorum( + uint8 quorumNumber, + address operator + ) external view returns (uint96) {} /** * @notice Returns the entire `operatorIdToStakeHistory[operatorId][quorumNumber]` array. * @param operatorId The id of the operator of interest. * @param quorumNumber The quorum number to get the stake for. */ - function getStakeHistory(bytes32 operatorId, uint8 quorumNumber) external view returns (StakeUpdate[] memory) {} + function getStakeHistory( + bytes32 operatorId, + uint8 quorumNumber + ) external view returns (StakeUpdate[] memory) {} - function getTotalStakeHistoryLength(uint8 quorumNumber) external view returns (uint256) {} + function getTotalStakeHistoryLength( + uint8 quorumNumber + ) external view returns (uint256) {} /** * @notice Returns the `index`-th entry in the dynamic array of total stake, `totalStakeHistory` for quorum `quorumNumber`. * @param quorumNumber The quorum number to get the stake for. * @param index Array index for lookup, within the dynamic array `totalStakeHistory[quorumNumber]`. */ - function getTotalStakeUpdateAtIndex(uint8 quorumNumber, uint256 index) external view returns (StakeUpdate memory) {} + function getTotalStakeUpdateAtIndex( + uint8 quorumNumber, + uint256 index + ) external view returns (StakeUpdate memory) {} /// @notice Returns the indices of the operator stakes for the provided `quorumNumber` at the given `blockNumber` - function getStakeUpdateIndexAtBlockNumber(bytes32 operatorId, uint8 quorumNumber, uint32 blockNumber) - external - view - returns (uint32) {} + function getStakeUpdateIndexAtBlockNumber( + bytes32 operatorId, + uint8 quorumNumber, + uint32 blockNumber + ) external view returns (uint32) {} /// @notice Returns the indices of the total stakes for the provided `quorumNumbers` at the given `blockNumber` - function getTotalStakeIndicesAtBlockNumber(uint32 blockNumber, bytes calldata quorumNumbers) external view returns(uint32[] memory) {} + function getTotalStakeIndicesAtBlockNumber( + uint32 blockNumber, + bytes calldata quorumNumbers + ) external view returns (uint32[] memory) {} /** * @notice Returns the `index`-th entry in the `operatorIdToStakeHistory[operatorId][quorumNumber]` array. @@ -149,16 +171,20 @@ contract StakeRegistryMock is IStakeRegistry { * @param index Array index for lookup, within the dynamic array `operatorIdToStakeHistory[operatorId][quorumNumber]`. * @dev Function will revert if `index` is out-of-bounds. */ - function getStakeUpdateAtIndex(uint8 quorumNumber, bytes32 operatorId, uint256 index) - external - view - returns (StakeUpdate memory) {} + function getStakeUpdateAtIndex( + uint8 quorumNumber, + bytes32 operatorId, + uint256 index + ) external view returns (StakeUpdate memory) {} /** * @notice Returns the most recent stake weight for the `operatorId` for a certain quorum * @dev Function returns an StakeUpdate struct with **every entry equal to 0** in the event that the operator has no stake history */ - function getLatestStakeUpdate(bytes32 operatorId, uint8 quorumNumber) external view returns (StakeUpdate memory) {} + function getLatestStakeUpdate( + bytes32 operatorId, + uint8 quorumNumber + ) external view returns (StakeUpdate memory) {} /** * @notice Returns the stake weight corresponding to `operatorId` for quorum `quorumNumber`, at the @@ -171,10 +197,12 @@ contract StakeRegistryMock is IStakeRegistry { * @dev Function will revert if `index` is out-of-bounds. * @dev used the BLSSignatureChecker to get past stakes of signing operators */ - function getStakeAtBlockNumberAndIndex(uint8 quorumNumber, uint32 blockNumber, bytes32 operatorId, uint256 index) - external - view - returns (uint96) {} + function getStakeAtBlockNumberAndIndex( + uint8 quorumNumber, + uint32 blockNumber, + bytes32 operatorId, + uint256 index + ) external view returns (uint96) {} /** * @notice Returns the total stake weight for quorum `quorumNumber`, at the `index`-th entry in the @@ -186,25 +214,35 @@ contract StakeRegistryMock is IStakeRegistry { * @dev Function will revert if `index` is out-of-bounds. * @dev used the BLSSignatureChecker to get past stakes of signing operators */ - function getTotalStakeAtBlockNumberFromIndex(uint8 quorumNumber, uint32 blockNumber, uint256 index) external view returns (uint96) {} + function getTotalStakeAtBlockNumberFromIndex( + uint8 quorumNumber, + uint32 blockNumber, + uint256 index + ) external view returns (uint96) {} /** * @notice Returns the most recent stake weight for the `operatorId` for quorum `quorumNumber` * @dev Function returns weight of **0** in the event that the operator has no stake history */ - function getCurrentStake(bytes32 operatorId, uint8 quorumNumber) external view returns (uint96) {} + function getCurrentStake( + bytes32 operatorId, + uint8 quorumNumber + ) external view returns (uint96) {} /// @notice Returns the stake of the operator for the provided `quorumNumber` at the given `blockNumber` - function getStakeAtBlockNumber(bytes32 operatorId, uint8 quorumNumber, uint32 blockNumber) - external - view - returns (uint96){} + function getStakeAtBlockNumber( + bytes32 operatorId, + uint8 quorumNumber, + uint32 blockNumber + ) external view returns (uint96) {} /** * @notice Returns the stake weight from the latest entry in `_totalStakeHistory` for quorum `quorumNumber`. * @dev Will revert if `_totalStakeHistory[quorumNumber]` is empty. */ - function getCurrentTotalStake(uint8 quorumNumber) external view returns (uint96) {} + function getCurrentTotalStake( + uint8 quorumNumber + ) external view returns (uint96) {} /** * @notice Called by the registry coordinator to update an operator's stake for one @@ -214,14 +252,16 @@ contract StakeRegistryMock is IStakeRegistry { * added to the */ function updateOperatorStake( - address /*operator*/, - bytes32 /*operatorId*/, + address, /*operator*/ + bytes32, /*operatorId*/ bytes calldata /*quorumNumbers*/ ) external returns (uint192) { return updateOperatorStakeReturnBitmap; } - function getMockOperatorId(address operator) external pure returns(bytes32) { + function getMockOperatorId( + address operator + ) external pure returns (bytes32) { return bytes32(uint256(keccak256(abi.encodePacked(operator, "operatorId")))); } } diff --git a/test/unit/AVSRegistrar.t.sol b/test/unit/AVSRegistrar.t.sol index deea28a2..1dd90226 100644 --- a/test/unit/AVSRegistrar.t.sol +++ b/test/unit/AVSRegistrar.t.sol @@ -8,7 +8,8 @@ import {IStakeRegistry} from "../../src/interfaces/IStakeRegistry.sol"; import {BitmapUtils} from "../../src/libraries/BitmapUtils.sol"; import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; -import {IAllocationManagerTypes} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IAllocationManagerTypes} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {AVSRegistrarMock} from "../mocks/AVSRegistrarMock.sol"; import {console2 as console} from "forge-std/Test.sol"; @@ -25,18 +26,26 @@ contract AVSRegistrarTest is MockAVSDeployer { function testSetAVSRegistrar() public { vm.prank(address(serviceManager)); - allocationManager.setAVSRegistrar(address(serviceManager), IAVSRegistrar(address(avsRegistrarMock))); - assertEq(address(allocationManager.getAVSRegistrar(address(serviceManager))), address(avsRegistrarMock)); + allocationManager.setAVSRegistrar( + address(serviceManager), IAVSRegistrar(address(avsRegistrarMock)) + ); + assertEq( + address(allocationManager.getAVSRegistrar(address(serviceManager))), + address(avsRegistrarMock) + ); } function testRegisterOperator() public { // Set up AVS registrar vm.prank(address(serviceManager)); - allocationManager.setAVSRegistrar(address(serviceManager), IAVSRegistrar(address(avsRegistrarMock))); + allocationManager.setAVSRegistrar( + address(serviceManager), IAVSRegistrar(address(avsRegistrarMock)) + ); // Create operator set uint32 operatorSetId = 1; - IAllocationManagerTypes.CreateSetParams[] memory createSetParams = new IAllocationManagerTypes.CreateSetParams[](1); + IAllocationManagerTypes.CreateSetParams[] memory createSetParams = + new IAllocationManagerTypes.CreateSetParams[](1); createSetParams[0] = IAllocationManagerTypes.CreateSetParams({ operatorSetId: operatorSetId, strategies: new IStrategy[](0) @@ -57,17 +66,22 @@ contract AVSRegistrarTest is MockAVSDeployer { vm.prank(operator); allocationManager.registerForOperatorSets( address(operator), - IAllocationManagerTypes.RegisterParams(address(serviceManager), operatorSetIds, emptyBytes) + IAllocationManagerTypes.RegisterParams( + address(serviceManager), operatorSetIds, emptyBytes + ) ); } function testRegisterOperator_RevertsIfNotOperator() public { vm.prank(address(serviceManager)); - allocationManager.setAVSRegistrar(address(serviceManager), IAVSRegistrar(address(avsRegistrarMock))); + allocationManager.setAVSRegistrar( + address(serviceManager), IAVSRegistrar(address(avsRegistrarMock)) + ); // Create operator set uint32 operatorSetId = 1; - IAllocationManagerTypes.CreateSetParams[] memory createSetParams = new IAllocationManagerTypes.CreateSetParams[](1); + IAllocationManagerTypes.CreateSetParams[] memory createSetParams = + new IAllocationManagerTypes.CreateSetParams[](1); createSetParams[0] = IAllocationManagerTypes.CreateSetParams({ operatorSetId: operatorSetId, strategies: new IStrategy[](0) @@ -90,11 +104,17 @@ contract AVSRegistrarTest is MockAVSDeployer { vm.expectRevert(); allocationManager.registerForOperatorSets( address(operator), - IAllocationManagerTypes.RegisterParams(address(serviceManager), operatorSetIds, emptyBytes) + IAllocationManagerTypes.RegisterParams( + address(serviceManager), operatorSetIds, emptyBytes + ) ); } + function testAllocationManagerDeployed() public { assertTrue(address(allocationManager) != address(0), "AllocationManager not deployed"); - assertTrue(address(allocationManagerImplementation) != address(0), "AllocationManager implementation not deployed"); + assertTrue( + address(allocationManagerImplementation) != address(0), + "AllocationManager implementation not deployed" + ); } } diff --git a/test/unit/BLSApkRegistryUnit.t.sol b/test/unit/BLSApkRegistryUnit.t.sol index fa644cae..295d5cec 100644 --- a/test/unit/BLSApkRegistryUnit.t.sol +++ b/test/unit/BLSApkRegistryUnit.t.sol @@ -43,8 +43,9 @@ contract BLSApkRegistryUnitTests is BLSMockAVSDeployer, IBLSApkRegistryEvents { * HELPERS AND MODIFIERS * */ - - modifier filterFuzzedAddressInputs(address fuzzedAddress) { + modifier filterFuzzedAddressInputs( + address fuzzedAddress + ) { cheats.assume(!addressIsExcludedFromFuzzedInputs[fuzzedAddress]); _; } @@ -58,26 +59,20 @@ contract BLSApkRegistryUnitTests is BLSMockAVSDeployer, IBLSApkRegistryEvents { addressIsExcludedFromFuzzedInputs[defaultOperator] = true; addressIsExcludedFromFuzzedInputs[address(proxyAdmin)] = true; - pubkeyRegistrationParams.pubkeyG1 = BN254.generatorG1().scalar_mul( - privKey - ); + pubkeyRegistrationParams.pubkeyG1 = BN254.generatorG1().scalar_mul(privKey); defaultPubkey = pubkeyRegistrationParams.pubkeyG1; defaultPubkeyHash = BN254.hashG1Point(defaultPubkey); //privKey*G2 - pubkeyRegistrationParams.pubkeyG2.X[ - 1 - ] = 19_101_821_850_089_705_274_637_533_855_249_918_363_070_101_489_527_618_151_493_230_256_975_900_223_847; - pubkeyRegistrationParams.pubkeyG2.X[ - 0 - ] = 5_334_410_886_741_819_556_325_359_147_377_682_006_012_228_123_419_628_681_352_847_439_302_316_235_957; - pubkeyRegistrationParams.pubkeyG2.Y[ - 1 - ] = 354_176_189_041_917_478_648_604_979_334_478_067_325_821_134_838_555_150_300_539_079_146_482_658_331; - pubkeyRegistrationParams.pubkeyG2.Y[ - 0 - ] = 4_185_483_097_059_047_421_902_184_823_581_361_466_320_657_066_600_218_863_748_375_739_772_335_928_910; + pubkeyRegistrationParams.pubkeyG2.X[1] = + 19_101_821_850_089_705_274_637_533_855_249_918_363_070_101_489_527_618_151_493_230_256_975_900_223_847; + pubkeyRegistrationParams.pubkeyG2.X[0] = + 5_334_410_886_741_819_556_325_359_147_377_682_006_012_228_123_419_628_681_352_847_439_302_316_235_957; + pubkeyRegistrationParams.pubkeyG2.Y[1] = + 354_176_189_041_917_478_648_604_979_334_478_067_325_821_134_838_555_150_300_539_079_146_482_658_331; + pubkeyRegistrationParams.pubkeyG2.Y[0] = + 4_185_483_097_059_047_421_902_184_823_581_361_466_320_657_066_600_218_863_748_375_739_772_335_928_910; // Initialize 3 quorums _initializeQuorum(); @@ -96,14 +91,14 @@ contract BLSApkRegistryUnitTests is BLSMockAVSDeployer, IBLSApkRegistryEvents { initializedQuorums[quorumNumber] = true; // Mark quorum initialized for other tests - initializedQuorumBitmap = uint192( - initializedQuorumBitmap.setBit(quorumNumber) - ); + initializedQuorumBitmap = uint192(initializedQuorumBitmap.setBit(quorumNumber)); initializedQuorumBytes = initializedQuorumBitmap.bitmapToBytesArray(); } /// @dev Doesn't increment nextQuorum as assumes quorumNumber is any valid arbitrary quorumNumber - function _initializeQuorum(uint8 quorumNumber) internal { + function _initializeQuorum( + uint8 quorumNumber + ) internal { cheats.prank(address(registryCoordinator)); // Initialize quorum and mark registered @@ -113,10 +108,10 @@ contract BLSApkRegistryUnitTests is BLSMockAVSDeployer, IBLSApkRegistryEvents { /// @dev initializeQuorum based on passed in bitmap of quorum numbers /// assumes that bitmap does not contain already initailized quorums and doesn't increment nextQuorum - function _initializeFuzzedQuorums(uint192 bitmap) internal { - bytes memory quorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray( - bitmap - ); + function _initializeFuzzedQuorums( + uint192 bitmap + ) internal { + bytes memory quorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray(bitmap); for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); @@ -124,7 +119,9 @@ contract BLSApkRegistryUnitTests is BLSMockAVSDeployer, IBLSApkRegistryEvents { } } - function _initializeFuzzedQuorum(uint8 quorumNumber) internal { + function _initializeFuzzedQuorum( + uint8 quorumNumber + ) internal { cheats.assume(!initializedQuorums[quorumNumber]); _initializeQuorum(quorumNumber); } @@ -137,14 +134,16 @@ contract BLSApkRegistryUnitTests is BLSMockAVSDeployer, IBLSApkRegistryEvents { return operator; } - function _getRandomPk(uint256 seed) internal view returns (bytes32) { + function _getRandomPk( + uint256 seed + ) internal view returns (bytes32) { return keccak256(abi.encodePacked(block.timestamp, seed)); } - function _getRandBool(uint256 seed) internal view returns (bool) { - uint256 randomNumber = uint256( - keccak256(abi.encodePacked(block.timestamp, seed)) - ); + function _getRandBool( + uint256 seed + ) internal view returns (bool) { + uint256 randomNumber = uint256(keccak256(abi.encodePacked(block.timestamp, seed))); return randomNumber % 2 == 0; } @@ -153,12 +152,10 @@ contract BLSApkRegistryUnitTests is BLSMockAVSDeployer, IBLSApkRegistryEvents { * Helpers using the default preset BLS key * */ - function _signMessage( address signer ) internal view returns (BN254.G1Point memory) { - BN254.G1Point memory messageHash = registryCoordinator - .pubkeyRegistrationMessageHash(signer); + BN254.G1Point memory messageHash = registryCoordinator.pubkeyRegistrationMessageHash(signer); return BN254.scalar_mul(messageHash, privKey); } @@ -184,28 +181,18 @@ contract BLSApkRegistryUnitTests is BLSMockAVSDeployer, IBLSApkRegistryEvents { function _registerDefaultBLSPubkey( address operator ) internal returns (bytes32) { - pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage( - operator - ); - BN254.G1Point memory messageHash = registryCoordinator - .pubkeyRegistrationMessageHash(operator); + pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(operator); + BN254.G1Point memory messageHash = + registryCoordinator.pubkeyRegistrationMessageHash(operator); cheats.prank(address(registryCoordinator)); - return - blsApkRegistry.registerBLSPublicKey( - operator, - pubkeyRegistrationParams, - messageHash - ); + return blsApkRegistry.registerBLSPublicKey(operator, pubkeyRegistrationParams, messageHash); } /** * @dev register operator, assumes operator has a registered BLS public key and that quorumNumbers are valid */ - function _registerOperator( - address operator, - bytes memory quorumNumbers - ) internal { + function _registerOperator(address operator, bytes memory quorumNumbers) internal { bytes32 operatorId = blsApkRegistry.getOperatorId(operator); cheats.prank(address(registryCoordinator)); cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); @@ -216,10 +203,7 @@ contract BLSApkRegistryUnitTests is BLSMockAVSDeployer, IBLSApkRegistryEvents { /** * @dev deregister operator, assumes operator has a registered BLS public key and that quorumNumbers are valid */ - function _deregisterOperator( - address operator, - bytes memory quorumNumbers - ) internal { + function _deregisterOperator(address operator, bytes memory quorumNumbers) internal { bytes32 operatorId = blsApkRegistry.getOperatorId(operator); cheats.prank(address(registryCoordinator)); cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); @@ -232,13 +216,10 @@ contract BLSApkRegistryUnitTests is BLSMockAVSDeployer, IBLSApkRegistryEvents { * Helpers for assertions * */ - function _getApks( bytes memory quorumNumbers ) internal view returns (BN254.G1Point[] memory) { - BN254.G1Point[] memory quorumApks = new BN254.G1Point[]( - quorumNumbers.length - ); + BN254.G1Point[] memory quorumApks = new BN254.G1Point[](quorumNumbers.length); for (uint8 i = 0; i < quorumNumbers.length; i++) { quorumApks[i] = blsApkRegistry.getApk(uint8(quorumNumbers[i])); } @@ -257,9 +238,7 @@ contract BLSApkRegistryUnitTests is BLSMockAVSDeployer, IBLSApkRegistryEvents { "apksBefore and quorumNumbers must be the same length" ); assertEq( - apksBefore.length, - apksAfter.length, - "apksBefore and apksAfter must be the same length" + apksBefore.length, apksAfter.length, "apksBefore and apksAfter must be the same length" ); for (uint256 i = 0; i < apksBefore.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); @@ -271,11 +250,9 @@ contract BLSApkRegistryUnitTests is BLSMockAVSDeployer, IBLSApkRegistryEvents { "quorum apk not updated correctly adding the operator pubkey" ); - uint32 quorumHistoryLength = blsApkRegistry.getApkHistoryLength( - quorumNumber - ); - IBLSApkRegistry.ApkUpdate memory latestApkUpdate = blsApkRegistry - .getApkUpdateAtIndex(quorumNumber, quorumHistoryLength - 1); + uint32 quorumHistoryLength = blsApkRegistry.getApkHistoryLength(quorumNumber); + IBLSApkRegistry.ApkUpdate memory latestApkUpdate = + blsApkRegistry.getApkUpdateAtIndex(quorumNumber, quorumHistoryLength - 1); assertEq( latestApkUpdate.apkHash, bytes24(BN254.hashG1Point(apkAfter)), @@ -316,9 +293,7 @@ contract BLSApkRegistryUnitTests_configAndGetters is BLSApkRegistryUnitTests { } /// @notice test for BLSApkRegistry.registerBLSPublicKey() -contract BLSApkRegistryUnitTests_registerBLSPublicKey is - BLSApkRegistryUnitTests -{ +contract BLSApkRegistryUnitTests_registerBLSPublicKey is BLSApkRegistryUnitTests { using BN254 for BN254.G1Point; function testFuzz_registerOperator_Revert_WhenNotRegistryCoordinator( @@ -326,19 +301,13 @@ contract BLSApkRegistryUnitTests_registerBLSPublicKey is ) public filterFuzzedAddressInputs(nonCoordinatorAddress) { cheats.assume(nonCoordinatorAddress != address(registryCoordinator)); - pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage( - defaultOperator - ); - BN254.G1Point memory messageHash = registryCoordinator - .pubkeyRegistrationMessageHash(defaultOperator); + pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(defaultOperator); + BN254.G1Point memory messageHash = + registryCoordinator.pubkeyRegistrationMessageHash(defaultOperator); cheats.prank(address(nonCoordinatorAddress)); cheats.expectRevert(IBLSApkRegistryErrors.OnlyRegistryCoordinatorOwner.selector); - blsApkRegistry.registerBLSPublicKey( - defaultOperator, - pubkeyRegistrationParams, - messageHash - ); + blsApkRegistry.registerBLSPublicKey(defaultOperator, pubkeyRegistrationParams, messageHash); } function testFuzz_registerOperator_Revert_WhenZeroPubkeyHash( @@ -346,71 +315,43 @@ contract BLSApkRegistryUnitTests_registerBLSPublicKey is ) public filterFuzzedAddressInputs(operator) { pubkeyRegistrationParams.pubkeyG1.X = 0; pubkeyRegistrationParams.pubkeyG1.Y = 0; - BN254.G1Point memory messageHash = registryCoordinator - .pubkeyRegistrationMessageHash(operator); + BN254.G1Point memory messageHash = + registryCoordinator.pubkeyRegistrationMessageHash(operator); cheats.prank(address(registryCoordinator)); cheats.expectRevert(IBLSApkRegistryErrors.ZeroPubKey.selector); - blsApkRegistry.registerBLSPublicKey( - operator, - pubkeyRegistrationParams, - messageHash - ); + blsApkRegistry.registerBLSPublicKey(operator, pubkeyRegistrationParams, messageHash); } function testFuzz_registerOperator_Revert_WhenOperatorAlreadyRegistered( address operator ) public filterFuzzedAddressInputs(operator) { - pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage( - operator - ); - BN254.G1Point memory messageHash = registryCoordinator - .pubkeyRegistrationMessageHash(operator); + pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(operator); + BN254.G1Point memory messageHash = + registryCoordinator.pubkeyRegistrationMessageHash(operator); cheats.startPrank(address(registryCoordinator)); - blsApkRegistry.registerBLSPublicKey( - operator, - pubkeyRegistrationParams, - messageHash - ); + blsApkRegistry.registerBLSPublicKey(operator, pubkeyRegistrationParams, messageHash); cheats.expectRevert(IBLSApkRegistryErrors.OperatorAlreadyRegistered.selector); - blsApkRegistry.registerBLSPublicKey( - operator, - pubkeyRegistrationParams, - messageHash - ); + blsApkRegistry.registerBLSPublicKey(operator, pubkeyRegistrationParams, messageHash); } function testFuzz_registerOperator_Revert_WhenPubkeyAlreadyRegistered( address operator, address operator2 - ) - public - filterFuzzedAddressInputs(operator) - filterFuzzedAddressInputs(operator2) - { + ) public filterFuzzedAddressInputs(operator) filterFuzzedAddressInputs(operator2) { cheats.assume(operator != address(0)); cheats.assume(operator != operator2); - BN254.G1Point memory messageHash = registryCoordinator - .pubkeyRegistrationMessageHash(operator); - pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage( - operator - ); + BN254.G1Point memory messageHash = + registryCoordinator.pubkeyRegistrationMessageHash(operator); + pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(operator); cheats.startPrank(address(registryCoordinator)); - blsApkRegistry.registerBLSPublicKey( - operator, - pubkeyRegistrationParams, - messageHash - ); + blsApkRegistry.registerBLSPublicKey(operator, pubkeyRegistrationParams, messageHash); cheats.expectRevert(IBLSApkRegistryErrors.BLSPubkeyAlreadyRegistered.selector); - blsApkRegistry.registerBLSPublicKey( - operator2, - pubkeyRegistrationParams, - messageHash - ); + blsApkRegistry.registerBLSPublicKey(operator2, pubkeyRegistrationParams, messageHash); } /** @@ -420,25 +361,17 @@ contract BLSApkRegistryUnitTests_registerBLSPublicKey is function testFuzz_registerOperator_Revert_WhenInvalidSignature( address operator, address invalidOperator - ) - public - filterFuzzedAddressInputs(operator) - filterFuzzedAddressInputs(invalidOperator) - { + ) public filterFuzzedAddressInputs(operator) filterFuzzedAddressInputs(invalidOperator) { cheats.assume(invalidOperator != operator); - BN254.G1Point memory messageHash = registryCoordinator - .pubkeyRegistrationMessageHash(operator); + BN254.G1Point memory messageHash = + registryCoordinator.pubkeyRegistrationMessageHash(operator); BN254.G1Point memory invalidSignature = _signMessage(invalidOperator); pubkeyRegistrationParams.pubkeyRegistrationSignature = invalidSignature; cheats.startPrank(address(registryCoordinator)); cheats.expectRevert(IBLSApkRegistryErrors.InvalidBLSSignatureOrPrivateKey.selector); - blsApkRegistry.registerBLSPublicKey( - operator, - pubkeyRegistrationParams, - messageHash - ); + blsApkRegistry.registerBLSPublicKey(operator, pubkeyRegistrationParams, messageHash); } /** @@ -447,22 +380,16 @@ contract BLSApkRegistryUnitTests_registerBLSPublicKey is function testFuzz_registerOperator_Revert_WhenInvalidSignatureMismatchKey( address operator ) public filterFuzzedAddressInputs(operator) { - pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage( - operator - ); + pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(operator); BN254.G1Point memory badPubkeyG1 = BN254.generatorG1().scalar_mul(420); // mismatch public keys pubkeyRegistrationParams.pubkeyG1 = badPubkeyG1; - BN254.G1Point memory messageHash = registryCoordinator - .pubkeyRegistrationMessageHash(operator); + BN254.G1Point memory messageHash = + registryCoordinator.pubkeyRegistrationMessageHash(operator); cheats.prank(address(registryCoordinator)); cheats.expectRevert(IBLSApkRegistryErrors.InvalidBLSSignatureOrPrivateKey.selector); - blsApkRegistry.registerBLSPublicKey( - operator, - pubkeyRegistrationParams, - messageHash - ); + blsApkRegistry.registerBLSPublicKey(operator, pubkeyRegistrationParams, messageHash); } /** @@ -473,47 +400,23 @@ contract BLSApkRegistryUnitTests_registerBLSPublicKey is address operator ) public filterFuzzedAddressInputs(operator) { // sign messagehash for operator with private key - pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage( - operator - ); - BN254.G1Point memory messageHash = registryCoordinator - .pubkeyRegistrationMessageHash(operator); + pubkeyRegistrationParams.pubkeyRegistrationSignature = _signMessage(operator); + BN254.G1Point memory messageHash = + registryCoordinator.pubkeyRegistrationMessageHash(operator); cheats.prank(address(registryCoordinator)); cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); emit NewPubkeyRegistration( - operator, - pubkeyRegistrationParams.pubkeyG1, - pubkeyRegistrationParams.pubkeyG2 - ); - blsApkRegistry.registerBLSPublicKey( - operator, - pubkeyRegistrationParams, - messageHash + operator, pubkeyRegistrationParams.pubkeyG1, pubkeyRegistrationParams.pubkeyG2 ); + blsApkRegistry.registerBLSPublicKey(operator, pubkeyRegistrationParams, messageHash); - ( - BN254.G1Point memory registeredPubkey, - bytes32 registeredpkHash - ) = blsApkRegistry.getRegisteredPubkey(operator); - assertEq( - registeredPubkey.X, - defaultPubkey.X, - "registeredPubkey not set correctly" - ); + (BN254.G1Point memory registeredPubkey, bytes32 registeredpkHash) = + blsApkRegistry.getRegisteredPubkey(operator); + assertEq(registeredPubkey.X, defaultPubkey.X, "registeredPubkey not set correctly"); + assertEq(registeredPubkey.Y, defaultPubkey.Y, "registeredPubkey not set correctly"); + assertEq(registeredpkHash, defaultPubkeyHash, "registeredpkHash not set correctly"); assertEq( - registeredPubkey.Y, - defaultPubkey.Y, - "registeredPubkey not set correctly" - ); - assertEq( - registeredpkHash, - defaultPubkeyHash, - "registeredpkHash not set correctly" - ); - assertEq( - blsApkRegistry.pubkeyHashToOperator( - BN254.hashG1Point(defaultPubkey) - ), + blsApkRegistry.pubkeyHashToOperator(BN254.hashG1Point(defaultPubkey)), operator, "operator address not stored correctly" ); @@ -550,12 +453,8 @@ contract BLSApkRegistryUnitTests_registerOperator is BLSApkRegistryUnitTests { cheats.prank(address(registryCoordinator)); cheats.assume(quorumBitmap > initializedQuorumBitmap); // mask out quorums that are already initialized - quorumBitmap = uint192( - quorumBitmap.minus(uint256(initializedQuorumBitmap)) - ); - bytes memory quorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray( - quorumBitmap - ); + quorumBitmap = uint192(quorumBitmap.minus(uint256(initializedQuorumBitmap))); + bytes memory quorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray(quorumBitmap); _registerDefaultBLSPubkey(operator); @@ -576,26 +475,15 @@ contract BLSApkRegistryUnitTests_registerOperator is BLSApkRegistryUnitTests { ) public filterFuzzedAddressInputs(operator) { // Test setup, initialize fuzzed quorums and register operator BLS pubkey cheats.assume(quorumBitmap > initializedQuorumBitmap); - uint192 initializingBitmap = uint192( - quorumBitmap.minus(uint256(initializedQuorumBitmap)) - ); + uint192 initializingBitmap = uint192(quorumBitmap.minus(uint256(initializedQuorumBitmap))); _initializeFuzzedQuorums(initializingBitmap); - bytes memory quorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray( - quorumBitmap - ); - (BN254.G1Point memory pubkey, ) = _registerRandomBLSPubkey( - operator, - randomSeed - ); + bytes memory quorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray(quorumBitmap); + (BN254.G1Point memory pubkey,) = _registerRandomBLSPubkey(operator, randomSeed); // get before values - BN254.G1Point[] memory quorumApksBefore = new BN254.G1Point[]( - quorumNumbers.length - ); + BN254.G1Point[] memory quorumApksBefore = new BN254.G1Point[](quorumNumbers.length); for (uint8 i = 0; i < quorumNumbers.length; i++) { - quorumApksBefore[i] = blsApkRegistry.getApk( - uint8(quorumNumbers[i]) - ); + quorumApksBefore[i] = blsApkRegistry.getApk(uint8(quorumNumbers[i])); } // registerOperator with expected OperatorAddedToQuorums event @@ -609,20 +497,16 @@ contract BLSApkRegistryUnitTests_registerOperator is BLSApkRegistryUnitTests { for (uint8 i = 0; i < quorumNumbers.length; i++) { // Check currentApk[quorumNumber] values uint8 quorumNumber = uint8(quorumNumbers[i]); - BN254.G1Point memory quorumApkAfter = blsApkRegistry.getApk( - uint8(quorumNumbers[i]) - ); + BN254.G1Point memory quorumApkAfter = blsApkRegistry.getApk(uint8(quorumNumbers[i])); assertEq( BN254.hashG1Point(quorumApkAfter), BN254.hashG1Point(quorumApksBefore[i].plus(pubkey)), "quorum apk not updated correctly adding the operator pubkey" ); // Check the latest ApkUpdate values - uint32 quorumHistoryLength = blsApkRegistry.getApkHistoryLength( - quorumNumber - ); - IBLSApkRegistry.ApkUpdate memory latestApkUpdate = blsApkRegistry - .getApkUpdateAtIndex(quorumNumber, quorumHistoryLength - 1); + uint32 quorumHistoryLength = blsApkRegistry.getApkHistoryLength(quorumNumber); + IBLSApkRegistry.ApkUpdate memory latestApkUpdate = + blsApkRegistry.getApkUpdateAtIndex(quorumNumber, quorumHistoryLength - 1); assertEq( latestApkUpdate.apkHash, bytes24(BN254.hashG1Point(quorumApkAfter)), @@ -672,14 +556,10 @@ contract BLSApkRegistryUnitTests_deregisterOperator is BLSApkRegistryUnitTests { cheats.prank(address(registryCoordinator)); cheats.assume(quorumBitmap > initializedQuorumBitmap); // mask out quorums that are already initialized - quorumBitmap = uint192( - quorumBitmap.minus(uint256(initializedQuorumBitmap)) - ); - bytes memory validQuorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray( - initializedQuorumBitmap - ); - bytes memory invalidQuorumNumbers = bitmapUtilsWrapper - .bitmapToBytesArray(quorumBitmap); + quorumBitmap = uint192(quorumBitmap.minus(uint256(initializedQuorumBitmap))); + bytes memory validQuorumNumbers = + bitmapUtilsWrapper.bitmapToBytesArray(initializedQuorumBitmap); + bytes memory invalidQuorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray(quorumBitmap); _registerDefaultBLSPubkey(operator); _registerOperator(operator, validQuorumNumbers); @@ -701,27 +581,16 @@ contract BLSApkRegistryUnitTests_deregisterOperator is BLSApkRegistryUnitTests { ) public filterFuzzedAddressInputs(operator) { // Test setup, initialize fuzzed quorums and register operator BLS pubkey cheats.assume(quorumBitmap > initializedQuorumBitmap); - uint192 initializingBitmap = uint192( - quorumBitmap.minus(uint256(initializedQuorumBitmap)) - ); + uint192 initializingBitmap = uint192(quorumBitmap.minus(uint256(initializedQuorumBitmap))); _initializeFuzzedQuorums(initializingBitmap); - bytes memory quorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray( - quorumBitmap - ); - (BN254.G1Point memory pubkey, ) = _registerRandomBLSPubkey( - operator, - randomSeed - ); + bytes memory quorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray(quorumBitmap); + (BN254.G1Point memory pubkey,) = _registerRandomBLSPubkey(operator, randomSeed); _registerOperator(operator, quorumNumbers); // get before values - BN254.G1Point[] memory quorumApksBefore = new BN254.G1Point[]( - quorumNumbers.length - ); + BN254.G1Point[] memory quorumApksBefore = new BN254.G1Point[](quorumNumbers.length); for (uint8 i = 0; i < quorumNumbers.length; i++) { - quorumApksBefore[i] = blsApkRegistry.getApk( - uint8(quorumNumbers[i]) - ); + quorumApksBefore[i] = blsApkRegistry.getApk(uint8(quorumNumbers[i])); } // registerOperator with expected OperatorAddedToQuorums event @@ -735,20 +604,16 @@ contract BLSApkRegistryUnitTests_deregisterOperator is BLSApkRegistryUnitTests { for (uint8 i = 0; i < quorumNumbers.length; i++) { // Check currentApk[quorumNumber] values uint8 quorumNumber = uint8(quorumNumbers[i]); - BN254.G1Point memory quorumApkAfter = blsApkRegistry.getApk( - uint8(quorumNumbers[i]) - ); + BN254.G1Point memory quorumApkAfter = blsApkRegistry.getApk(uint8(quorumNumbers[i])); assertEq( BN254.hashG1Point(quorumApkAfter), BN254.hashG1Point(quorumApksBefore[i].plus(pubkey.negate())), "quorum apk not updated correctly removing the operator pubkey" ); // Check the latest ApkUpdate values - uint32 quorumHistoryLength = blsApkRegistry.getApkHistoryLength( - quorumNumber - ); - IBLSApkRegistry.ApkUpdate memory latestApkUpdate = blsApkRegistry - .getApkUpdateAtIndex(quorumNumber, quorumHistoryLength - 1); + uint32 quorumHistoryLength = blsApkRegistry.getApkHistoryLength(quorumNumber); + IBLSApkRegistry.ApkUpdate memory latestApkUpdate = + blsApkRegistry.getApkUpdateAtIndex(quorumNumber, quorumHistoryLength - 1); assertEq( latestApkUpdate.apkHash, bytes24(BN254.hashG1Point(quorumApkAfter)), @@ -780,10 +645,7 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { * @dev register/deregister up to 200 operators and check quorum apk updates * Test uses only the defaultQuorumNumber */ - function testFuzz_quorumApkUpdates( - uint256 numOperators, - uint256[200] memory randSeed - ) public { + function testFuzz_quorumApkUpdates(uint256 numOperators, uint256[200] memory randSeed) public { cheats.assume(0 < numOperators && numOperators <= 200); bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); @@ -797,17 +659,11 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { // register and check quorum apk updates BN254.G1Point[] memory quorumApksBefore = _getApks(quorumNumbers); address operator = _selectNewOperator(); - (BN254.G1Point memory operatorPubkey, ) = _registerRandomBLSPubkey( - operator, - randSeed[i] - ); + (BN254.G1Point memory operatorPubkey,) = _registerRandomBLSPubkey(operator, randSeed[i]); _registerOperator(operator, quorumNumbers); BN254.G1Point[] memory quorumApksAfter = _getApks(quorumNumbers); _assertQuorumApkUpdates( - quorumNumbers, - quorumApksBefore, - quorumApksAfter, - operatorPubkey + quorumNumbers, quorumApksBefore, quorumApksAfter, operatorPubkey ); // deregister and check quorum apk updates @@ -817,10 +673,7 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { _deregisterOperator(operator, quorumNumbers); quorumApksAfter = _getApks(quorumNumbers); _assertQuorumApkUpdates( - quorumNumbers, - quorumApksBefore, - quorumApksAfter, - operatorPubkey.negate() + quorumNumbers, quorumApksBefore, quorumApksAfter, operatorPubkey.negate() ); } } @@ -838,13 +691,9 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { cheats.assume(0 < numOperators && numOperators <= 50); cheats.assume(quorumBitmap > initializedQuorumBitmap); // mask out quorums that are already initialized - uint192 initializingBitmap = uint192( - quorumBitmap.minus(uint256(initializedQuorumBitmap)) - ); + uint192 initializingBitmap = uint192(quorumBitmap.minus(uint256(initializedQuorumBitmap))); _initializeFuzzedQuorums(initializingBitmap); - bytes memory quorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray( - quorumBitmap - ); + bytes memory quorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray(quorumBitmap); /** * For each operator, randomly proceed with either registering/deregistering an operator @@ -855,17 +704,11 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { // register and check quorum apk updates BN254.G1Point[] memory quorumApksBefore = _getApks(quorumNumbers); address operator = _selectNewOperator(); - (BN254.G1Point memory operatorPubkey, ) = _registerRandomBLSPubkey( - operator, - randSeed[i] - ); + (BN254.G1Point memory operatorPubkey,) = _registerRandomBLSPubkey(operator, randSeed[i]); _registerOperator(operator, quorumNumbers); BN254.G1Point[] memory quorumApksAfter = _getApks(quorumNumbers); _assertQuorumApkUpdates( - quorumNumbers, - quorumApksBefore, - quorumApksAfter, - operatorPubkey + quorumNumbers, quorumApksBefore, quorumApksAfter, operatorPubkey ); // deregister and check quorum apk updates @@ -875,10 +718,7 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { _deregisterOperator(operator, quorumNumbers); quorumApksAfter = _getApks(quorumNumbers); _assertQuorumApkUpdates( - quorumNumbers, - quorumApksBefore, - quorumApksAfter, - operatorPubkey.negate() + quorumNumbers, quorumApksBefore, quorumApksAfter, operatorPubkey.negate() ); } } @@ -900,13 +740,9 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { _initializeFuzzedQuorum(quorumNumber2); } - BN254.G1Point[] memory quorumApksBefore = new BN254.G1Point[]( - quorumNumbers.length - ); + BN254.G1Point[] memory quorumApksBefore = new BN254.G1Point[](quorumNumbers.length); for (uint8 i = 0; i < quorumNumbers.length; i++) { - quorumApksBefore[i] = blsApkRegistry.getApk( - uint8(quorumNumbers[i]) - ); + quorumApksBefore[i] = blsApkRegistry.getApk(uint8(quorumNumbers[i])); } // use harnessed function to directly set the pubkey, bypassing the ordinary checks @@ -917,16 +753,9 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { //check quorum apk updates for (uint8 i = 0; i < quorumNumbers.length; i++) { - BN254.G1Point memory quorumApkAfter = blsApkRegistry.getApk( - uint8(quorumNumbers[i]) - ); + BN254.G1Point memory quorumApkAfter = blsApkRegistry.getApk(uint8(quorumNumbers[i])); assertEq( - BN254.hashG1Point( - BN254.plus( - quorumApkAfter, - BN254.negate(quorumApksBefore[i]) - ) - ), + BN254.hashG1Point(BN254.plus(quorumApkAfter, BN254.negate(quorumApksBefore[i]))), BN254.hashG1Point(defaultPubKey), "quorum apk not updated correctly" ); @@ -946,9 +775,7 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { _registerRandomBLSPubkey(defaultOperator, randSeed); _registerOperator(defaultOperator, quorumNumbers); - BN254.G1Point memory quorumApk = blsApkRegistry.getApk( - defaultQuorumNumber - ); + BN254.G1Point memory quorumApk = blsApkRegistry.getApk(defaultQuorumNumber); BN254.G1Point memory negatedQuorumApk = BN254.negate(quorumApk); //register for one quorum with negative quorum apk @@ -984,23 +811,18 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { for (uint256 i = 0; i < numRegistrants; i++) { // generate operator and register them with BLS pubkey address operator = _selectNewOperator(); - (BN254.G1Point memory operatorPubkey, ) = _registerRandomBLSPubkey( - operator, - uint256(keccak256(abi.encodePacked(operator, randSeed))) + (BN254.G1Point memory operatorPubkey,) = _registerRandomBLSPubkey( + operator, uint256(keccak256(abi.encodePacked(operator, randSeed))) ); _registerOperator(operator, quorumNumbers); quorumApk = quorumApk.plus(operatorPubkey); quorumApkHash = bytes24(BN254.hashG1Point(quorumApk)); - uint256 historyLength = blsApkRegistry.getApkHistoryLength( - defaultQuorumNumber - ); + uint256 historyLength = blsApkRegistry.getApkHistoryLength(defaultQuorumNumber); assertEq( quorumApkHash, blsApkRegistry.getApkHashAtBlockNumberAndIndex( - defaultQuorumNumber, - uint32(block.number + blockGap), - historyLength - 1 + defaultQuorumNumber, uint32(block.number + blockGap), historyLength - 1 ), "incorrect quorum apk update" ); @@ -1009,15 +831,11 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { _deregisterOperator(operator, quorumNumbers); quorumApk = quorumApk.plus(operatorPubkey.negate()); quorumApkHash = bytes24(BN254.hashG1Point(quorumApk)); - historyLength = blsApkRegistry.getApkHistoryLength( - defaultQuorumNumber - ); + historyLength = blsApkRegistry.getApkHistoryLength(defaultQuorumNumber); assertEq( quorumApkHash, blsApkRegistry.getApkHashAtBlockNumberAndIndex( - defaultQuorumNumber, - uint32(block.number + blockGap), - historyLength - 1 + defaultQuorumNumber, uint32(block.number + blockGap), historyLength - 1 ), "incorrect quorum apk update" ); @@ -1047,8 +865,7 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { for (uint256 i = 0; i < numRegistrants; i++) { address operator = _selectNewOperator(); _registerRandomBLSPubkey( - operator, - uint256(keccak256(abi.encodePacked(operator, randSeed))) + operator, uint256(keccak256(abi.encodePacked(operator, randSeed))) ); _registerOperator(operator, quorumNumbers); cheats.roll(block.number + 100); @@ -1057,20 +874,14 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { emit log_named_uint("index too recent: ", indexToCheck); cheats.expectRevert(IBLSApkRegistryErrors.BlockNumberTooRecent.selector); blsApkRegistry.getApkHashAtBlockNumberAndIndex( - defaultQuorumNumber, - wrongBlockNumber, - indexToCheck + defaultQuorumNumber, wrongBlockNumber, indexToCheck ); } - if ( - wrongBlockNumber >= startingBlockNumber + (indexToCheck + 1) * 100 - ) { + if (wrongBlockNumber >= startingBlockNumber + (indexToCheck + 1) * 100) { emit log_named_uint("index not latest: ", indexToCheck); cheats.expectRevert(IBLSApkRegistryErrors.BlockNumberNotLatest.selector); blsApkRegistry.getApkHashAtBlockNumberAndIndex( - defaultQuorumNumber, - wrongBlockNumber, - indexToCheck + defaultQuorumNumber, wrongBlockNumber, indexToCheck ); } } @@ -1096,9 +907,7 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { BN254.G1Point[] memory quorumApksBefore = new BN254.G1Point[](2); for (uint8 i = 0; i < quorumNumbers.length; i++) { - quorumApksBefore[i] = blsApkRegistry.getApk( - uint8(quorumNumbers[i]) - ); + quorumApksBefore[i] = blsApkRegistry.getApk(uint8(quorumNumbers[i])); } cheats.startPrank(address(registryCoordinator)); @@ -1108,13 +917,9 @@ contract BLSApkRegistryUnitTests_quorumApkUpdates is BLSApkRegistryUnitTests { BN254.G1Point memory quorumApkAfter; for (uint8 i = 0; i < quorumNumbers.length; i++) { quorumApkAfter = blsApkRegistry.getApk(uint8(quorumNumbers[i])); - BN254.G1Point memory quorumApk = blsApkRegistry.getApk( - defaultQuorumNumber - ); + BN254.G1Point memory quorumApk = blsApkRegistry.getApk(defaultQuorumNumber); assertEq( - BN254.hashG1Point( - quorumApksBefore[i].plus(defaultPubKey.negate()) - ), + BN254.hashG1Point(quorumApksBefore[i].plus(defaultPubKey.negate())), BN254.hashG1Point(quorumApkAfter), "quorum apk not updated correctly" ); diff --git a/test/unit/BLSSignatureCheckerUnit.t.sol b/test/unit/BLSSignatureCheckerUnit.t.sol index d1d0ac7f..a58d6112 100644 --- a/test/unit/BLSSignatureCheckerUnit.t.sol +++ b/test/unit/BLSSignatureCheckerUnit.t.sol @@ -15,7 +15,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { event StaleStakesForbiddenUpdate(bool value); - function setUp() virtual public { + function setUp() public virtual { _setUpBLSMockAVSDeployer(); blsSignatureChecker = new BLSSignatureChecker(registryCoordinator); @@ -31,7 +31,9 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { testFuzz_setStaleStakesForbidden(true); } - function testFuzz_setStaleStakesForbidden(bool newState) public { + function testFuzz_setStaleStakesForbidden( + bool newState + ) public { cheats.expectEmit(true, true, true, true, address(blsSignatureChecker)); emit StaleStakesForbiddenUpdate(newState); cheats.prank(registryCoordinatorOwner); @@ -42,35 +44,46 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // this test checks that a valid signature from maxOperatorsToRegister with a random number of nonsigners is checked // correctly on the BLSSignatureChecker contract when all operators are only regsitered for a single quorum and // the signature is only checked for stakes on that quorum - function testFuzz_checkSignatures_SingleQuorum(uint256 pseudoRandomNumber) public { + function testFuzz_checkSignatures_SingleQuorum( + uint256 pseudoRandomNumber + ) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 1); uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + pseudoRandomNumber, numNonSigners, quorumBitmap + ); - bytes32[] memory pubkeyHashes = new bytes32[](nonSignerStakesAndSignature.nonSignerPubkeys.length); + bytes32[] memory pubkeyHashes = + new bytes32[](nonSignerStakesAndSignature.nonSignerPubkeys.length); for (uint256 i = 0; i < nonSignerStakesAndSignature.nonSignerPubkeys.length; ++i) { pubkeyHashes[i] = nonSignerStakesAndSignature.nonSignerPubkeys[i].hashG1Point(); } - bytes32 expectedSignatoryRecordHash = keccak256(abi.encodePacked(referenceBlockNumber, pubkeyHashes)); + bytes32 expectedSignatoryRecordHash = + keccak256(abi.encodePacked(referenceBlockNumber, pubkeyHashes)); uint256 gasBefore = gasleft(); ( BLSSignatureChecker.QuorumStakeTotals memory quorumStakeTotals, bytes32 signatoryRecordHash ) = blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); uint256 gasAfter = gasleft(); emit log_named_uint("gasUsed", gasBefore - gasAfter); - assertTrue(quorumStakeTotals.signedStakeForQuorum[0] > 0, "signedStakeForQuorum should be nonzero"); - assertEq(expectedSignatoryRecordHash, signatoryRecordHash, "signatoryRecordHash does not match expectation"); + assertTrue( + quorumStakeTotals.signedStakeForQuorum[0] > 0, "signedStakeForQuorum should be nonzero" + ); + assertEq( + expectedSignatoryRecordHash, + signatoryRecordHash, + "signatoryRecordHash does not match expectation" + ); // 0 nonSigners: 159908 // 1 nonSigner: 178683 // 2 nonSigners: 197410 @@ -82,82 +95,114 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(nonRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + nonRandomNumber, numNonSigners, quorumBitmap + ); - bytes32[] memory pubkeyHashes = new bytes32[](nonSignerStakesAndSignature.nonSignerPubkeys.length); + bytes32[] memory pubkeyHashes = + new bytes32[](nonSignerStakesAndSignature.nonSignerPubkeys.length); for (uint256 i = 0; i < nonSignerStakesAndSignature.nonSignerPubkeys.length; ++i) { pubkeyHashes[i] = nonSignerStakesAndSignature.nonSignerPubkeys[i].hashG1Point(); } - bytes32 expectedSignatoryRecordHash = keccak256(abi.encodePacked(referenceBlockNumber, pubkeyHashes)); + bytes32 expectedSignatoryRecordHash = + keccak256(abi.encodePacked(referenceBlockNumber, pubkeyHashes)); uint256 gasBefore = gasleft(); ( BLSSignatureChecker.QuorumStakeTotals memory quorumStakeTotals, bytes32 signatoryRecordHash ) = blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); uint256 gasAfter = gasleft(); emit log_named_uint("gasUsed", gasBefore - gasAfter); - assertEq(expectedSignatoryRecordHash, signatoryRecordHash, "signatoryRecordHash does not match expectation"); + assertEq( + expectedSignatoryRecordHash, + signatoryRecordHash, + "signatoryRecordHash does not match expectation" + ); - assertEq(quorumStakeTotals.signedStakeForQuorum[0], 3000000000000000000, "signedStakeForQuorum incorrect"); - assertEq(quorumStakeTotals.totalStakeForQuorum[0], 4000000000000000000, "totalStakeForQuorum incorrect"); + assertEq( + quorumStakeTotals.signedStakeForQuorum[0], + 3_000_000_000_000_000_000, + "signedStakeForQuorum incorrect" + ); + assertEq( + quorumStakeTotals.totalStakeForQuorum[0], + 4_000_000_000_000_000_000, + "totalStakeForQuorum incorrect" + ); } // this test checks that a valid signature from maxOperatorsToRegister with a random number of nonsigners is checked // correctly on the BLSSignatureChecker contract when all operators are registered for the first 100 quorums // and the signature is only checked for stakes on those quorums - function test_checkSignatures_100Quorums(uint256 pseudoRandomNumber) public { + function test_checkSignatures_100Quorums( + uint256 pseudoRandomNumber + ) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 1); // 100 set bits uint256 quorumBitmap = (1 << 100) - 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + pseudoRandomNumber, numNonSigners, quorumBitmap + ); nonSignerStakesAndSignature.sigma = sigma.scalar_mul(quorumNumbers.length); nonSignerStakesAndSignature.apkG2 = oneHundredQuorumApkG2; - bytes32[] memory pubkeyHashes = new bytes32[](nonSignerStakesAndSignature.nonSignerPubkeys.length); + bytes32[] memory pubkeyHashes = + new bytes32[](nonSignerStakesAndSignature.nonSignerPubkeys.length); for (uint256 i = 0; i < nonSignerStakesAndSignature.nonSignerPubkeys.length; ++i) { pubkeyHashes[i] = nonSignerStakesAndSignature.nonSignerPubkeys[i].hashG1Point(); } - bytes32 expectedSignatoryRecordHash = keccak256(abi.encodePacked(referenceBlockNumber, pubkeyHashes)); + bytes32 expectedSignatoryRecordHash = + keccak256(abi.encodePacked(referenceBlockNumber, pubkeyHashes)); uint256 gasBefore = gasleft(); ( BLSSignatureChecker.QuorumStakeTotals memory quorumStakeTotals, bytes32 signatoryRecordHash ) = blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); uint256 gasAfter = gasleft(); emit log_named_uint("gasUsed", gasBefore - gasAfter); for (uint256 i = 0; i < quorumStakeTotals.signedStakeForQuorum.length; ++i) { - assertTrue(quorumStakeTotals.signedStakeForQuorum[i] > 0, "signedStakeForQuorum should be nonzero"); + assertTrue( + quorumStakeTotals.signedStakeForQuorum[i] > 0, + "signedStakeForQuorum should be nonzero" + ); } - assertEq(expectedSignatoryRecordHash, signatoryRecordHash, "signatoryRecordHash does not match expectation"); + assertEq( + expectedSignatoryRecordHash, + signatoryRecordHash, + "signatoryRecordHash does not match expectation" + ); } function test_checkSignatures_revert_inputLengthMismatch() public { uint256 numNonSigners = 0; uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(1, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + 1, numNonSigners, quorumBitmap + ); - IBLSSignatureChecker.NonSignerStakesAndSignature memory incorrectLengthInputs = IBLSSignatureChecker.NonSignerStakesAndSignature({ + IBLSSignatureChecker.NonSignerStakesAndSignature memory incorrectLengthInputs = + IBLSSignatureChecker.NonSignerStakesAndSignature({ nonSignerQuorumBitmapIndices: nonSignerStakesAndSignature.nonSignerQuorumBitmapIndices, nonSignerPubkeys: nonSignerStakesAndSignature.nonSignerPubkeys, quorumApks: nonSignerStakesAndSignature.quorumApks, @@ -172,10 +217,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { cheats.expectRevert(IBLSSignatureCheckerErrors.InputArrayLengthMismatch.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - incorrectLengthInputs + msgHash, quorumNumbers, referenceBlockNumber, incorrectLengthInputs ); // reset the input to correct values @@ -184,10 +226,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { incorrectLengthInputs.quorumApkIndices = new uint32[](5); cheats.expectRevert(IBLSSignatureCheckerErrors.InputArrayLengthMismatch.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - incorrectLengthInputs + msgHash, quorumNumbers, referenceBlockNumber, incorrectLengthInputs ); // reset the input to correct values @@ -196,10 +235,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { incorrectLengthInputs.totalStakeIndices = new uint32[](5); cheats.expectRevert(IBLSSignatureCheckerErrors.InputArrayLengthMismatch.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - incorrectLengthInputs + msgHash, quorumNumbers, referenceBlockNumber, incorrectLengthInputs ); // reset the input to correct values @@ -208,51 +244,47 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { incorrectLengthInputs.nonSignerStakeIndices = new uint32[][](5); cheats.expectRevert(IBLSSignatureCheckerErrors.InputArrayLengthMismatch.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - incorrectLengthInputs + msgHash, quorumNumbers, referenceBlockNumber, incorrectLengthInputs ); // reset the input to correct values - incorrectLengthInputs.nonSignerStakeIndices = nonSignerStakesAndSignature.nonSignerStakeIndices; + incorrectLengthInputs.nonSignerStakeIndices = + nonSignerStakesAndSignature.nonSignerStakeIndices; // make one part of the input incorrect length - incorrectLengthInputs.nonSignerQuorumBitmapIndices = new uint32[](nonSignerStakesAndSignature.nonSignerPubkeys.length + 1); + incorrectLengthInputs.nonSignerQuorumBitmapIndices = + new uint32[](nonSignerStakesAndSignature.nonSignerPubkeys.length + 1); cheats.expectRevert(IBLSSignatureCheckerErrors.InputNonSignerLengthMismatch.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - incorrectLengthInputs + msgHash, quorumNumbers, referenceBlockNumber, incorrectLengthInputs ); // reset the input to correct values - incorrectLengthInputs.nonSignerQuorumBitmapIndices = nonSignerStakesAndSignature.nonSignerQuorumBitmapIndices; + incorrectLengthInputs.nonSignerQuorumBitmapIndices = + nonSignerStakesAndSignature.nonSignerQuorumBitmapIndices; // sanity check for call passing with the correct values blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - incorrectLengthInputs + msgHash, quorumNumbers, referenceBlockNumber, incorrectLengthInputs ); } - function test_checkSignatures_revert_referenceBlockNumberInFuture(uint256 pseudoRandomNumber) public { + function test_checkSignatures_revert_referenceBlockNumberInFuture( + uint256 pseudoRandomNumber + ) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 2) + 1; uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (/*uint32 referenceBlockNumber*/, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); + ( /*uint32 referenceBlockNumber*/ + , BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + pseudoRandomNumber, numNonSigners, quorumBitmap + ); // Create an invalid reference block: any block number >= the current block uint32 invalidReferenceBlock = uint32(block.number + (pseudoRandomNumber % 20)); cheats.expectRevert(IBLSSignatureCheckerErrors.InvalidReferenceBlocknumber.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - invalidReferenceBlock, - nonSignerStakesAndSignature + msgHash, quorumNumbers, invalidReferenceBlock, nonSignerStakesAndSignature ); } @@ -262,17 +294,19 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 nonRandomNumber = 777; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(nonRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + nonRandomNumber, numNonSigners, quorumBitmap + ); // swap out a pubkey to make sure there is a duplicate - nonSignerStakesAndSignature.nonSignerPubkeys[1] = nonSignerStakesAndSignature.nonSignerPubkeys[0]; + nonSignerStakesAndSignature.nonSignerPubkeys[1] = + nonSignerStakesAndSignature.nonSignerPubkeys[0]; cheats.expectRevert(IBLSSignatureCheckerErrors.NonSignerPubkeysNotSorted.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); } @@ -282,18 +316,24 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 nonRandomNumber = 777; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(nonRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + nonRandomNumber, numNonSigners, quorumBitmap + ); // swap two pubkeys to ensure ordering is wrong - (nonSignerStakesAndSignature.nonSignerPubkeys[0], nonSignerStakesAndSignature.nonSignerPubkeys[1]) = - (nonSignerStakesAndSignature.nonSignerPubkeys[1], nonSignerStakesAndSignature.nonSignerPubkeys[0]); + ( + nonSignerStakesAndSignature.nonSignerPubkeys[0], + nonSignerStakesAndSignature.nonSignerPubkeys[1] + ) = ( + nonSignerStakesAndSignature.nonSignerPubkeys[1], + nonSignerStakesAndSignature.nonSignerPubkeys[0] + ); cheats.expectRevert(IBLSSignatureCheckerErrors.NonSignerPubkeysNotSorted.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); } @@ -303,31 +343,34 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { uint256 nonRandomNumber = 777; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(nonRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + nonRandomNumber, numNonSigners, quorumBitmap + ); // make sure the `staleStakesForbidden` flag is set to 'true' testFuzz_setStaleStakesForbidden(true); uint256 stalestUpdateBlock = type(uint256).max; for (uint256 i = 0; i < quorumNumbers.length; ++i) { - uint256 quorumUpdateBlockNumber = registryCoordinator.quorumUpdateBlockNumber(uint8(quorumNumbers[i])); + uint256 quorumUpdateBlockNumber = + registryCoordinator.quorumUpdateBlockNumber(uint8(quorumNumbers[i])); if (quorumUpdateBlockNumber < stalestUpdateBlock) { stalestUpdateBlock = quorumUpdateBlockNumber; } } // move referenceBlockNumber forward to a block number the last block number where the stakes will be considered "not stale" - referenceBlockNumber = uint32(stalestUpdateBlock + delegationMock.minWithdrawalDelayBlocks()) - 1; + referenceBlockNumber = + uint32(stalestUpdateBlock + delegationMock.minWithdrawalDelayBlocks()) - 1; // roll forward to make the reference block number valid // we roll to referenceBlockNumber + 1 because the current block number is not a valid reference block cheats.roll(referenceBlockNumber + 1); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); // move referenceBlockNumber forward one more block, making the stakes "stale" @@ -336,153 +379,172 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { cheats.roll(referenceBlockNumber + 1); cheats.expectRevert(IBLSSignatureCheckerErrors.StaleStakesForbidden.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); } - function test_checkSignatures_revert_incorrectQuorumBitmapIndex(uint256 pseudoRandomNumber) public { + function test_checkSignatures_revert_incorrectQuorumBitmapIndex( + uint256 pseudoRandomNumber + ) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 2) + 1; uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + pseudoRandomNumber, numNonSigners, quorumBitmap + ); // record a quorumBitmap update via a harnessed function - registryCoordinator._updateOperatorBitmapExternal(nonSignerStakesAndSignature.nonSignerPubkeys[0].hashG1Point(), uint192(quorumBitmap | 2)); + registryCoordinator._updateOperatorBitmapExternal( + nonSignerStakesAndSignature.nonSignerPubkeys[0].hashG1Point(), uint192(quorumBitmap | 2) + ); // set the nonSignerQuorumBitmapIndices to a different value nonSignerStakesAndSignature.nonSignerQuorumBitmapIndices[0] = 1; cheats.expectRevert(QuorumBitmapHistoryLib.BitmapUpdateIsAfterBlockNumber.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); } - function test_checkSignatures_revert_incorrectTotalStakeIndex(uint256 pseudoRandomNumber) public { + function test_checkSignatures_revert_incorrectTotalStakeIndex( + uint256 pseudoRandomNumber + ) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 2) + 1; uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + pseudoRandomNumber, numNonSigners, quorumBitmap + ); // set the totalStakeIndices to a different value nonSignerStakesAndSignature.totalStakeIndices[0] = 0; cheats.expectRevert(IStakeRegistryErrors.InvalidBlockNumber.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); } - function test_checkSignatures_revert_incorrectNonSignerStakeIndex(uint256 pseudoRandomNumber) public { + function test_checkSignatures_revert_incorrectNonSignerStakeIndex( + uint256 pseudoRandomNumber + ) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 2) + 1; uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + pseudoRandomNumber, numNonSigners, quorumBitmap + ); bytes32 nonSignerOperatorId = nonSignerStakesAndSignature.nonSignerPubkeys[0].hashG1Point(); // record a stake update - stakeRegistry.recordOperatorStakeUpdate( - nonSignerOperatorId, - uint8(quorumNumbers[0]), - 1234 - ); + stakeRegistry.recordOperatorStakeUpdate(nonSignerOperatorId, uint8(quorumNumbers[0]), 1234); // set the nonSignerStakeIndices to a different value nonSignerStakesAndSignature.nonSignerStakeIndices[0][0] = 1; cheats.expectRevert(IStakeRegistryErrors.InvalidBlockNumber.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); - } - function test_checkSignatures_revert_incorrectQuorumAPKIndex(uint256 pseudoRandomNumber) public { + function test_checkSignatures_revert_incorrectQuorumAPKIndex( + uint256 pseudoRandomNumber + ) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 2) + 1; uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + pseudoRandomNumber, numNonSigners, quorumBitmap + ); // set the quorumApkIndices to a different value nonSignerStakesAndSignature.quorumApkIndices[0] = 0; cheats.expectRevert(IBLSApkRegistryErrors.BlockNumberNotLatest.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); } - function test_checkSignatures_revert_incorrectQuorumAPK(uint256 pseudoRandomNumber) public { + function test_checkSignatures_revert_incorrectQuorumAPK( + uint256 pseudoRandomNumber + ) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 2) + 1; uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + pseudoRandomNumber, numNonSigners, quorumBitmap + ); // set the quorumApk to a different value - nonSignerStakesAndSignature.quorumApks[0] = nonSignerStakesAndSignature.quorumApks[0].negate(); + nonSignerStakesAndSignature.quorumApks[0] = + nonSignerStakesAndSignature.quorumApks[0].negate(); cheats.expectRevert(IBLSSignatureCheckerErrors.InvalidQuorumApkHash.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); } - function test_checkSignatures_revert_incorrectSignature(uint256 pseudoRandomNumber) public { + function test_checkSignatures_revert_incorrectSignature( + uint256 pseudoRandomNumber + ) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 2) + 1; uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + pseudoRandomNumber, numNonSigners, quorumBitmap + ); // set the sigma to a different value nonSignerStakesAndSignature.sigma = nonSignerStakesAndSignature.sigma.negate(); cheats.expectRevert(IBLSSignatureCheckerErrors.InvalidBLSSignature.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); } - function test_checkSignatures_revert_invalidSignature(uint256 pseudoRandomNumber) public { + function test_checkSignatures_revert_invalidSignature( + uint256 pseudoRandomNumber + ) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 2) + 1; uint256 quorumBitmap = 1; bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + pseudoRandomNumber, numNonSigners, quorumBitmap + ); // set the sigma to a different value nonSignerStakesAndSignature.sigma.X++; @@ -490,20 +552,23 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // expect a non-specific low-level revert, since this call will ultimately fail as part of the precompile call cheats.expectRevert(); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); } - function testBLSSignatureChecker_reverts_emptyQuorums(uint256 pseudoRandomNumber) public { + function testBLSSignatureChecker_reverts_emptyQuorums( + uint256 pseudoRandomNumber + ) public { uint256 numNonSigners = pseudoRandomNumber % (maxOperatorsToRegister - 2) + 1; uint256 quorumBitmap = 1; - (uint32 referenceBlockNumber, BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature) = - _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(pseudoRandomNumber, numNonSigners, quorumBitmap); + ( + uint32 referenceBlockNumber, + BLSSignatureChecker.NonSignerStakesAndSignature memory nonSignerStakesAndSignature + ) = _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + pseudoRandomNumber, numNonSigners, quorumBitmap + ); // Create an empty quorumNumbers array bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(0); @@ -511,10 +576,7 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { // expect a non-specific low-level revert, since this call will ultimately fail as part of the precompile call cheats.expectRevert(IBLSSignatureCheckerErrors.InputEmptyQuorumNumbers.selector); blsSignatureChecker.checkSignatures( - msgHash, - quorumNumbers, - referenceBlockNumber, - nonSignerStakesAndSignature + msgHash, quorumNumbers, referenceBlockNumber, nonSignerStakesAndSignature ); } } diff --git a/test/unit/BitmapUtils.t.sol b/test/unit/BitmapUtils.t.sol index a998dbe3..1563d687 100644 --- a/test/unit/BitmapUtils.t.sol +++ b/test/unit/BitmapUtils.t.sol @@ -18,7 +18,9 @@ contract BitmapUtilsUnitTests is Test { contract BitmapUtilsUnitTests_bitwiseOperations is BitmapUtilsUnitTests { /// @notice check for consistency of `countNumOnes` function - function testFuzz_countNumOnes(uint256 input) public { + function testFuzz_countNumOnes( + uint256 input + ) public { uint16 libraryOutput = bitmapUtilsWrapper.countNumOnes(input); // run dumb routine uint16 numOnes = 0; @@ -37,7 +39,9 @@ contract BitmapUtilsUnitTests_bitwiseOperations is BitmapUtilsUnitTests { assertTrue(bitmapUtilsWrapper.isSet(255, 7), "isSet function is broken 2"); assertTrue(bitmapUtilsWrapper.isSet(1024, 10), "isSet function is broken 3"); for (uint256 i = 0; i < 256; ++i) { - assertTrue(bitmapUtilsWrapper.isSet(type(uint256).max, uint8(i)), "isSet function is broken 4"); + assertTrue( + bitmapUtilsWrapper.isSet(type(uint256).max, uint8(i)), "isSet function is broken 4" + ); assertFalse(bitmapUtilsWrapper.isSet(0, uint8(i)), "isSet function is broken 5"); } } @@ -46,12 +50,12 @@ contract BitmapUtilsUnitTests_bitwiseOperations is BitmapUtilsUnitTests { // Ensure that numberToAdd isn't already in the bitmap cheats.assume(bitmap | (1 << bitToSet) != bitmap); uint256 updatedBitmap = bitmapUtilsWrapper.setBit(bitmap, bitToSet); - assertTrue( - bitmapUtilsWrapper.isSet(updatedBitmap, bitToSet), "setBit function is broken" - ); + assertTrue(bitmapUtilsWrapper.isSet(updatedBitmap, bitToSet), "setBit function is broken"); } - function testFuzz_isEmpty(uint256 input) public { + function testFuzz_isEmpty( + uint256 input + ) public { if (input == 0) { // assertTrue(bitmapUtilsWrapper.isEmpty(input), "isEmpty function is broken"); assertTrue(bitmapUtilsWrapper.isEmpty(input), "isEmpty function is broken"); @@ -123,16 +127,24 @@ contract BitmapUtilsUnitTests_bytesArrayToBitmap is BitmapUtilsUnitTests { function test_EmptyArrayEncoding() public { bytes memory emptyBytesArray; uint256 returnedBitMap = bitmapUtilsWrapper.orderedBytesArrayToBitmap(emptyBytesArray); - assertEq(returnedBitMap, 0, "BitmapUtilsUnitTests.testEmptyArrayEncoding: empty array not encoded to empty bitmap"); + assertEq( + returnedBitMap, + 0, + "BitmapUtilsUnitTests.testEmptyArrayEncoding: empty array not encoded to empty bitmap" + ); } // ensure that the bitmap encoding of a single uint8 (i.e. a single byte) matches the expected output - function testFuzz_SingleByteEncoding(uint8 fuzzedNumber) public { + function testFuzz_SingleByteEncoding( + uint8 fuzzedNumber + ) public { bytes1 singleByte = bytes1(fuzzedNumber); bytes memory bytesArray = abi.encodePacked(singleByte); uint256 returnedBitMap = bitmapUtilsWrapper.orderedBytesArrayToBitmap(bytesArray); uint256 bitMask = uint256(1 << fuzzedNumber); - assertEq(returnedBitMap, bitMask, "BitmapUtilsUnitTests.testSingleByteEncoding: non-equivalence"); + assertEq( + returnedBitMap, bitMask, "BitmapUtilsUnitTests.testSingleByteEncoding: non-equivalence" + ); } // ensure that the bitmap encoding of a two uint8's (i.e. a two byte array) matches the expected output @@ -142,20 +154,28 @@ contract BitmapUtilsUnitTests_bytesArrayToBitmap is BitmapUtilsUnitTests { bytes1 secondSingleByte = bytes1(secondFuzzedNumber); bytes memory bytesArray = abi.encodePacked(firstSingleByte, secondSingleByte); if (firstFuzzedNumber == secondFuzzedNumber) { - cheats.expectRevert(bytes("BitmapUtils.orderedBytesArrayToBitmap: repeat entry in bytesArray")); + cheats.expectRevert( + bytes("BitmapUtils.orderedBytesArrayToBitmap: repeat entry in bytesArray") + ); bitmapUtilsWrapper.orderedBytesArrayToBitmap(bytesArray); } else { uint256 returnedBitMap = bitmapUtilsWrapper.orderedBytesArrayToBitmap(bytesArray); uint256 firstBitMask = uint256(1 << firstFuzzedNumber); uint256 secondBitMask = uint256(1 << secondFuzzedNumber); uint256 combinedBitMask = firstBitMask | secondBitMask; - assertEq(returnedBitMap, combinedBitMask, "BitmapUtilsUnitTests.testTwoByteEncoding: non-equivalence"); + assertEq( + returnedBitMap, + combinedBitMask, + "BitmapUtilsUnitTests.testTwoByteEncoding: non-equivalence" + ); } } // ensure that converting bytes array => bitmap => bytes array returns the original bytes array (i.e. is lossless and artifactless) // note that this only works on ordered arrays, because unordered arrays will be returned ordered - function testFuzz_BytesArrayToBitmapToBytesArray(bytes memory originalBytesArray) public { + function testFuzz_BytesArrayToBitmapToBytesArray( + bytes memory originalBytesArray + ) public { // filter down to only ordered inputs cheats.assume(bitmapUtilsWrapper.isArrayStrictlyAscendingOrdered(originalBytesArray)); uint256 bitmap = bitmapUtilsWrapper.orderedBytesArrayToBitmap(originalBytesArray); @@ -169,7 +189,9 @@ contract BitmapUtilsUnitTests_bytesArrayToBitmap is BitmapUtilsUnitTests { // ensure that converting bytes array => bitmap => bytes array returns the original bytes array (i.e. is lossless and artifactless) // note that this only works on ordered arrays - function testFuzz_BytesArrayToBitmapToBytesArray_OrderedVersion(bytes memory originalBytesArray) public { + function testFuzz_BytesArrayToBitmapToBytesArray_OrderedVersion( + bytes memory originalBytesArray + ) public { // filter down to only ordered inputs cheats.assume(bitmapUtilsWrapper.isArrayStrictlyAscendingOrdered(originalBytesArray)); uint256 bitmap = bitmapUtilsWrapper.orderedBytesArrayToBitmap(originalBytesArray); @@ -183,7 +205,9 @@ contract BitmapUtilsUnitTests_bytesArrayToBitmap is BitmapUtilsUnitTests { /// @notice Test that for non-strictly ascending bytes array ordering always reverts /// when calling orderedBytesArrayToBitmap - function testFuzz_OrderedBytesArrayToBitmap_Revert_WhenNotOrdered(bytes memory originalBytesArray) public { + function testFuzz_OrderedBytesArrayToBitmap_Revert_WhenNotOrdered( + bytes memory originalBytesArray + ) public { cheats.assume(!bitmapUtilsWrapper.isArrayStrictlyAscendingOrdered(originalBytesArray)); cheats.expectRevert(BitmapUtils.BytesArrayNotOrdered.selector); bitmapUtilsWrapper.orderedBytesArrayToBitmap(originalBytesArray); @@ -191,7 +215,9 @@ contract BitmapUtilsUnitTests_bytesArrayToBitmap is BitmapUtilsUnitTests { // ensure that converting bytes array => bitmap => bytes array returns the original bytes array (i.e. is lossless and artifactless) // note that this only works on ordered arrays - function testFuzz_BytesArrayToBitmapToBytesArray_OrderedVersion_Yul(bytes memory originalBytesArray) public { + function testFuzz_BytesArrayToBitmapToBytesArray_OrderedVersion_Yul( + bytes memory originalBytesArray + ) public { // filter down to only ordered inputs cheats.assume(bitmapUtilsWrapper.isArrayStrictlyAscendingOrdered(originalBytesArray)); uint256 bitmap = bitmapUtilsWrapper.orderedBytesArrayToBitmap(originalBytesArray); @@ -206,7 +232,14 @@ contract BitmapUtilsUnitTests_bytesArrayToBitmap is BitmapUtilsUnitTests { // testing one function for a specific input. used for comparing gas costs function test_BytesArrayToBitmap_OrderedVersion_SpecificInput() public { bytes memory originalBytesArray = abi.encodePacked( - bytes1(uint8(5)), bytes1(uint8(6)), bytes1(uint8(7)), bytes1(uint8(8)), bytes1(uint8(9)), bytes1(uint8(10)), bytes1(uint8(11)), bytes1(uint8(12)) + bytes1(uint8(5)), + bytes1(uint8(6)), + bytes1(uint8(7)), + bytes1(uint8(8)), + bytes1(uint8(9)), + bytes1(uint8(10)), + bytes1(uint8(11)), + bytes1(uint8(12)) ); uint256 gasLeftBefore = gasleft(); uint256 bitmap = bitmapUtilsWrapper.orderedBytesArrayToBitmap(originalBytesArray); @@ -219,7 +252,14 @@ contract BitmapUtilsUnitTests_bytesArrayToBitmap is BitmapUtilsUnitTests { // testing one function for a specific input. used for comparing gas costs function test_BytesArrayToBitmap_SpecificInput() public { bytes memory originalBytesArray = abi.encodePacked( - bytes1(uint8(5)), bytes1(uint8(6)), bytes1(uint8(7)), bytes1(uint8(8)), bytes1(uint8(9)), bytes1(uint8(10)), bytes1(uint8(11)), bytes1(uint8(12)) + bytes1(uint8(5)), + bytes1(uint8(6)), + bytes1(uint8(7)), + bytes1(uint8(8)), + bytes1(uint8(9)), + bytes1(uint8(10)), + bytes1(uint8(11)), + bytes1(uint8(12)) ); uint256 gasLeftBefore = gasleft(); uint256 bitmap = bitmapUtilsWrapper.orderedBytesArrayToBitmap(originalBytesArray); @@ -229,7 +269,9 @@ contract BitmapUtilsUnitTests_bytesArrayToBitmap is BitmapUtilsUnitTests { emit log_named_uint("gasSpent", gasSpent); } - function testFuzz_bitmapToBytesArrayToBitmap(uint256 originalBitmap) public { + function testFuzz_bitmapToBytesArrayToBitmap( + uint256 originalBitmap + ) public { uint256 gasLeftBefore = gasleft(); bytes memory bytesArray = bitmapUtilsWrapper.bitmapToBytesArray(originalBitmap); uint256 gasLeftAfter = gasleft(); @@ -256,7 +298,7 @@ contract BitmapUtilsUnitTests_bytesArrayToBitmap is BitmapUtilsUnitTests { function test_bitmapToBytesArrayToBitmap_distributedTenEntriesBitmap() public { // 2^0+2^10+2^20+2^30+2^40+2^50+2^60+2^70+2^80+2^90 - uint256 originalBitmap = 1239150146850664126585242625; + uint256 originalBitmap = 1_239_150_146_850_664_126_585_242_625; testFuzz_bitmapToBytesArrayToBitmap(originalBitmap); } } @@ -265,16 +307,37 @@ contract BitmapUtilsUnitTests_isArrayStrictlyAscendingOrdered is BitmapUtilsUnit function test_DifferentBytesArrayOrdering() public { // Descending order and duplicate element bytes arrays should return false bytes memory descendingBytesArray = abi.encodePacked( - bytes1(uint8(12)), bytes1(uint8(11)), bytes1(uint8(10)), bytes1(uint8(9)), bytes1(uint8(8)), bytes1(uint8(7)), bytes1(uint8(6)), bytes1(uint8(5)) + bytes1(uint8(12)), + bytes1(uint8(11)), + bytes1(uint8(10)), + bytes1(uint8(9)), + bytes1(uint8(8)), + bytes1(uint8(7)), + bytes1(uint8(6)), + bytes1(uint8(5)) ); assertFalse(bitmapUtilsWrapper.isArrayStrictlyAscendingOrdered(descendingBytesArray)); bytes memory duplicateBytesArray = abi.encodePacked( - bytes1(uint8(5)), bytes1(uint8(5)), bytes1(uint8(5)), bytes1(uint8(5)), bytes1(uint8(5)), bytes1(uint8(5)), bytes1(uint8(5)), bytes1(uint8(5)) + bytes1(uint8(5)), + bytes1(uint8(5)), + bytes1(uint8(5)), + bytes1(uint8(5)), + bytes1(uint8(5)), + bytes1(uint8(5)), + bytes1(uint8(5)), + bytes1(uint8(5)) ); assertFalse(bitmapUtilsWrapper.isArrayStrictlyAscendingOrdered(duplicateBytesArray)); // Strictly ascending returns true bytes memory ascendingBytesArray = abi.encodePacked( - bytes1(uint8(5)), bytes1(uint8(6)), bytes1(uint8(7)), bytes1(uint8(8)), bytes1(uint8(9)), bytes1(uint8(10)), bytes1(uint8(11)), bytes1(uint8(12)) + bytes1(uint8(5)), + bytes1(uint8(6)), + bytes1(uint8(7)), + bytes1(uint8(8)), + bytes1(uint8(9)), + bytes1(uint8(10)), + bytes1(uint8(11)), + bytes1(uint8(12)) ); assertTrue(bitmapUtilsWrapper.isArrayStrictlyAscendingOrdered(ascendingBytesArray)); // Empty bytes array and single element bytes array returns true diff --git a/test/unit/ECDSAStakeRegistryEqualWeightUnit.t.sol b/test/unit/ECDSAStakeRegistryEqualWeightUnit.t.sol index 0008da7f..2878e67d 100644 --- a/test/unit/ECDSAStakeRegistryEqualWeightUnit.t.sol +++ b/test/unit/ECDSAStakeRegistryEqualWeightUnit.t.sol @@ -2,89 +2,60 @@ pragma solidity ^0.8.27; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {IDelegationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; -import {ECDSAStakeRegistryEventsAndErrors, Quorum, StrategyParams} from "../../src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; +import { + ECDSAStakeRegistryEventsAndErrors, + Quorum, + StrategyParams +} from "../../src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; import {ECDSAStakeRegistrySetup} from "./ECDSAStakeRegistryUnit.t.sol"; -import {ECDSAStakeRegistryEqualWeight} from "../../src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol"; +import {ECDSAStakeRegistryEqualWeight} from + "../../src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol"; contract EqualWeightECDSARegistry is ECDSAStakeRegistrySetup { ECDSAStakeRegistryEqualWeight internal fixedWeightRegistry; function setUp() public virtual override { super.setUp(); - fixedWeightRegistry = new ECDSAStakeRegistryEqualWeight( - IDelegationManager(address(mockDelegationManager)) - ); + fixedWeightRegistry = + new ECDSAStakeRegistryEqualWeight(IDelegationManager(address(mockDelegationManager))); IStrategy mockStrategy = IStrategy(address(0x1234)); Quorum memory quorum = Quorum({strategies: new StrategyParams[](1)}); - quorum.strategies[0] = StrategyParams({ - strategy: mockStrategy, - multiplier: 10000 - }); - fixedWeightRegistry.initialize( - address(mockServiceManager), - 100, - quorum - ); + quorum.strategies[0] = StrategyParams({strategy: mockStrategy, multiplier: 10_000}); + fixedWeightRegistry.initialize(address(mockServiceManager), 100, quorum); fixedWeightRegistry.permitOperator(operator1); fixedWeightRegistry.permitOperator(operator2); ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; vm.prank(operator1); - fixedWeightRegistry.registerOperatorWithSignature( - operatorSignature, - operator1 - ); + fixedWeightRegistry.registerOperatorWithSignature(operatorSignature, operator1); vm.prank(operator2); - fixedWeightRegistry.registerOperatorWithSignature( - operatorSignature, - operator2 - ); + fixedWeightRegistry.registerOperatorWithSignature(operatorSignature, operator2); } function test_FixedStakeUpdates() public { - assertEq( - fixedWeightRegistry.getLastCheckpointOperatorWeight(operator1), - 1 - ); - assertEq( - fixedWeightRegistry.getLastCheckpointOperatorWeight(operator2), - 1 - ); + assertEq(fixedWeightRegistry.getLastCheckpointOperatorWeight(operator1), 1); + assertEq(fixedWeightRegistry.getLastCheckpointOperatorWeight(operator2), 1); assertEq(fixedWeightRegistry.getLastCheckpointTotalWeight(), 2); vm.roll(block.number + 1); vm.prank(operator1); fixedWeightRegistry.deregisterOperator(); - assertEq( - fixedWeightRegistry.getLastCheckpointOperatorWeight(operator1), - 0 - ); - assertEq( - fixedWeightRegistry.getLastCheckpointOperatorWeight(operator2), - 1 - ); + assertEq(fixedWeightRegistry.getLastCheckpointOperatorWeight(operator1), 0); + assertEq(fixedWeightRegistry.getLastCheckpointOperatorWeight(operator2), 1); assertEq(fixedWeightRegistry.getLastCheckpointTotalWeight(), 1); vm.roll(block.number + 1); ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; vm.prank(operator1); - fixedWeightRegistry.registerOperatorWithSignature( - operatorSignature, - operator1 - ); + fixedWeightRegistry.registerOperatorWithSignature(operatorSignature, operator1); - assertEq( - fixedWeightRegistry.getLastCheckpointOperatorWeight(operator1), - 1 - ); - assertEq( - fixedWeightRegistry.getLastCheckpointOperatorWeight(operator2), - 1 - ); + assertEq(fixedWeightRegistry.getLastCheckpointOperatorWeight(operator1), 1); + assertEq(fixedWeightRegistry.getLastCheckpointOperatorWeight(operator2), 1); assertEq(fixedWeightRegistry.getLastCheckpointTotalWeight(), 2); vm.roll(block.number + 1); @@ -93,14 +64,8 @@ contract EqualWeightECDSARegistry is ECDSAStakeRegistrySetup { operators[1] = operator2; fixedWeightRegistry.updateOperators(operators); - assertEq( - fixedWeightRegistry.getLastCheckpointOperatorWeight(operator1), - 1 - ); - assertEq( - fixedWeightRegistry.getLastCheckpointOperatorWeight(operator2), - 1 - ); + assertEq(fixedWeightRegistry.getLastCheckpointOperatorWeight(operator1), 1); + assertEq(fixedWeightRegistry.getLastCheckpointOperatorWeight(operator2), 1); assertEq(fixedWeightRegistry.getLastCheckpointTotalWeight(), 2); } } diff --git a/test/unit/ECDSAStakeRegistryPermissionedUnit.t.sol b/test/unit/ECDSAStakeRegistryPermissionedUnit.t.sol index 8205034d..ced14a41 100644 --- a/test/unit/ECDSAStakeRegistryPermissionedUnit.t.sol +++ b/test/unit/ECDSAStakeRegistryPermissionedUnit.t.sol @@ -2,46 +2,38 @@ pragma solidity ^0.8.27; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {IDelegationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; -import {ECDSAStakeRegistryEventsAndErrors, Quorum, StrategyParams} from "../../src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; +import { + ECDSAStakeRegistryEventsAndErrors, + Quorum, + StrategyParams +} from "../../src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; import {ECDSAStakeRegistrySetup} from "./ECDSAStakeRegistryUnit.t.sol"; -import {ECDSAStakeRegistryPermissioned} from "../../src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol"; +import {ECDSAStakeRegistryPermissioned} from + "../../src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol"; contract PermissionedECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { ECDSAStakeRegistryPermissioned internal permissionedRegistry; function setUp() public virtual override { super.setUp(); - permissionedRegistry = new ECDSAStakeRegistryPermissioned( - IDelegationManager(address(mockDelegationManager)) - ); + permissionedRegistry = + new ECDSAStakeRegistryPermissioned(IDelegationManager(address(mockDelegationManager))); IStrategy mockStrategy = IStrategy(address(0x1234)); Quorum memory quorum = Quorum({strategies: new StrategyParams[](1)}); - quorum.strategies[0] = StrategyParams({ - strategy: mockStrategy, - multiplier: 10000 - }); - permissionedRegistry.initialize( - address(mockServiceManager), - 100, - quorum - ); + quorum.strategies[0] = StrategyParams({strategy: mockStrategy, multiplier: 10_000}); + permissionedRegistry.initialize(address(mockServiceManager), 100, quorum); permissionedRegistry.permitOperator(operator1); permissionedRegistry.permitOperator(operator2); ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; vm.prank(operator1); - permissionedRegistry.registerOperatorWithSignature( - operatorSignature, - operator1 - ); + permissionedRegistry.registerOperatorWithSignature(operatorSignature, operator1); vm.prank(operator2); - permissionedRegistry.registerOperatorWithSignature( - operatorSignature, - operator1 - ); + permissionedRegistry.registerOperatorWithSignature(operatorSignature, operator1); } function test_RevertsWhen_NotOwner_PermitOperator() public { @@ -96,15 +88,10 @@ contract PermissionedECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; vm.expectRevert( - abi.encodeWithSelector( - ECDSAStakeRegistryPermissioned.OperatorNotAllowlisted.selector - ) + abi.encodeWithSelector(ECDSAStakeRegistryPermissioned.OperatorNotAllowlisted.selector) ); vm.prank(operator3); - permissionedRegistry.registerOperatorWithSignature( - operatorSignature, - operator3 - ); + permissionedRegistry.registerOperatorWithSignature(operatorSignature, operator3); } function test_WhenAllowlisted_RegisterOperatorWithSig() public { @@ -112,10 +99,7 @@ contract PermissionedECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { permissionedRegistry.permitOperator(operator3); ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; vm.prank(operator3); - permissionedRegistry.registerOperatorWithSignature( - operatorSignature, - operator3 - ); + permissionedRegistry.registerOperatorWithSignature(operatorSignature, operator3); } function test_DeregisterOperator() public { @@ -123,10 +107,7 @@ contract PermissionedECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { permissionedRegistry.permitOperator(operator3); ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; vm.prank(operator3); - permissionedRegistry.registerOperatorWithSignature( - operatorSignature, - operator3 - ); + permissionedRegistry.registerOperatorWithSignature(operatorSignature, operator3); vm.prank(operator3); permissionedRegistry.deregisterOperator(); diff --git a/test/unit/ECDSAStakeRegistryUnit.t.sol b/test/unit/ECDSAStakeRegistryUnit.t.sol index e1d7de77..89a4dc98 100644 --- a/test/unit/ECDSAStakeRegistryUnit.t.sol +++ b/test/unit/ECDSAStakeRegistryUnit.t.sol @@ -4,15 +4,22 @@ pragma solidity ^0.8.27; import {Test, console} from "forge-std/Test.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; -import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; +import {IDelegationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {ECDSAStakeRegistry} from "../../src/unaudited/ECDSAStakeRegistry.sol"; -import {ECDSAStakeRegistryEventsAndErrors, Quorum, StrategyParams} from "../../src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; +import { + ECDSAStakeRegistryEventsAndErrors, + Quorum, + StrategyParams +} from "../../src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; contract MockServiceManager { // solhint-disable-next-line - function deregisterOperatorFromAVS(address) external {} + function deregisterOperatorFromAVS( + address + ) external {} function registerOperatorToAVS( address, @@ -58,13 +65,8 @@ contract ECDSAStakeRegistrySetup is Test, ECDSAStakeRegistryEventsAndErrors { mockServiceManager = new MockServiceManager(); IStrategy mockStrategy = IStrategy(address(0x1234)); Quorum memory quorum = Quorum({strategies: new StrategyParams[](1)}); - quorum.strategies[0] = StrategyParams({ - strategy: mockStrategy, - multiplier: 10_000 - }); - registry = new ECDSAStakeRegistry( - IDelegationManager(address(mockDelegationManager)) - ); + quorum.strategies[0] = StrategyParams({strategy: mockStrategy, multiplier: 10_000}); + registry = new ECDSAStakeRegistry(IDelegationManager(address(mockDelegationManager))); registry.initialize(address(mockServiceManager), 100, quorum); ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; vm.prank(operator1); @@ -81,10 +83,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { Quorum memory oldQuorum = registry.quorum(); Quorum memory newQuorum = Quorum({strategies: new StrategyParams[](1)}); - newQuorum.strategies[0] = StrategyParams({ - strategy: mockStrategy, - multiplier: 10_000 - }); + newQuorum.strategies[0] = StrategyParams({strategy: mockStrategy, multiplier: 10_000}); address[] memory operators = new address[](2); operators[0] = operator1; operators[1] = operator2; @@ -96,9 +95,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { } function test_RevertsWhen_InvalidQuorum_UpdateQuourmConfig() public { - Quorum memory invalidQuorum = Quorum({ - strategies: new StrategyParams[](1) - }); + Quorum memory invalidQuorum = Quorum({strategies: new StrategyParams[](1)}); invalidQuorum.strategies[0] = StrategyParams({ /// TODO: Make mock strategy strategy: IStrategy(address(420)), @@ -108,20 +105,14 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { operators[0] = operator1; operators[1] = operator2; - vm.expectRevert( - ECDSAStakeRegistryEventsAndErrors.InvalidQuorum.selector - ); + vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.InvalidQuorum.selector); registry.updateQuorumConfig(invalidQuorum, operators); } function test_RevertsWhen_NotOwner_UpdateQuorumConfig() public { - Quorum memory validQuorum = Quorum({ - strategies: new StrategyParams[](1) - }); - validQuorum.strategies[0] = StrategyParams({ - strategy: IStrategy(address(420)), - multiplier: 10_000 - }); + Quorum memory validQuorum = Quorum({strategies: new StrategyParams[](1)}); + validQuorum.strategies[0] = + StrategyParams({strategy: IStrategy(address(420)), multiplier: 10_000}); address[] memory operators = new address[](2); operators[0] = operator1; @@ -145,60 +136,42 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { } function test_RevertSWhen_Duplicate_UpdateQuorumConfig() public { - Quorum memory invalidQuorum = Quorum({ - strategies: new StrategyParams[](2) - }); - invalidQuorum.strategies[0] = StrategyParams({ - strategy: IStrategy(address(420)), - multiplier: 5000 - }); + Quorum memory invalidQuorum = Quorum({strategies: new StrategyParams[](2)}); + invalidQuorum.strategies[0] = + StrategyParams({strategy: IStrategy(address(420)), multiplier: 5000}); address[] memory operators = new address[](2); operators[0] = operator1; operators[1] = operator2; - invalidQuorum.strategies[1] = StrategyParams({ - strategy: IStrategy(address(420)), - multiplier: 5000 - }); + invalidQuorum.strategies[1] = + StrategyParams({strategy: IStrategy(address(420)), multiplier: 5000}); vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.NotSorted.selector); registry.updateQuorumConfig(invalidQuorum, operators); } function test_RevertSWhen_NotSorted_UpdateQuorumConfig() public { - Quorum memory invalidQuorum = Quorum({ - strategies: new StrategyParams[](2) - }); - invalidQuorum.strategies[0] = StrategyParams({ - strategy: IStrategy(address(420)), - multiplier: 5000 - }); + Quorum memory invalidQuorum = Quorum({strategies: new StrategyParams[](2)}); + invalidQuorum.strategies[0] = + StrategyParams({strategy: IStrategy(address(420)), multiplier: 5000}); address[] memory operators = new address[](2); operators[0] = operator1; operators[1] = operator2; - invalidQuorum.strategies[1] = StrategyParams({ - strategy: IStrategy(address(419)), - multiplier: 5000 - }); + invalidQuorum.strategies[1] = + StrategyParams({strategy: IStrategy(address(419)), multiplier: 5000}); vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.NotSorted.selector); registry.updateQuorumConfig(invalidQuorum, operators); } function test_RevertSWhen_OverMultiplierTotal_UpdateQuorumConfig() public { - Quorum memory invalidQuorum = Quorum({ - strategies: new StrategyParams[](1) - }); - invalidQuorum.strategies[0] = StrategyParams({ - strategy: IStrategy(address(420)), - multiplier: 10_001 - }); + Quorum memory invalidQuorum = Quorum({strategies: new StrategyParams[](1)}); + invalidQuorum.strategies[0] = + StrategyParams({strategy: IStrategy(address(420)), multiplier: 10_001}); address[] memory operators = new address[](2); operators[0] = operator1; operators[1] = operator2; - vm.expectRevert( - ECDSAStakeRegistryEventsAndErrors.InvalidQuorum.selector - ); + vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.InvalidQuorum.selector); registry.updateQuorumConfig(invalidQuorum, operators); } @@ -211,23 +184,17 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { assertEq(registry.getLastCheckpointOperatorWeight(operator3), 1000); } - function test_RevertsWhen_AlreadyRegistered_RegisterOperatorWithSignature() - public - { + function test_RevertsWhen_AlreadyRegistered_RegisterOperatorWithSignature() public { assertEq(registry.getLastCheckpointOperatorWeight(operator1), 1000); assertEq(registry.getLastCheckpointTotalWeight(), 2000); ISignatureUtils.SignatureWithSaltAndExpiry memory signature; - vm.expectRevert( - ECDSAStakeRegistryEventsAndErrors.OperatorAlreadyRegistered.selector - ); + vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.OperatorAlreadyRegistered.selector); vm.prank(operator1); registry.registerOperatorWithSignature(signature, operator1); } - function test_RevertsWhen_SignatureIsInvalid_RegisterOperatorWithSignature() - public - { + function test_RevertsWhen_SignatureIsInvalid_RegisterOperatorWithSignature() public { bytes memory signatureData; vm.mockCall( address(mockServiceManager), @@ -258,9 +225,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { function test_RevertsWhen_NotOperator_DeregisterOperator() public { address notOperator = address(0x2); vm.prank(notOperator); - vm.expectRevert( - ECDSAStakeRegistryEventsAndErrors.OperatorNotRegistered.selector - ); + vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.OperatorNotRegistered.selector); registry.deregisterOperator(); } @@ -284,9 +249,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { operators[0] = operator1; registry.updateOperators(operators); - uint256 updatedWeight = registry.getLastCheckpointOperatorWeight( - operator1 - ); + uint256 updatedWeight = registry.getLastCheckpointOperatorWeight(operator1); assertEq(updatedWeight, 1000); } @@ -318,12 +281,8 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { registry.updateOperators(operators); - uint256 updatedWeight1 = registry.getLastCheckpointOperatorWeight( - operator1 - ); - uint256 updatedWeight2 = registry.getLastCheckpointOperatorWeight( - operator2 - ); + uint256 updatedWeight1 = registry.getLastCheckpointOperatorWeight(operator1); + uint256 updatedWeight2 = registry.getLastCheckpointOperatorWeight(operator2); assertEq(updatedWeight1, 1000); assertEq(updatedWeight2, 1000); } @@ -335,9 +294,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { registry.updateOperators(operators); - uint256 updatedWeight = registry.getLastCheckpointOperatorWeight( - operator1 - ); + uint256 updatedWeight = registry.getLastCheckpointOperatorWeight(operator1); assertEq(updatedWeight, 1000); } @@ -346,14 +303,8 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { IStrategy mockStrategy2 = IStrategy(address(421)); Quorum memory quorum = Quorum({strategies: new StrategyParams[](2)}); - quorum.strategies[0] = StrategyParams({ - strategy: mockStrategy, - multiplier: 5000 - }); - quorum.strategies[1] = StrategyParams({ - strategy: mockStrategy2, - multiplier: 5000 - }); + quorum.strategies[0] = StrategyParams({strategy: mockStrategy, multiplier: 5000}); + quorum.strategies[1] = StrategyParams({strategy: mockStrategy2, multiplier: 5000}); address[] memory operators = new address[](2); operators[0] = operator1; @@ -370,21 +321,15 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { vm.mockCall( address(mockDelegationManager), abi.encodeWithSelector( - MockDelegationManager.getOperatorShares.selector, - operator1, - strategies + MockDelegationManager.getOperatorShares.selector, operator1, strategies ), abi.encode(shares) ); registry.updateOperators(operators); - uint256 updatedWeight1 = registry.getLastCheckpointOperatorWeight( - operator1 - ); - uint256 updatedWeight2 = registry.getLastCheckpointOperatorWeight( - operator2 - ); + uint256 updatedWeight1 = registry.getLastCheckpointOperatorWeight(operator1); + uint256 updatedWeight2 = registry.getLastCheckpointOperatorWeight(operator2); assertEq(updatedWeight1, 525); assertEq(updatedWeight2, 1000); vm.roll(block.number + 1); @@ -465,10 +410,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { (v, r, s) = vm.sign(operator2Pk, msgHash); signatures[1] = abi.encodePacked(r, s, v); - registry.isValidSignature( - msgHash, - abi.encode(signers, signatures, block.number - 1) - ); + registry.isValidSignature(msgHash, abi.encode(signers, signatures, block.number - 1)); } function test_RevertsWhen_LengthMismatch_CheckSignatures() public { @@ -479,13 +421,8 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { (uint8 v, bytes32 r, bytes32 s) = vm.sign(operator1Pk, msgHash); signatures[0] = abi.encode(v, r, s); - vm.expectRevert( - ECDSAStakeRegistryEventsAndErrors.LengthMismatch.selector - ); - registry.isValidSignature( - msgHash, - abi.encode(signers, signatures, block.number - 1) - ); + vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.LengthMismatch.selector); + registry.isValidSignature(msgHash, abi.encode(signers, signatures, block.number - 1)); } function test_RevertsWhen_InvalidLength_CheckSignatures() public { @@ -493,13 +430,8 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { address[] memory signers = new address[](0); bytes[] memory signatures = new bytes[](0); - vm.expectRevert( - ECDSAStakeRegistryEventsAndErrors.InvalidLength.selector - ); - registry.isValidSignature( - dataHash, - abi.encode(signers, signatures, block.number - 1) - ); + vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.InvalidLength.selector); + registry.isValidSignature(dataHash, abi.encode(signers, signatures, block.number - 1)); } function test_RevertsWhen_NotSorted_CheckSignatures() public { @@ -514,10 +446,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { signatures[0] = abi.encodePacked(r, s, v); vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.NotSorted.selector); - registry.isValidSignature( - msgHash, - abi.encode(signers, signatures, block.number - 1) - ); + registry.isValidSignature(msgHash, abi.encode(signers, signatures, block.number - 1)); } function test_RevertsWhen_Duplicates_CheckSignatures() public { @@ -535,10 +464,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { signatures[1] = abi.encodePacked(r, s, v); vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.NotSorted.selector); - registry.isValidSignature( - msgHash, - abi.encode(signers, signatures, block.number - 1) - ); + registry.isValidSignature(msgHash, abi.encode(signers, signatures, block.number - 1)); } function test_RevetsWhen_InvalidSignature_CheckSignatures() public { @@ -548,13 +474,8 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { bytes[] memory signatures = new bytes[](1); signatures[0] = "invalid-signature"; - vm.expectRevert( - ECDSAStakeRegistryEventsAndErrors.InvalidSignature.selector - ); - registry.isValidSignature( - dataHash, - abi.encode(signers, signatures, block.number - 1) - ); + vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.InvalidSignature.selector); + registry.isValidSignature(dataHash, abi.encode(signers, signatures, block.number - 1)); } function test_RevertsWhen_InsufficientSignedStake_CheckSignatures() public { @@ -576,19 +497,13 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { vm.mockCall( address(registry), abi.encodeWithSelector( - ECDSAStakeRegistry.getLastCheckpointOperatorWeight.selector, - operator1 + ECDSAStakeRegistry.getLastCheckpointOperatorWeight.selector, operator1 ), abi.encode(50) ); - vm.expectRevert( - ECDSAStakeRegistryEventsAndErrors.InsufficientSignedStake.selector - ); - registry.isValidSignature( - msgHash, - abi.encode(signers, signatures, block.number - 1) - ); + vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.InsufficientSignedStake.selector); + registry.isValidSignature(msgHash, abi.encode(signers, signatures, block.number - 1)); } function test_RevertsWhen_LengthMismatch_CheckSignaturesAtBlock() public { @@ -599,13 +514,8 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { signers[1] = operator2; bytes[] memory signatures = new bytes[](1); - vm.expectRevert( - ECDSAStakeRegistryEventsAndErrors.LengthMismatch.selector - ); - registry.isValidSignature( - dataHash, - abi.encode(signers, signatures, referenceBlock) - ); + vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.LengthMismatch.selector); + registry.isValidSignature(dataHash, abi.encode(signers, signatures, referenceBlock)); } function test_RevertsWhen_InvalidLength_CheckSignaturesAtBlock() public { @@ -614,13 +524,8 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { address[] memory signers = new address[](0); bytes[] memory signatures = new bytes[](0); - vm.expectRevert( - ECDSAStakeRegistryEventsAndErrors.InvalidLength.selector - ); - registry.isValidSignature( - dataHash, - abi.encode(signers, signatures, referenceBlock) - ); + vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.InvalidLength.selector); + registry.isValidSignature(dataHash, abi.encode(signers, signatures, referenceBlock)); } function test_RevertsWhen_NotSorted_CheckSignaturesAtBlock() public { @@ -637,15 +542,10 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { signatures[0] = abi.encodePacked(r, s, v); vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.NotSorted.selector); - registry.isValidSignature( - msgHash, - abi.encode(signers, signatures, referenceBlock) - ); + registry.isValidSignature(msgHash, abi.encode(signers, signatures, referenceBlock)); } - function test_RevetsWhen_InsufficientSignedStake_CheckSignaturesAtBlock() - public - { + function test_RevetsWhen_InsufficientSignedStake_CheckSignaturesAtBlock() public { uint32 referenceBlock = 123; msgHash = keccak256("data"); signers = new address[](2); @@ -665,20 +565,13 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { vm.mockCall( address(registry), abi.encodeWithSelector( - ECDSAStakeRegistry.getOperatorWeightAtBlock.selector, - operator1, - referenceBlock + ECDSAStakeRegistry.getOperatorWeightAtBlock.selector, operator1, referenceBlock ), abi.encode(50) ); - vm.expectRevert( - ECDSAStakeRegistryEventsAndErrors.InsufficientSignedStake.selector - ); - registry.isValidSignature( - msgHash, - abi.encode(signers, signatures, referenceBlock) - ); + vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.InsufficientSignedStake.selector); + registry.isValidSignature(msgHash, abi.encode(signers, signatures, referenceBlock)); } function test_Gas_UpdateOperators() public { @@ -694,10 +587,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { for (uint256 i; i < operators.length; i++) { operators[i] = address(uint160(i)); vm.prank(operators[i]); - registry.registerOperatorWithSignature( - operatorSignature, - operators[i] - ); + registry.registerOperatorWithSignature(operatorSignature, operators[i]); } vm.resumeGasMetering(); registry.updateOperators(operators); @@ -723,10 +613,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { for (uint256 i = 1; i < operators.length + 1; i++) { operators[i - 1] = address(vm.addr(i)); vm.prank(operators[i - 1]); - registry.registerOperatorWithSignature( - operatorSignature, - operators[i - 1] - ); + registry.registerOperatorWithSignature(operatorSignature, operators[i - 1]); (v, r, s) = vm.sign(i, msgHash); signatures[i - 1] = abi.encodePacked(r, s, v); } @@ -735,10 +622,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { vm.roll(block.number + 1); vm.resumeGasMetering(); - registry.isValidSignature( - msgHash, - abi.encode(operators, signatures, block.number - 1) - ); + registry.isValidSignature(msgHash, abi.encode(operators, signatures, block.number - 1)); emit log_named_uint("Gas consumed", before - gasleft()); } @@ -759,9 +643,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { registry.registerOperatorWithSignature(operatorSignature, signer); // Verify that the signing key has been successfully registered for the operator - address registeredSigningKey = registry.getLastestOperatorSigningKey( - operator - ); + address registeredSigningKey = registry.getLastestOperatorSigningKey(operator); assertEq( registeredSigningKey, signer, @@ -783,15 +665,11 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { registry.updateOperatorSigningKey(address(420)); // Verify that the signing key has been successfully registered for the operator - address registeredSigningKey = registry.getLastestOperatorSigningKey( - operator - ); + address registeredSigningKey = registry.getLastestOperatorSigningKey(operator); vm.roll(block.number + 1); - registeredSigningKey = registry.getOperatorSigningKeyAtBlock( - operator, - uint32(block.number - 1) - ); + registeredSigningKey = + registry.getOperatorSigningKeyAtBlock(operator, uint32(block.number - 1)); assertEq( registeredSigningKey, address(420), @@ -820,10 +698,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { signatures[0] = abi.encodePacked(r, s, v); // Check signatures using the registered signing key - registry.isValidSignature( - dataHash, - abi.encode(operators, signatures, block.number - 1) - ); + registry.isValidSignature(dataHash, abi.encode(operators, signatures, block.number - 1)); } function test_WhenUsingSigningKey_CheckSignaturesAtBlock() public { @@ -835,10 +710,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { // Register operator with the initial signing key vm.prank(operator); - registry.registerOperatorWithSignature( - operatorSignature, - initialSigningKey - ); + registry.registerOperatorWithSignature(operatorSignature, initialSigningKey); vm.roll(block.number + 1); // Prepare data for signature with initial signing key @@ -852,10 +724,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { signatures[0] = abi.encodePacked(r, s, v); // Check signatures using the initial registered signing key - registry.isValidSignature( - dataHash, - abi.encode(operators, signatures, block.number - 1) - ); + registry.isValidSignature(dataHash, abi.encode(operators, signatures, block.number - 1)); // Increase block number vm.roll(block.number + 10); @@ -870,10 +739,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { signatures[0] = abi.encodePacked(r, s, v); // Check signatures using the updated registered signing key - registry.isValidSignature( - dataHash, - abi.encode(operators, signatures, block.number - 1) - ); + registry.isValidSignature(dataHash, abi.encode(operators, signatures, block.number - 1)); } function test_WhenUsingPriorSigningKey_CheckSignaturesAtBlock() public { @@ -885,10 +751,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { // Register operator with the initial signing key vm.prank(operator); - registry.registerOperatorWithSignature( - operatorSignature, - initialSigningKey - ); + registry.registerOperatorWithSignature(operatorSignature, initialSigningKey); vm.roll(block.number + 1); // Prepare data for signature with initial signing key @@ -909,10 +772,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { registry.updateOperatorSigningKey(updatedSigningKey); // Check signatures using the initial registered signing key at the previous block - registry.isValidSignature( - dataHash, - abi.encode(operators, signatures, block.number - 10) - ); + registry.isValidSignature(dataHash, abi.encode(operators, signatures, block.number - 10)); } function test_RevertsWhen_SigningCurrentBlock_IsValidSignature() public { @@ -929,15 +789,10 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { signatures[0] = signature; vm.expectRevert(abi.encodeWithSignature("InvalidReferenceBlock()")); - registry.isValidSignature( - dataHash, - abi.encode(operators, signatures, currentBlock) - ); + registry.isValidSignature(dataHash, abi.encode(operators, signatures, currentBlock)); } - function test_RevertsWhen_SigningKeyNotValidAtBlock_IsValidSignature() - public - { + function test_RevertsWhen_SigningKeyNotValidAtBlock_IsValidSignature() public { address operator = operator1; uint256 invalidSignerPk = signerPk + 1; address updatedSigningKey = address(vm.addr(invalidSignerPk)); @@ -958,20 +813,14 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { signatures[0] = signature; vm.expectRevert(abi.encodeWithSignature("InvalidSignature()")); - registry.isValidSignature( - dataHash, - abi.encode(operators, signatures, referenceBlock) - ); + registry.isValidSignature(dataHash, abi.encode(operators, signatures, referenceBlock)); } function _sort( address[] memory operators, bytes[] memory signatures ) internal pure returns (address[] memory, bytes[] memory) { - require( - operators.length == signatures.length, - "Operators and signatures length mismatch" - ); + require(operators.length == signatures.length, "Operators and signatures length mismatch"); uint256 length = operators.length; for (uint256 i = 0; i < length - 1; i++) { diff --git a/test/unit/EjectionManagerUnit.t.sol b/test/unit/EjectionManagerUnit.t.sol index a95366f7..2cfa859e 100644 --- a/test/unit/EjectionManagerUnit.t.sol +++ b/test/unit/EjectionManagerUnit.t.sol @@ -8,9 +8,10 @@ import {IEjectionManager, IEjectionManagerErrors} from "../../src/interfaces/IEj import "../utils/MockAVSDeployer.sol"; contract EjectionManagerUnitTests is MockAVSDeployer { - event EjectorUpdated(address ejector, bool status); - event QuorumEjectionParamsSet(uint8 quorumNumber, uint32 rateLimitWindow, uint16 ejectableStakePercent); + event QuorumEjectionParamsSet( + uint8 quorumNumber, uint32 rateLimitWindow, uint16 ejectableStakePercent + ); event OperatorEjected(bytes32 operatorId, uint8 quorumNumber); event FailedOperatorEjection(bytes32 operatorId, uint8 quorumNumber, bytes err); @@ -22,24 +23,24 @@ contract EjectionManagerUnitTests is MockAVSDeployer { uint32 public ratelimitWindow = 1 days; uint16 public ejectableStakePercent = 1000; - function setUp() virtual public { - for(uint8 i = 0; i < numQuorums; i++) { - quorumEjectionParams.push(IEjectionManager.QuorumEjectionParams({ - rateLimitWindow: ratelimitWindow, - ejectableStakePercent: ejectableStakePercent - })); + function setUp() public virtual { + for (uint8 i = 0; i < numQuorums; i++) { + quorumEjectionParams.push( + IEjectionManager.QuorumEjectionParams({ + rateLimitWindow: ratelimitWindow, + ejectableStakePercent: ejectableStakePercent + }) + ); } defaultMaxOperatorCount = 200; _deployMockEigenLayerAndAVS(); - ejectionManager = EjectionManager(address( - new TransparentUpgradeableProxy( - address(emptyContract), - address(proxyAdmin), - "" + ejectionManager = EjectionManager( + address( + new TransparentUpgradeableProxy(address(emptyContract), address(proxyAdmin), "") ) - )); + ); ejectionManagerImplementation = new EjectionManager(registryCoordinator, stakeRegistry); @@ -73,15 +74,19 @@ contract EjectionManagerUnitTests is MockAVSDeployer { bytes32[][] memory operatorIds = new bytes32[][](numQuorums); for (uint8 i = 0; i < numQuorums; i++) { operatorIds[i] = new bytes32[](operatorsToEject); - for (uint j = 0; j < operatorsToEject; j++) { - operatorIds[i][j] = registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); + for (uint256 j = 0; j < operatorsToEject; j++) { + operatorIds[i][j] = + registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); } } - assertEq(uint8(registryCoordinator.getOperatorStatus(defaultOperator)), uint8(IRegistryCoordinator.OperatorStatus.REGISTERED)); + assertEq( + uint8(registryCoordinator.getOperatorStatus(defaultOperator)), + uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) + ); - for(uint8 i = 0; i < numQuorums; i++) { - for(uint8 j = 0; j < operatorsToEject; j++) { + for (uint8 i = 0; i < numQuorums; i++) { + for (uint8 j = 0; j < operatorsToEject; j++) { cheats.expectEmit(true, true, true, true, address(ejectionManager)); emit OperatorEjected(operatorIds[i][j], i); } @@ -90,7 +95,10 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - assertEq(uint8(registryCoordinator.getOperatorStatus(defaultOperator)), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); + assertEq( + uint8(registryCoordinator.getOperatorStatus(defaultOperator)), + uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) + ); } function testEjectOperators_MultipleOperatorInsideRatelimit() public { @@ -102,17 +110,21 @@ contract EjectionManagerUnitTests is MockAVSDeployer { bytes32[][] memory operatorIds = new bytes32[][](numQuorums); for (uint8 i = 0; i < numQuorums; i++) { operatorIds[i] = new bytes32[](operatorsToEject); - for (uint j = 0; j < operatorsToEject; j++) { - operatorIds[i][j] = registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); + for (uint256 j = 0; j < operatorsToEject; j++) { + operatorIds[i][j] = + registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); } } - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) + ); } - for(uint8 i = 0; i < numQuorums; i++) { - for(uint8 j = 0; j < operatorsToEject; j++) { + for (uint8 i = 0; i < numQuorums; i++) { + for (uint8 j = 0; j < operatorsToEject; j++) { cheats.expectEmit(true, true, true, true, address(ejectionManager)); emit OperatorEjected(operatorIds[i][j], i); } @@ -121,8 +133,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) + ); } } @@ -136,17 +151,21 @@ contract EjectionManagerUnitTests is MockAVSDeployer { bytes32[][] memory operatorIds = new bytes32[][](numQuorums); for (uint8 i = 0; i < numQuorums; i++) { operatorIds[i] = new bytes32[](operatorsToEject); - for (uint j = 0; j < operatorsToEject; j++) { - operatorIds[i][j] = registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); + for (uint256 j = 0; j < operatorsToEject; j++) { + operatorIds[i][j] = + registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); } } - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) + ); } - for(uint8 i = 0; i < numQuorums; i++) { - for(uint8 j = 0; j < operatorsCanEject; j++) { + for (uint8 i = 0; i < numQuorums; i++) { + for (uint8 j = 0; j < operatorsCanEject; j++) { cheats.expectEmit(true, true, true, true, address(ejectionManager)); emit OperatorEjected(operatorIds[i][j], i); } @@ -155,12 +174,18 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsCanEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsCanEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) + ); } - for(uint8 i = operatorsCanEject; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = operatorsCanEject; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) + ); } } @@ -173,17 +198,21 @@ contract EjectionManagerUnitTests is MockAVSDeployer { bytes32[][] memory operatorIds = new bytes32[][](numQuorums); for (uint8 i = 0; i < numQuorums; i++) { operatorIds[i] = new bytes32[](operatorsToEject); - for (uint j = 0; j < operatorsToEject; j++) { - operatorIds[i][j] = registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); + for (uint256 j = 0; j < operatorsToEject; j++) { + operatorIds[i][j] = + registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); } } - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) + ); } - for(uint8 i = 0; i < numQuorums; i++) { - for(uint8 j = 0; j < operatorsToEject; j++) { + for (uint8 i = 0; i < numQuorums; i++) { + for (uint8 j = 0; j < operatorsToEject; j++) { cheats.expectEmit(true, true, true, true, address(ejectionManager)); emit OperatorEjected(operatorIds[i][j], i); } @@ -192,8 +221,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) + ); } cheats.warp(block.timestamp + (ratelimitWindow / 2)); @@ -201,17 +233,26 @@ contract EjectionManagerUnitTests is MockAVSDeployer { operatorIds = new bytes32[][](numQuorums); for (uint8 i = 0; i < numQuorums; i++) { operatorIds[i] = new bytes32[](operatorsToEject); - for (uint j = 0; j < operatorsToEject; j++) { - operatorIds[i][j] = registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, operatorsToEject + j)); + for (uint256 j = 0; j < operatorsToEject; j++) { + operatorIds[i][j] = registryCoordinator.getOperatorId( + _incrementAddress(defaultOperator, operatorsToEject + j) + ); } } - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, operatorsToEject + i))), uint8(IRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8( + registryCoordinator.getOperatorStatus( + _incrementAddress(defaultOperator, operatorsToEject + i) + ) + ), + uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) + ); } - for(uint8 i = 0; i < numQuorums; i++) { - for(uint8 j = 0; j < operatorsToEject; j++) { + for (uint8 i = 0; i < numQuorums; i++) { + for (uint8 j = 0; j < operatorsToEject; j++) { cheats.expectEmit(true, true, true, true, address(ejectionManager)); emit OperatorEjected(operatorIds[i][j], i); } @@ -220,8 +261,15 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, operatorsToEject + i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8( + registryCoordinator.getOperatorStatus( + _incrementAddress(defaultOperator, operatorsToEject + i) + ) + ), + uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) + ); } } @@ -241,17 +289,21 @@ contract EjectionManagerUnitTests is MockAVSDeployer { bytes32[][] memory operatorIds = new bytes32[][](numQuorums); for (uint8 i = 0; i < numQuorums; i++) { operatorIds[i] = new bytes32[](operatorsToEject); - for (uint j = 0; j < operatorsToEject; j++) { - operatorIds[i][j] = registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); + for (uint256 j = 0; j < operatorsToEject; j++) { + operatorIds[i][j] = + registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); } } - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) + ); } - for(uint8 i = 0; i < numQuorums; i++) { - for(uint8 j = 0; j < operatorsToEject; j++) { + for (uint8 i = 0; i < numQuorums; i++) { + for (uint8 j = 0; j < operatorsToEject; j++) { cheats.expectEmit(true, true, true, true, address(ejectionManager)); emit OperatorEjected(operatorIds[i][j], i); } @@ -260,8 +312,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) + ); } } @@ -274,17 +329,21 @@ contract EjectionManagerUnitTests is MockAVSDeployer { bytes32[][] memory operatorIds = new bytes32[][](numQuorums); for (uint8 i = 0; i < numQuorums; i++) { operatorIds[i] = new bytes32[](operatorsToEject); - for (uint j = 0; j < operatorsToEject; j++) { - operatorIds[i][j] = registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); + for (uint256 j = 0; j < operatorsToEject; j++) { + operatorIds[i][j] = + registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); } } - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) + ); } - for(uint8 i = 0; i < numQuorums; i++) { - for(uint8 j = 0; j < operatorsToEject; j++) { + for (uint8 i = 0; i < numQuorums; i++) { + for (uint8 j = 0; j < operatorsToEject; j++) { cheats.expectEmit(true, true, true, true, address(ejectionManager)); emit OperatorEjected(operatorIds[i][j], i); } @@ -293,8 +352,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(registryCoordinatorOwner); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) + ); } } @@ -307,20 +369,24 @@ contract EjectionManagerUnitTests is MockAVSDeployer { bytes32[][] memory operatorIds = new bytes32[][](numQuorums); for (uint8 i = 0; i < numQuorums; i++) { operatorIds[i] = new bytes32[](operatorsToEject); - for (uint j = 0; j < operatorsToEject; j++) { - operatorIds[i][j] = registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); + for (uint256 j = 0; j < operatorsToEject; j++) { + operatorIds[i][j] = + registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); } } cheats.prank(defaultOperator); registryCoordinator.deregisterOperator(BitmapUtils.bitmapToBytesArray(MAX_QUORUM_BITMAP)); - for(uint8 i = 1; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = 1; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) + ); } - for(uint8 i = 0; i < numQuorums; i++) { - for(uint8 j = 1; j < operatorsToEject; j++) { + for (uint8 i = 0; i < numQuorums; i++) { + for (uint8 j = 1; j < operatorsToEject; j++) { cheats.expectEmit(true, true, true, true, address(ejectionManager)); emit OperatorEjected(operatorIds[i][j], i); } @@ -329,8 +395,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) + ); } } @@ -338,7 +407,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { uint8 quorumNumber = 0; ratelimitWindow = 2 days; ejectableStakePercent = 2000; - IEjectionManager.QuorumEjectionParams memory _quorumEjectionParams = IEjectionManager.QuorumEjectionParams({ + IEjectionManager.QuorumEjectionParams memory _quorumEjectionParams = IEjectionManager + .QuorumEjectionParams({ rateLimitWindow: ratelimitWindow, ejectableStakePercent: ejectableStakePercent }); @@ -349,7 +419,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(registryCoordinatorOwner); ejectionManager.setQuorumEjectionParams(quorumNumber, _quorumEjectionParams); - (uint32 setRatelimitWindow, uint16 setEjectableStakePercent) = ejectionManager.quorumEjectionParams(quorumNumber); + (uint32 setRatelimitWindow, uint16 setEjectableStakePercent) = + ejectionManager.quorumEjectionParams(quorumNumber); assertEq(setRatelimitWindow, _quorumEjectionParams.rateLimitWindow); assertEq(setEjectableStakePercent, _quorumEjectionParams.ejectableStakePercent); } @@ -379,10 +450,13 @@ contract EjectionManagerUnitTests is MockAVSDeployer { function test_Overflow_Regression() public { cheats.prank(registryCoordinatorOwner); - ejectionManager.setQuorumEjectionParams(0, IEjectionManager.QuorumEjectionParams({ - rateLimitWindow: 7 days, - ejectableStakePercent: 9999 - })); + ejectionManager.setQuorumEjectionParams( + 0, + IEjectionManager.QuorumEjectionParams({ + rateLimitWindow: 7 days, + ejectableStakePercent: 9999 + }) + ); stakeRegistry.recordTotalStakeUpdate(1, 2_000_000_000 * 1 ether); @@ -390,7 +464,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } function _registerOperaters(uint8 numOperators, uint96 stake) internal { - for (uint i = 0; i < numOperators; i++) { + for (uint256 i = 0; i < numOperators; i++) { BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(i))); address operator = _incrementAddress(defaultOperator, i); _registerOperatorWithCoordinator(operator, MAX_QUORUM_BITMAP, pubKey, stake); diff --git a/test/unit/IndexRegistryUnit.t.sol b/test/unit/IndexRegistryUnit.t.sol index 79d74e91..8846ff9d 100644 --- a/test/unit/IndexRegistryUnit.t.sol +++ b/test/unit/IndexRegistryUnit.t.sol @@ -45,10 +45,11 @@ contract IndexRegistryUnitTests is MockAVSDeployer, IIndexRegistryEvents { _initializeQuorum(); } - /******************************************************************************* - INTERNAL UNIT TEST HELPERS - *******************************************************************************/ - + /** + * + * INTERNAL UNIT TEST HELPERS + * + */ function _initializeQuorum() internal { uint8 quorumNumber = nextQuorum; nextQuorum++; @@ -65,7 +66,9 @@ contract IndexRegistryUnitTests is MockAVSDeployer, IIndexRegistryEvents { } /// @dev Doesn't increment nextQuorum as assumes quorumNumber is any valid arbitrary quorumNumber - function _initializeQuorum(uint8 quorumNumber) internal { + function _initializeQuorum( + uint8 quorumNumber + ) internal { cheats.prank(address(registryCoordinator)); // Initialize quorum and mark registered @@ -75,10 +78,12 @@ contract IndexRegistryUnitTests is MockAVSDeployer, IIndexRegistryEvents { /// @dev initializeQuorum based on passed in bitmap of quorum numbers /// assumes that bitmap does not contain already initailized quorums and doesn't increment nextQuorum - function _initializeFuzzedQuorums(uint192 bitmap) internal { + function _initializeFuzzedQuorums( + uint192 bitmap + ) internal { bytes memory quorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray(bitmap); - for (uint i = 0; i < quorumNumbers.length; i++) { + for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); _initializeQuorum(quorumNumber); } @@ -100,7 +105,8 @@ contract IndexRegistryUnitTests is MockAVSDeployer, IIndexRegistryEvents { bytes memory quorumNumbers ) internal returns (uint32[] memory) { cheats.prank(address(registryCoordinator)); - uint32[] memory numOperatorsPerQuorum = indexRegistry.registerOperator(operatorId, quorumNumbers); + uint32[] memory numOperatorsPerQuorum = + indexRegistry.registerOperator(operatorId, quorumNumbers); return numOperatorsPerQuorum; } @@ -112,24 +118,19 @@ contract IndexRegistryUnitTests is MockAVSDeployer, IIndexRegistryEvents { bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(quorumNumber); cheats.prank(address(registryCoordinator)); - uint32[] memory numOperatorsPerQuorum = indexRegistry.registerOperator(operatorId, quorumNumbers); + uint32[] memory numOperatorsPerQuorum = + indexRegistry.registerOperator(operatorId, quorumNumbers); return numOperatorsPerQuorum[0]; } /// @dev deregister an operator for a given set of quorums - function _deregisterOperator( - bytes32 operatorId, - bytes memory quorumNumbers - ) internal { + function _deregisterOperator(bytes32 operatorId, bytes memory quorumNumbers) internal { cheats.prank(address(registryCoordinator)); indexRegistry.deregisterOperator(operatorId, quorumNumbers); } /// @dev deregister an operator for a single quorum - function _deregisterOperatorSingleQuorum( - bytes32 operatorId, - uint8 quorumNumber - ) internal { + function _deregisterOperatorSingleQuorum(bytes32 operatorId, uint8 quorumNumber) internal { bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(quorumNumber); cheats.prank(address(registryCoordinator)); @@ -138,15 +139,15 @@ contract IndexRegistryUnitTests is MockAVSDeployer, IIndexRegistryEvents { /// @dev Uses `rand` to return a random uint, with a range given by `min` and `max` (inclusive) /// @return `min` <= result <= `max` - function _randUint(bytes32 rand, uint min, uint max) internal pure returns (uint) { + function _randUint(bytes32 rand, uint256 min, uint256 max) internal pure returns (uint256) { // hashing makes for more uniform randomness rand = keccak256(abi.encodePacked(rand)); - uint range = max - min + 1; + uint256 range = max - min + 1; // calculate the number of bits needed for the range - uint bitsNeeded = 0; - uint tempRange = range; + uint256 bitsNeeded = 0; + uint256 tempRange = range; while (tempRange > 0) { bitsNeeded++; tempRange >>= 1; @@ -154,8 +155,8 @@ contract IndexRegistryUnitTests is MockAVSDeployer, IIndexRegistryEvents { // create a mask for the required number of bits // and extract the value from the hash - uint mask = (1 << bitsNeeded) - 1; - uint value = uint(rand) & mask; + uint256 mask = (1 << bitsNeeded) - 1; + uint256 value = uint256(rand) & mask; // in case value is out of range, wrap around or retry while (value >= range) { @@ -165,18 +166,19 @@ contract IndexRegistryUnitTests is MockAVSDeployer, IIndexRegistryEvents { return min + value; } - /******************************************************************************* - ASSERTION HELPERS - *******************************************************************************/ - + /** + * + * ASSERTION HELPERS + * + */ function _assertQuorumUpdate( uint8 quorumNumber, uint256 expectedNumOperators, uint256 expectedFromBlockNumber ) internal { // Check _totalOperatorsHistory updates for quorum - IIndexRegistry.QuorumUpdate memory quorumUpdate = indexRegistry - .getLatestQuorumUpdate(quorumNumber); + IIndexRegistry.QuorumUpdate memory quorumUpdate = + indexRegistry.getLatestQuorumUpdate(quorumNumber); assertEq( quorumUpdate.numOperators, expectedNumOperators, @@ -201,17 +203,11 @@ contract IndexRegistryUnitTests is MockAVSDeployer, IIndexRegistryEvents { bytes32 operatorId, uint256 expectedFromBlockNumber ) internal { - IIndexRegistry.OperatorUpdate memory operatorUpdate = indexRegistry - .getOperatorUpdateAtIndex(quorumNumber, operatorIndex, arrayIndex); + IIndexRegistry.OperatorUpdate memory operatorUpdate = + indexRegistry.getOperatorUpdateAtIndex(quorumNumber, operatorIndex, arrayIndex); + assertEq(operatorUpdate.operatorId, operatorId, "incorrect operatorId"); assertEq( - operatorUpdate.operatorId, - operatorId, - "incorrect operatorId" - ); - assertEq( - operatorUpdate.fromBlockNumber, - expectedFromBlockNumber, - "fromBlockNumber not correct" + operatorUpdate.fromBlockNumber, expectedFromBlockNumber, "fromBlockNumber not correct" ); } } @@ -222,10 +218,11 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { assertEq(address(indexRegistry.registryCoordinator()), address(registryCoordinator)); } - /******************************************************************************* - UNIT TESTS - GETTERS - *******************************************************************************/ - + /** + * + * UNIT TESTS - GETTERS + * + */ function _assertOperatorListsEqual( bytes32[] memory operatorList1, bytes32[] memory operatorList2, @@ -237,11 +234,7 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { ); for (uint256 i = 0; i < operatorList1.length; i++) { - assertEq( - operatorList1[i], - operatorList2[i], - "operator lists not equal" - ); + assertEq(operatorList1[i], operatorList2[i], "operator lists not equal"); } } @@ -266,11 +259,8 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { bytes32[] memory currRegisteredOperatorIds = new bytes32[](numOperators); uint256 currIndex = 0; for (uint256 i = 0; i < numOperators; i++) { - uint256 rand = _randUint({ - rand: keccak256(abi.encodePacked(bytes32(i), randSalt)), - min: 0, - max: 1 - }); + uint256 rand = + _randUint({rand: keccak256(abi.encodePacked(bytes32(i), randSalt)), min: 0, max: 1}); // Roll block number currBlockNumber += 10; @@ -282,7 +272,7 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { _deregisterOperatorSingleQuorum(operatorId, quorumNumber); currRegisteredOperatorIds[currIndex] = operatorId; currIndex--; - // register operator + // register operator } else { (, bytes32 operatorId) = _selectNewOperator(); _registerOperatorSingleQuorum(operatorId, quorumNumber); @@ -292,12 +282,11 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { } // should revert with startBlocknumber - cheats.expectRevert("IndexRegistry._operatorCountAtBlockNumber: quorum did not exist at given block number"); - - indexRegistry.getOperatorListAtBlockNumber( - quorumNumber, - startBlockNumber + cheats.expectRevert( + "IndexRegistry._operatorCountAtBlockNumber: quorum did not exist at given block number" ); + + indexRegistry.getOperatorListAtBlockNumber(quorumNumber, startBlockNumber); } } @@ -306,16 +295,16 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { * And keeping track of the total operators and their indexes. Checks that the return list of operatorIds * from `getOperatorListForQuorum` matches the expected list of operatorIds */ - function testFuzz_getOperatorListForQuorumAtBlockNumber(uint8 numOperators, bytes32 randSalt) public { + function testFuzz_getOperatorListForQuorumAtBlockNumber( + uint8 numOperators, + bytes32 randSalt + ) public { bytes32[] memory currRegisteredOperatorIds = new bytes32[](numOperators); uint256 currIndex = 0; uint32 currBlockNumber = uint32(block.number); for (uint256 i = 0; i < numOperators; i++) { - uint256 rand = _randUint({ - rand: keccak256(abi.encodePacked(bytes32(i), randSalt)), - min: 0, - max: 1 - }); + uint256 rand = + _randUint({rand: keccak256(abi.encodePacked(bytes32(i), randSalt)), min: 0, max: 1}); // Roll block number currBlockNumber += 10; @@ -327,7 +316,7 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { _deregisterOperatorSingleQuorum(operatorId, defaultQuorumNumber); currRegisteredOperatorIds[currIndex] = operatorId; currIndex--; - // register operator + // register operator } else { (, bytes32 operatorId) = _selectNewOperator(); _registerOperatorSingleQuorum(operatorId, defaultQuorumNumber); @@ -337,16 +326,10 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { } // Check operator list - bytes32[] memory operatorList = indexRegistry.getOperatorListAtBlockNumber( - defaultQuorumNumber, - currBlockNumber - ); + bytes32[] memory operatorList = + indexRegistry.getOperatorListAtBlockNumber(defaultQuorumNumber, currBlockNumber); - _assertOperatorListsEqual( - operatorList, - currRegisteredOperatorIds, - currIndex - ); + _assertOperatorListsEqual(operatorList, currRegisteredOperatorIds, currIndex); } } @@ -354,15 +337,15 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { * @dev Loop for numOperators randomly registering and deregistering operators for a single quorum. * Checks that the totalOperatorsForQuorum returns the correct total after each register/deregister */ - function testFuzz_TotalOperatorUpdatesForOneQuorum(uint8 numOperators, bytes32 randSalt) public { + function testFuzz_TotalOperatorUpdatesForOneQuorum( + uint8 numOperators, + bytes32 randSalt + ) public { bytes32[] memory currRegisteredOperatorIds = new bytes32[](numOperators); uint256 currIndex = 0; for (uint256 i = 0; i < numOperators; i++) { - uint256 rand = _randUint({ - rand: keccak256(abi.encodePacked(bytes32(i), randSalt)), - min: 0, - max: 1 - }); + uint256 rand = + _randUint({rand: keccak256(abi.encodePacked(bytes32(i), randSalt)), min: 0, max: 1}); // deregister operator, must also have at least one registered operator if (rand == 0 && currIndex > 0) { @@ -370,7 +353,7 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { _deregisterOperatorSingleQuorum(operatorId, defaultQuorumNumber); currRegisteredOperatorIds[currIndex] = operatorId; currIndex--; - // register operator + // register operator } else { (, bytes32 operatorId) = _selectNewOperator(); _registerOperatorSingleQuorum(operatorId, defaultQuorumNumber); @@ -388,7 +371,9 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { } } - function testFuzz_viewFunctions_Revert_WhenInvalidQuorumNumber(uint8 quorumNumber) public { + function testFuzz_viewFunctions_Revert_WhenInvalidQuorumNumber( + uint8 quorumNumber + ) public { cheats.assume(quorumNumber >= nextQuorum); cheats.expectRevert(); @@ -408,12 +393,14 @@ contract IndexRegistryUnitTests_configAndGetters is IndexRegistryUnitTests { contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { using BitmapUtils for *; - - /******************************************************************************* - UNIT TESTS - REGISTRATION - *******************************************************************************/ - - function testFuzz_Revert_WhenNonRegistryCoordinator(address nonRegistryCoordinator) public { + /** + * + * UNIT TESTS - REGISTRATION + * + */ + function testFuzz_Revert_WhenNonRegistryCoordinator( + address nonRegistryCoordinator + ) public { cheats.assume(nonRegistryCoordinator != address(registryCoordinator)); cheats.assume(nonRegistryCoordinator != proxyAdminOwner); bytes memory quorumNumbers = new bytes(defaultQuorumNumber); @@ -433,7 +420,8 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { cheats.assume(invalidBitmap > initializedQuorumBitmap); // mask out quorums that are already initialized and the quorums that are not going to be registered invalidBitmap = uint192(invalidBitmap.minus(uint256(initializedQuorumBitmap))); - bitmap = uint192(bitmap.minus(uint256(initializedQuorumBitmap)).minus(uint256(invalidBitmap))); + bitmap = + uint192(bitmap.minus(uint256(initializedQuorumBitmap)).minus(uint256(invalidBitmap))); // Initialize fuzzed quorum numbers _initializeFuzzedQuorums(bitmap); @@ -457,11 +445,7 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { (, bytes32 operatorId) = _selectNewOperator(); uint32 numOperators = _registerOperatorSingleQuorum(operatorId, defaultQuorumNumber); - assertEq( - numOperators, - 1, - "IndexRegistry.registerOperator: numOperators is not 1" - ); + assertEq(numOperators, 1, "IndexRegistry.registerOperator: numOperators is not 1"); // Check _totalOperatorsHistory updates _assertQuorumUpdate({ @@ -551,11 +535,7 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { uint32 numOperators = _registerOperatorSingleQuorum(operatorId2, defaultQuorumNumber); // Check return value - assertEq( - numOperators, - 2, - "IndexRegistry.registerOperator: numOperators not 2" - ); + assertEq(numOperators, 2, "IndexRegistry.registerOperator: numOperators not 2"); // Check _totalOperatorsHistory and _indexHistory updates for quorum _assertOperatorUpdate({ @@ -587,7 +567,9 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { * 4. quorumNumbers.length != 0 * 5. operator is not already registerd for any quorums being registered for */ - function testFuzz_registerOperator_MultipleQuorums(uint192 bitmap) public { + function testFuzz_registerOperator_MultipleQuorums( + uint192 bitmap + ) public { // mask out quorums that are already initialized bitmap = uint192(bitmap.minus(uint256(initializedQuorumBitmap))); bytes memory quorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray(bitmap); @@ -682,7 +664,11 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { for (uint256 i = 0; i < quorumNumbers.length; i++) { quorumUpdate = indexRegistry.getLatestQuorumUpdate(uint8(quorumNumbers[i])); assertEq(quorumUpdate.numOperators, numOperators, "num operators not correct"); - assertEq(quorumUpdate.fromBlockNumber, block.number, "latest update should be from current block number"); + assertEq( + quorumUpdate.fromBlockNumber, + block.number, + "latest update should be from current block number" + ); } } } @@ -690,10 +676,14 @@ contract IndexRegistryUnitTests_registerOperator is IndexRegistryUnitTests { contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { using BitmapUtils for *; - /******************************************************************************* - UNIT TESTS - DEREGISTRATION - *******************************************************************************/ - function testFuzz_Revert_WhenNonRegistryCoordinator(address nonRegistryCoordinator) public { + /** + * + * UNIT TESTS - DEREGISTRATION + * + */ + function testFuzz_Revert_WhenNonRegistryCoordinator( + address nonRegistryCoordinator + ) public { cheats.assume(nonRegistryCoordinator != address(registryCoordinator)); cheats.assume(nonRegistryCoordinator != address(proxyAdmin)); // de-register an operator @@ -714,7 +704,8 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { cheats.assume(invalidBitmap > initializedQuorumBitmap); // mask out quorums that are already initialized and the quorums that are not going to be registered invalidBitmap = uint192(invalidBitmap.minus(uint256(initializedQuorumBitmap))); - bitmap = uint192(bitmap.minus(uint256(initializedQuorumBitmap)).minus(uint256(invalidBitmap))); + bitmap = + uint192(bitmap.minus(uint256(initializedQuorumBitmap)).minus(uint256(invalidBitmap))); bytes memory quorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray(bitmap); bytes memory invalidQuorumNumbers = bitmapUtilsWrapper.bitmapToBytesArray(invalidBitmap); _initializeFuzzedQuorums(bitmap); @@ -831,10 +822,15 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { // get operator index, if operator index is new quorumCount // then other operator indexes are unchanged // otherwise the popped index operatorId will replace the deregistered operator's index - uint32 operatorIndex = IndexRegistry(address(indexRegistry)).currentOperatorIndex(quorumNumber, operatorId); - uint32 quorumCountBefore = indexRegistry.getLatestQuorumUpdate(quorumNumber).numOperators; - - assertTrue(operatorIndex <= quorumCountBefore - 1, "operator index should be less than quorumCount"); + uint32 operatorIndex = + IndexRegistry(address(indexRegistry)).currentOperatorIndex(quorumNumber, operatorId); + uint32 quorumCountBefore = + indexRegistry.getLatestQuorumUpdate(quorumNumber).numOperators; + + assertTrue( + operatorIndex <= quorumCountBefore - 1, + "operator index should be less than quorumCount" + ); bytes32 operatorIdAtBeforeQuorumCount = indexRegistry.getLatestOperatorUpdate({ quorumNumber: quorumNumber, operatorIndex: quorumCountBefore - 1 @@ -848,7 +844,11 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { _deregisterOperatorSingleQuorum(operatorId, quorumNumber); if (operatorIndex != quorumCountBefore - 1) { - assertNotEq(operatorIdAtBeforeQuorumCount, operatorId, "operatorId at currentQuorumCount - 1 should not be operatorId we are deregistering"); + assertNotEq( + operatorIdAtBeforeQuorumCount, + operatorId, + "operatorId at currentQuorumCount - 1 should not be operatorId we are deregistering" + ); _assertOperatorUpdate({ quorumNumber: quorumNumber, operatorIndex: operatorIndex, @@ -898,10 +898,15 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { // get operator index, if operator index is new quorumCount // then other operator indexes are unchanged // otherwise the popped index operatorId will replace the deregistered operator's index - uint32 operatorIndex = IndexRegistry(address(indexRegistry)).currentOperatorIndex(quorumNumber, operatorId); - uint32 quorumCountBefore = indexRegistry.getLatestQuorumUpdate(quorumNumber).numOperators; - - assertTrue(operatorIndex <= quorumCountBefore - 1, "operator index should be less than quorumCount"); + uint32 operatorIndex = + IndexRegistry(address(indexRegistry)).currentOperatorIndex(quorumNumber, operatorId); + uint32 quorumCountBefore = + indexRegistry.getLatestQuorumUpdate(quorumNumber).numOperators; + + assertTrue( + operatorIndex <= quorumCountBefore - 1, + "operator index should be less than quorumCount" + ); bytes32 operatorIdAtBeforeQuorumCount = indexRegistry.getLatestOperatorUpdate({ quorumNumber: quorumNumber, operatorIndex: quorumCountBefore - 1 @@ -991,7 +996,9 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { IIndexRegistry.OperatorUpdate memory operatorUpdate = indexRegistry .getLatestOperatorUpdate({quorumNumber: uint8(quorumsToRemove[i]), operatorIndex: 0}); - assertEq(operatorUpdate.fromBlockNumber, block.number, "fromBlockNumber not set correctly"); + assertEq( + operatorUpdate.fromBlockNumber, block.number, "fromBlockNumber not set correctly" + ); assertEq(operatorUpdate.operatorId, operatorId3, "incorrect operatorId"); } } @@ -1044,8 +1051,10 @@ contract IndexRegistryUnitTests_deregisterOperator is IndexRegistryUnitTests { // Check operator's index for removed quorums IIndexRegistry.OperatorUpdate memory operatorUpdate = indexRegistry .getLatestOperatorUpdate({quorumNumber: uint8(quorumsToRemove[i]), operatorIndex: 1}); - assertEq(operatorUpdate.fromBlockNumber, block.number, "fromBlockNumber not set correctly"); + assertEq( + operatorUpdate.fromBlockNumber, block.number, "fromBlockNumber not set correctly" + ); assertEq(operatorUpdate.operatorId, bytes32(0), "incorrect operatorId"); } } -} \ No newline at end of file +} diff --git a/test/unit/LibMergeSort.t.sol b/test/unit/LibMergeSort.t.sol index dc2ddf7d..53031359 100644 --- a/test/unit/LibMergeSort.t.sol +++ b/test/unit/LibMergeSort.t.sol @@ -95,94 +95,93 @@ contract LibMergeSortTest is Test { } } -function testMergeSortArrays_Sort() public { - address[] memory left = new address[](3); - address[] memory right = new address[](3); + function testMergeSortArrays_Sort() public { + address[] memory left = new address[](3); + address[] memory right = new address[](3); - left[0] = address(0x3); - left[1] = address(0x1); - left[2] = address(0x2); + left[0] = address(0x3); + left[1] = address(0x1); + left[2] = address(0x2); - right[0] = address(0x6); - right[1] = address(0x4); - right[2] = address(0x5); + right[0] = address(0x6); + right[1] = address(0x4); + right[2] = address(0x5); - left = left.sort(); - right = right.sort(); + left = left.sort(); + right = right.sort(); - address[] memory expected = new address[](6); - expected[0] = address(0x1); - expected[1] = address(0x2); - expected[2] = address(0x3); - expected[3] = address(0x4); - expected[4] = address(0x5); - expected[5] = address(0x6); + address[] memory expected = new address[](6); + expected[0] = address(0x1); + expected[1] = address(0x2); + expected[2] = address(0x3); + expected[3] = address(0x4); + expected[4] = address(0x5); + expected[5] = address(0x6); - address[] memory result = left.mergeSortArrays(right); + address[] memory result = left.mergeSortArrays(right); - for (uint256 i = 0; i < expected.length; i++) { - assertEq(result[i], expected[i], "Array elements are not sorted correctly"); + for (uint256 i = 0; i < expected.length; i++) { + assertEq(result[i], expected[i], "Array elements are not sorted correctly"); + } } -} -/// NOTE: we're assuming the input arrays themselves are unique. -/// Demonstrating behavior of library -function testMergeSortArraysWithDuplicateInLeft() public { - address[] memory left = new address[](4); - address[] memory right = new address[](3); - - left[0] = address(0x1); - left[1] = address(0x3); - left[2] = address(0x3); // Duplicate - left[3] = address(0x5); - - right[0] = address(0x2); - right[1] = address(0x4); - right[2] = address(0x6); - - address[] memory expected = new address[](7); - expected[0] = address(0x1); - expected[1] = address(0x2); - expected[2] = address(0x3); - expected[3] = address(0x3); - expected[4] = address(0x4); - expected[5] = address(0x5); - expected[6] = address(0x6); - - address[] memory result = left.mergeSortArrays(right); - - for (uint256 i = 0; i < expected.length; i++) { - assertEq(result[i], expected[i], "Array elements are not sorted correctly"); - } -} -function testMergeSortArraysWithDuplicateInRight() public { - address[] memory left = new address[](3); - address[] memory right = new address[](4); - - left[0] = address(0x1); - left[1] = address(0x3); - left[2] = address(0x5); - - right[0] = address(0x2); - right[1] = address(0x4); - right[2] = address(0x4); // Duplicate - right[3] = address(0x6); - - address[] memory expected = new address[](7); - expected[0] = address(0x1); - expected[1] = address(0x2); - expected[2] = address(0x3); - expected[3] = address(0x4); - expected[4] = address(0x4); - expected[5] = address(0x5); - expected[6] = address(0x6); - - address[] memory result = left.mergeSortArrays(right); - - for (uint256 i = 0; i < expected.length; i++) { - assertEq(result[i], expected[i], "Array elements are not sorted correctly"); + /// NOTE: we're assuming the input arrays themselves are unique. + /// Demonstrating behavior of library + function testMergeSortArraysWithDuplicateInLeft() public { + address[] memory left = new address[](4); + address[] memory right = new address[](3); + + left[0] = address(0x1); + left[1] = address(0x3); + left[2] = address(0x3); // Duplicate + left[3] = address(0x5); + + right[0] = address(0x2); + right[1] = address(0x4); + right[2] = address(0x6); + + address[] memory expected = new address[](7); + expected[0] = address(0x1); + expected[1] = address(0x2); + expected[2] = address(0x3); + expected[3] = address(0x3); + expected[4] = address(0x4); + expected[5] = address(0x5); + expected[6] = address(0x6); + + address[] memory result = left.mergeSortArrays(right); + + for (uint256 i = 0; i < expected.length; i++) { + assertEq(result[i], expected[i], "Array elements are not sorted correctly"); + } } -} + function testMergeSortArraysWithDuplicateInRight() public { + address[] memory left = new address[](3); + address[] memory right = new address[](4); + + left[0] = address(0x1); + left[1] = address(0x3); + left[2] = address(0x5); + + right[0] = address(0x2); + right[1] = address(0x4); + right[2] = address(0x4); // Duplicate + right[3] = address(0x6); + + address[] memory expected = new address[](7); + expected[0] = address(0x1); + expected[1] = address(0x2); + expected[2] = address(0x3); + expected[3] = address(0x4); + expected[4] = address(0x4); + expected[5] = address(0x5); + expected[6] = address(0x6); + + address[] memory result = left.mergeSortArrays(right); + for (uint256 i = 0; i < expected.length; i++) { + assertEq(result[i], expected[i], "Array elements are not sorted correctly"); + } + } } diff --git a/test/unit/OperatorStateRetrieverUnit.t.sol b/test/unit/OperatorStateRetrieverUnit.t.sol index 55f6aabd..e16621fc 100644 --- a/test/unit/OperatorStateRetrieverUnit.t.sol +++ b/test/unit/OperatorStateRetrieverUnit.t.sol @@ -94,7 +94,9 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { IStakeRegistry.StrategyParams({strategy: IStrategy(address(1000)), multiplier: 1e16}); cheats.prank(registryCoordinator.owner()); - registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, minimumStake, strategyParams); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams, minimumStake, strategyParams + ); cheats.expectRevert( "IndexRegistry._operatorCountAtBlockNumber: quorum did not exist at given block number" @@ -234,7 +236,9 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { IStakeRegistry.StrategyParams({strategy: IStrategy(address(1000)), multiplier: 1e16}); cheats.prank(registryCoordinator.owner()); - registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, minimumStake, strategyParams); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams, minimumStake, strategyParams + ); cheats.expectRevert(IStakeRegistryErrors.EmptyStakeHistory.selector); operatorStateRetriever.getCheckSignaturesIndices( @@ -356,7 +360,9 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { assertEq(checkSignaturesIndices.nonSignerStakeIndices[1][0], 0); } - function testGetOperatorState_Valid(uint256 pseudoRandomNumber) public { + function testGetOperatorState_Valid( + uint256 pseudoRandomNumber + ) public { // register random operators and get the expected indices within the quorums and the metadata for the operators ( OperatorMetadata[] memory operatorMetadatas, @@ -425,7 +431,9 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { ); } - function testCheckSignaturesIndices_NoNonSigners_Valid(uint256 pseudoRandomNumber) public { + function testCheckSignaturesIndices_NoNonSigners_Valid( + uint256 pseudoRandomNumber + ) public { ( OperatorMetadata[] memory operatorMetadatas, uint256[][] memory expectedOperatorOverallIndices @@ -490,7 +498,9 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { } } - function testCheckSignaturesIndices_FewNonSigners_Valid(uint256 pseudoRandomNumber) public { + function testCheckSignaturesIndices_FewNonSigners_Valid( + uint256 pseudoRandomNumber + ) public { ( OperatorMetadata[] memory operatorMetadatas, uint256[][] memory expectedOperatorOverallIndices diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index 048e0cf1..3b62098d 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -7,7 +7,6 @@ import {QuorumBitmapHistoryLib} from "../../src/libraries/QuorumBitmapHistoryLib import {BitmapUtils} from "../../src/libraries/BitmapUtils.sol"; import {console} from "forge-std/console.sol"; - contract RegistryCoordinatorUnitTests is MockAVSDeployer { using BN254 for BN254.G1Point; @@ -24,30 +23,20 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { event OperatorSocketUpdate(bytes32 indexed operatorId, string socket); /// @notice emitted whenever the stake of `operator` is updated - event OperatorStakeUpdate( - bytes32 indexed operatorId, - uint8 quorumNumber, - uint96 stake - ); + event OperatorStakeUpdate(bytes32 indexed operatorId, uint8 quorumNumber, uint96 stake); // Emitted when a new operator pubkey is registered for a set of quorums - event OperatorAddedToQuorums( - address operator, - bytes32 operatorId, - bytes quorumNumbers - ); + event OperatorAddedToQuorums(address operator, bytes32 operatorId, bytes quorumNumbers); // Emitted when an operator pubkey is removed from a set of quorums - event OperatorRemovedFromQuorums( - address operator, - bytes32 operatorId, - bytes quorumNumbers - ); + event OperatorRemovedFromQuorums(address operator, bytes32 operatorId, bytes quorumNumbers); // emitted when an operator's index in the orderd operator list for the quorum with number `quorumNumber` is updated event QuorumIndexUpdate(bytes32 indexed operatorId, uint8 quorumNumber, uint32 newIndex); - event OperatorSetParamsUpdated(uint8 indexed quorumNumber, IRegistryCoordinator.OperatorSetParam operatorSetParams); + event OperatorSetParamsUpdated( + uint8 indexed quorumNumber, IRegistryCoordinator.OperatorSetParam operatorSetParams + ); event ChurnApproverUpdated(address prevChurnApprover, address newChurnApprover); @@ -55,7 +44,7 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { event QuorumBlockNumberUpdated(uint8 indexed quorumNumber, uint256 blocknumber); - function setUp() virtual public { + function setUp() public virtual { _deployMockEigenLayerAndAVS(numQuorums); } @@ -63,26 +52,31 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { uint256 pseudoRandomNumber, bytes memory quorumNumbers, uint96 operatorToKickStake - ) internal returns( - address operatorToRegister, - BN254.G1Point memory operatorToRegisterPubKey, - IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams - ) { + ) + internal + returns ( + address operatorToRegister, + BN254.G1Point memory operatorToRegisterPubKey, + IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams + ) + { uint32 kickRegistrationBlockNumber = 100; uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); cheats.roll(kickRegistrationBlockNumber); - for (uint i = 0; i < defaultMaxOperatorCount - 1; i++) { - BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); + for (uint256 i = 0; i < defaultMaxOperatorCount - 1; i++) { + BN254.G1Point memory pubKey = + BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); address operator = _incrementAddress(defaultOperator, i); _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); } operatorToRegister = _incrementAddress(defaultOperator, defaultMaxOperatorCount); - operatorToRegisterPubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, defaultMaxOperatorCount))); + operatorToRegisterPubKey = + BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, defaultMaxOperatorCount))); bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); bytes32 operatorToKickId; address operatorToKick; @@ -90,12 +84,16 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { // register last operator before kick operatorKickParams = new IRegistryCoordinator.OperatorKickParam[](1); { - BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, defaultMaxOperatorCount - 1))); + BN254.G1Point memory pubKey = BN254.hashToG1( + keccak256(abi.encodePacked(pseudoRandomNumber, defaultMaxOperatorCount - 1)) + ); operatorToKickId = BN254.hashG1Point(pubKey); operatorToKick = _incrementAddress(defaultOperator, defaultMaxOperatorCount - 1); // register last operator with much more than the kickBIPsOfTotalStake stake - _registerOperatorWithCoordinator(operatorToKick, quorumBitmap, pubKey, operatorToKickStake); + _registerOperatorWithCoordinator( + operatorToKick, quorumBitmap, pubKey, operatorToKickStake + ); bytes32[] memory operatorIdsToSwap = new bytes32[](1); // operatorIdsToSwap[0] = operatorToRegisterId @@ -118,7 +116,7 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina assertEq(address(registryCoordinator.indexRegistry()), address(indexRegistry)); assertEq(address(registryCoordinator.serviceManager()), address(serviceManager)); - for (uint i = 0; i < numQuorums; i++) { + for (uint256 i = 0; i < numQuorums; i++) { assertEq( keccak256(abi.encode(registryCoordinator.getOperatorSetParams(uint8(i)))), keccak256(abi.encode(operatorSetParams[i])) @@ -131,7 +129,7 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina registryCoordinatorOwner, churnApprover, ejector, - 0/*initialPausedStatus*/, + 0, /*initialPausedStatus*/ operatorSetParams, new uint96[](0), new IStakeRegistry.StrategyParams[][](0), @@ -145,8 +143,11 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina cheats.expectEmit(true, true, true, true, address(registryCoordinator)); emit OperatorSetParamsUpdated(0, operatorSetParams[1]); registryCoordinator.setOperatorSetParams(0, operatorSetParams[1]); - assertEq(keccak256(abi.encode(registryCoordinator.getOperatorSetParams(0))),keccak256(abi.encode(operatorSetParams[1])), - "operator set params not updated correctly"); + assertEq( + keccak256(abi.encode(registryCoordinator.getOperatorSetParams(0))), + keccak256(abi.encode(operatorSetParams[1])), + "operator set params not updated correctly" + ); } function test_setOperatorSetParams_revert_notOwner() public { @@ -198,7 +199,6 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina cheats.expectEmit(true, true, true, true, address(registryCoordinator)); emit OperatorSocketUpdate(defaultOperatorId, "localhost:32004"); registryCoordinator.updateSocket("localhost:32004"); - } function test_updateSocket_revert_notRegistered() public { @@ -214,7 +214,9 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina cheats.expectRevert("Ownable: caller is not the owner"); cheats.prank(defaultOperator); - registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, minimumStake, strategyParams); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams, minimumStake, strategyParams + ); } function test_createQuorum() public { @@ -222,26 +224,26 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina // this is necessary since the default setup already configures the max number of quorums, preventing adding more _deployMockEigenLayerAndAVS(0); - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = - IRegistryCoordinator.OperatorSetParam({ - maxOperatorCount: defaultMaxOperatorCount, - kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, - kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake - }); + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator + .OperatorSetParam({ + maxOperatorCount: defaultMaxOperatorCount, + kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, + kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake + }); uint96 minimumStake = 1; - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](1); strategyParams[0] = - IStakeRegistry.StrategyParams({ - strategy: IStrategy(address(1000)), - multiplier: 1e16 - }); + IStakeRegistry.StrategyParams({strategy: IStrategy(address(1000)), multiplier: 1e16}); uint8 quorumCountBefore = registryCoordinator.quorumCount(); cheats.expectEmit(true, true, true, true, address(registryCoordinator)); emit OperatorSetParamsUpdated(quorumCountBefore, operatorSetParams); cheats.prank(registryCoordinatorOwner); - registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, minimumStake, strategyParams); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams, minimumStake, strategyParams + ); uint8 quorumCountAfter = registryCoordinator.quorumCount(); assertEq(quorumCountAfter, quorumCountBefore + 1, "quorum count did not increase properly"); @@ -256,7 +258,6 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina } contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUnitTests { - function test_registerOperator_revert_paused() public { bytes memory emptyQuorumNumbers = new bytes(0); ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; @@ -267,7 +268,9 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni cheats.startPrank(defaultOperator); cheats.expectRevert(bytes4(keccak256("CurrentlyPaused()"))); - registryCoordinator.registerOperator(emptyQuorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + emptyQuorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); } function test_registerOperator_revert_emptyQuorumNumbers() public { @@ -276,7 +279,9 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni cheats.expectRevert(bytes4(keccak256("BitmapEmpty()"))); cheats.prank(defaultOperator); - registryCoordinator.registerOperator(emptyQuorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + emptyQuorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); } function test_registerOperator_revert_invalidQuorum() public { @@ -287,7 +292,9 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni cheats.expectRevert(BitmapUtils.BitmapValueTooLarge.selector); cheats.prank(defaultOperator); - registryCoordinator.registerOperator(quorumNumbersTooLarge, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbersTooLarge, defaultSocket, pubkeyRegistrationParams, emptySig + ); } function test_registerOperator_revert_nonexistentQuorum() public { @@ -299,7 +306,9 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni cheats.prank(defaultOperator); cheats.expectRevert(BitmapUtils.BitmapValueTooLarge.selector); - registryCoordinator.registerOperator(quorumNumbersNotCreated, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbersNotCreated, defaultSocket, pubkeyRegistrationParams, emptySig + ); } function test_registerOperator_singleQuorum() public { @@ -320,7 +329,9 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni uint256 gasBefore = gasleft(); cheats.prank(defaultOperator); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); uint256 gasAfter = gasleft(); emit log_named_uint("gasUsed, register for single quorum", gasBefore - gasAfter); @@ -329,24 +340,36 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: IRegistryCoordinator.OperatorStatus.REGISTERED + }) + ) + ) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }) + ) + ) ); } // @notice tests registering an operator for a fuzzed assortment of quorums - function testFuzz_registerOperator(uint256 quorumBitmap) public { + function testFuzz_registerOperator( + uint256 quorumBitmap + ) public { // filter the fuzzed input down to only valid quorums quorumBitmap = quorumBitmap & MAX_QUORUM_BITMAP; ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; @@ -354,7 +377,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); uint96 actualStake; - for (uint i = 0; i < quorumNumbers.length; i++) { + for (uint256 i = 0; i < quorumNumbers.length; i++) { actualStake = _setOperatorWeight(defaultOperator, uint8(quorumNumbers[i]), defaultStake); } @@ -366,19 +389,21 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); emit OperatorAddedToQuorums(defaultOperator, defaultOperatorId, quorumNumbers); - for (uint i = 0; i < quorumNumbers.length; i++) { + for (uint256 i = 0; i < quorumNumbers.length; i++) { cheats.expectEmit(true, true, true, true, address(stakeRegistry)); emit OperatorStakeUpdate(defaultOperatorId, uint8(quorumNumbers[i]), actualStake); } - for (uint i = 0; i < quorumNumbers.length; i++) { + for (uint256 i = 0; i < quorumNumbers.length; i++) { cheats.expectEmit(true, true, true, true, address(indexRegistry)); emit QuorumIndexUpdate(defaultOperatorId, uint8(quorumNumbers[i]), 0); } uint256 gasBefore = gasleft(); cheats.prank(defaultOperator); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); uint256 gasAfter = gasleft(); emit log_named_uint("gasUsed", gasBefore - gasAfter); emit log_named_uint("numQuorums", quorumNumbers.length); @@ -386,19 +411,29 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: IRegistryCoordinator.OperatorStatus.REGISTERED + }) + ) + ) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }) + ) + ) ); } @@ -414,12 +449,15 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); cheats.prank(defaultOperator); cheats.roll(registrationBlockNumber); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); bytes memory newQuorumNumbers = new bytes(1); - newQuorumNumbers[0] = bytes1(defaultQuorumNumber+1); + newQuorumNumbers[0] = bytes1(defaultQuorumNumber + 1); - uint96 actualStake = _setOperatorWeight(defaultOperator, uint8(newQuorumNumbers[0]), defaultStake); + uint96 actualStake = + _setOperatorWeight(defaultOperator, uint8(newQuorumNumbers[0]), defaultStake); cheats.expectEmit(true, true, true, true, address(registryCoordinator)); emit OperatorSocketUpdate(defaultOperatorId, defaultSocket); cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); @@ -430,38 +468,59 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni emit QuorumIndexUpdate(defaultOperatorId, uint8(newQuorumNumbers[0]), 0); cheats.roll(nextRegistrationBlockNumber); cheats.prank(defaultOperator); - registryCoordinator.registerOperator(newQuorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + newQuorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); - uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers) | BitmapUtils.orderedBytesArrayToBitmap(newQuorumNumbers); + uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers) + | BitmapUtils.orderedBytesArrayToBitmap(newQuorumNumbers); assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: IRegistryCoordinator.OperatorStatus.REGISTERED + }) + ) + ) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers)), - updateBlockNumber: uint32(registrationBlockNumber), - nextUpdateBlockNumber: uint32(nextRegistrationBlockNumber) - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers)), + updateBlockNumber: uint32(registrationBlockNumber), + nextUpdateBlockNumber: uint32(nextRegistrationBlockNumber) + }) + ) + ) ); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(nextRegistrationBlockNumber), - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1)) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(nextRegistrationBlockNumber), + nextUpdateBlockNumber: 0 + }) + ) + ) ); } - function test_registerOperator_revert_overFilledQuorum(uint256 pseudoRandomNumber) public { + function test_registerOperator_revert_overFilledQuorum( + uint256 pseudoRandomNumber + ) public { uint32 numOperators = defaultMaxOperatorCount; uint32 registrationBlockNumber = 200; ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; @@ -473,15 +532,17 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni cheats.roll(registrationBlockNumber); - for (uint i = 0; i < numOperators; i++) { - BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); + for (uint256 i = 0; i < numOperators; i++) { + BN254.G1Point memory pubKey = + BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); address operator = _incrementAddress(defaultOperator, i); _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); } address operatorToRegister = _incrementAddress(defaultOperator, numOperators); - BN254.G1Point memory operatorToRegisterPubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, numOperators))); + BN254.G1Point memory operatorToRegisterPubKey = + BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, numOperators))); blsApkRegistry.setBLSPublicKey(operatorToRegister, operatorToRegisterPubKey); @@ -489,7 +550,9 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni cheats.prank(operatorToRegister); cheats.expectRevert(bytes4(keccak256("MaxQuorumsReached()"))); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); } function test_registerOperator_revert_operatorAlreadyRegisteredForQuorum() public { @@ -504,12 +567,16 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni cheats.prank(defaultOperator); cheats.roll(registrationBlockNumber); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); cheats.prank(defaultOperator); cheats.roll(nextRegistrationBlockNumber); cheats.expectRevert(bytes4(keccak256("AlreadyRegisteredForQuorums()"))); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); } // tests for the internal `_registerOperator` function: @@ -518,7 +585,9 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; cheats.expectRevert(bytes4(keccak256("BitmapEmpty()"))); - registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, emptyQuorumNumbers, defaultSocket, emptySig); + registryCoordinator._registerOperatorExternal( + defaultOperator, defaultOperatorId, emptyQuorumNumbers, defaultSocket, emptySig + ); } function test_registerOperatorInternal_revert_nonexistentQuorum() public { @@ -528,7 +597,9 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni quorumNumbersTooLarge[0] = 0xC0; cheats.expectRevert(BitmapUtils.BitmapValueTooLarge.selector); - registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, quorumNumbersTooLarge, defaultSocket, emptySig); + registryCoordinator._registerOperatorExternal( + defaultOperator, defaultOperatorId, quorumNumbersTooLarge, defaultSocket, emptySig + ); } function test_registerOperatorInternal_revert_operatorAlreadyRegisteredForQuorum() public { @@ -537,10 +608,14 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni quorumNumbers[0] = bytes1(defaultQuorumNumber); _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); - registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, quorumNumbers, defaultSocket, emptySig); + registryCoordinator._registerOperatorExternal( + defaultOperator, defaultOperatorId, quorumNumbers, defaultSocket, emptySig + ); cheats.expectRevert(bytes4(keccak256("AlreadyRegisteredForQuorums()"))); - registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, quorumNumbers, defaultSocket, emptySig); + registryCoordinator._registerOperatorExternal( + defaultOperator, defaultOperatorId, quorumNumbers, defaultSocket, emptySig + ); } function test_registerOperatorInternal() public { @@ -559,32 +634,46 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni cheats.expectEmit(true, true, true, true, address(indexRegistry)); emit QuorumIndexUpdate(defaultOperatorId, defaultQuorumNumber, 0); - registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, quorumNumbers, defaultSocket, emptySig); + registryCoordinator._registerOperatorExternal( + defaultOperator, defaultOperatorId, quorumNumbers, defaultSocket, emptySig + ); uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: IRegistryCoordinator.OperatorStatus.REGISTERED + }) + ) + ) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }) + ) + ) ); } } // @dev note that this contract also contains tests for the `getQuorumBitmapIndicesAtBlockNumber` and `getQuorumBitmapAtBlockNumberByIndex` view fncs -contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is RegistryCoordinatorUnitTests { +contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is + RegistryCoordinatorUnitTests +{ function test_deregisterOperator_revert_paused() public { bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); @@ -641,7 +730,9 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.roll(registrationBlockNumber); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); @@ -659,25 +750,37 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.DEREGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: IRegistryCoordinator.OperatorStatus.DEREGISTERED + }) + ) + ) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }) + ) + ) ); } // @notice verifies that an operator who was registered for a fuzzed set of quorums can be deregistered // @dev deregisters the operator from *all* quorums for which they we registered. - function testFuzz_deregisterOperator_fuzzedQuorumAndSingleOperator(uint256 quorumBitmap) public { + function testFuzz_deregisterOperator_fuzzedQuorumAndSingleOperator( + uint256 quorumBitmap + ) public { ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; uint32 registrationBlockNumber = 100; uint32 deregistrationBlockNumber = 200; @@ -687,7 +790,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.assume(quorumBitmap != 0); bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - for (uint i = 0; i < quorumNumbers.length; i++) { + for (uint256 i = 0; i < quorumNumbers.length; i++) { _setOperatorWeight(defaultOperator, uint8(quorumNumbers[i]), defaultStake); } @@ -695,11 +798,13 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.roll(registrationBlockNumber); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); emit OperatorRemovedFromQuorums(defaultOperator, defaultOperatorId, quorumNumbers); - for (uint i = 0; i < quorumNumbers.length; i++) { + for (uint256 i = 0; i < quorumNumbers.length; i++) { cheats.expectEmit(true, true, true, true, address(stakeRegistry)); emit OperatorStakeUpdate(defaultOperatorId, uint8(quorumNumbers[i]), 0); } @@ -714,23 +819,34 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.DEREGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: IRegistryCoordinator.OperatorStatus.DEREGISTERED + }) + ) + ) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }) + ) + ) ); } // @notice verifies that an operator who was registered for a fuzzed set of quorums can be deregistered from a subset of those quorums // @dev deregisters the operator from a fuzzed subset of the quorums for which they we registered. + function testFuzz_deregisterOperator_singleOperator_partialDeregistration( uint256 registrationQuorumBitmap, uint256 deregistrationQuorumBitmap @@ -745,9 +861,10 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // filter the other fuzzed input to a subset of the first fuzzed input deregistrationQuorumBitmap = deregistrationQuorumBitmap & registrationQuorumBitmap; cheats.assume(deregistrationQuorumBitmap != 0); - bytes memory registrationquorumNumbers = BitmapUtils.bitmapToBytesArray(registrationQuorumBitmap); + bytes memory registrationquorumNumbers = + BitmapUtils.bitmapToBytesArray(registrationQuorumBitmap); - for (uint i = 0; i < registrationquorumNumbers.length; i++) { + for (uint256 i = 0; i < registrationquorumNumbers.length; i++) { _setOperatorWeight(defaultOperator, uint8(registrationquorumNumbers[i]), defaultStake); } @@ -755,13 +872,18 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.roll(registrationBlockNumber); - registryCoordinator.registerOperator(registrationquorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + registrationquorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); - bytes memory deregistrationquorumNumbers = BitmapUtils.bitmapToBytesArray(deregistrationQuorumBitmap); + bytes memory deregistrationquorumNumbers = + BitmapUtils.bitmapToBytesArray(deregistrationQuorumBitmap); cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); - emit OperatorRemovedFromQuorums(defaultOperator, defaultOperatorId, deregistrationquorumNumbers); - for (uint i = 0; i < deregistrationquorumNumbers.length; i++) { + emit OperatorRemovedFromQuorums( + defaultOperator, defaultOperatorId, deregistrationquorumNumbers + ); + for (uint256 i = 0; i < deregistrationquorumNumbers.length; i++) { cheats.expectEmit(true, true, true, true, address(stakeRegistry)); emit OperatorStakeUpdate(defaultOperatorId, uint8(deregistrationquorumNumbers[i]), 0); } @@ -778,47 +900,74 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist if (deregistrationQuorumBitmap == registrationQuorumBitmap) { assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.DEREGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: IRegistryCoordinator.OperatorStatus.DEREGISTERED + }) + ) + ) ); } else { assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: IRegistryCoordinator.OperatorStatus.REGISTERED + }) + ) + ) ); } // ensure that the operator's current quorum bitmap matches the expectation - uint256 expectedQuorumBitmap = BitmapUtils.minus(registrationQuorumBitmap, deregistrationQuorumBitmap); - assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), expectedQuorumBitmap); + uint256 expectedQuorumBitmap = + BitmapUtils.minus(registrationQuorumBitmap, deregistrationQuorumBitmap); + assertEq( + registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), expectedQuorumBitmap + ); // check that the quorum bitmap history is as expected assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(registrationQuorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(registrationQuorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }) + ) + ) ); // note: there will be no second entry in the operator's bitmap history in the event that the operator has totally deregistered if (deregistrationQuorumBitmap != registrationQuorumBitmap) { assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(expectedQuorumBitmap), - updateBlockNumber: deregistrationBlockNumber, - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode( + registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1) + ) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(expectedQuorumBitmap), + updateBlockNumber: deregistrationBlockNumber, + nextUpdateBlockNumber: 0 + }) + ) + ) ); } } // @notice registers the max number of operators with fuzzed bitmaps and then deregisters a pseudorandom operator (from all of their quorums) - function testFuzz_deregisterOperator_manyOperators(uint256 pseudoRandomNumber) public { + function testFuzz_deregisterOperator_manyOperators( + uint256 pseudoRandomNumber + ) public { uint32 numOperators = defaultMaxOperatorCount; uint32 registrationBlockNumber = 100; @@ -826,17 +975,20 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // pad quorumBitmap with 1 until it has numOperators elements uint256[] memory quorumBitmaps = new uint256[](numOperators); - for (uint i = 0; i < numOperators; i++) { + for (uint256 i = 0; i < numOperators; i++) { // limit to maxQuorumsToRegisterFor quorums via mask so we don't run out of gas, make them all register for quorum 0 as well - quorumBitmaps[i] = uint256(keccak256(abi.encodePacked("quorumBitmap", pseudoRandomNumber, i))) & (1 << maxQuorumsToRegisterFor - 1) | 1; + quorumBitmaps[i] = uint256( + keccak256(abi.encodePacked("quorumBitmap", pseudoRandomNumber, i)) + ) & (1 << maxQuorumsToRegisterFor - 1) | 1; } cheats.roll(registrationBlockNumber); bytes32[] memory lastOperatorInQuorum = new bytes32[](numQuorums); - for (uint i = 0; i < numOperators; i++) { + for (uint256 i = 0; i < numOperators; i++) { emit log_named_uint("i", i); - BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); + BN254.G1Point memory pubKey = + BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); bytes32 operatorId = BN254.hashG1Point(pubKey); address operator = _incrementAddress(defaultOperator, i); @@ -844,29 +996,37 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // for each quorum the operator is in, save the operatorId bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmaps[i]); - for (uint j = 0; j < quorumNumbers.length; j++) { + for (uint256 j = 0; j < quorumNumbers.length; j++) { lastOperatorInQuorum[uint8(quorumNumbers[j])] = operatorId; } } uint256 indexOfOperatorToDeregister = pseudoRandomNumber % numOperators; - address operatorToDeregister = _incrementAddress(defaultOperator, indexOfOperatorToDeregister); - BN254.G1Point memory operatorToDeregisterPubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, indexOfOperatorToDeregister))); + address operatorToDeregister = + _incrementAddress(defaultOperator, indexOfOperatorToDeregister); + BN254.G1Point memory operatorToDeregisterPubKey = BN254.hashToG1( + keccak256(abi.encodePacked(pseudoRandomNumber, indexOfOperatorToDeregister)) + ); bytes32 operatorToDeregisterId = BN254.hashG1Point(operatorToDeregisterPubKey); uint256 operatorToDeregisterQuorumBitmap = quorumBitmaps[indexOfOperatorToDeregister]; - bytes memory operatorToDeregisterQuorumNumbers = BitmapUtils.bitmapToBytesArray(operatorToDeregisterQuorumBitmap); + bytes memory operatorToDeregisterQuorumNumbers = + BitmapUtils.bitmapToBytesArray(operatorToDeregisterQuorumBitmap); bytes32[] memory operatorIdsToSwap = new bytes32[](operatorToDeregisterQuorumNumbers.length); - for (uint i = 0; i < operatorToDeregisterQuorumNumbers.length; i++) { + for (uint256 i = 0; i < operatorToDeregisterQuorumNumbers.length; i++) { operatorIdsToSwap[i] = lastOperatorInQuorum[uint8(operatorToDeregisterQuorumNumbers[i])]; } cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); - emit OperatorRemovedFromQuorums(operatorToDeregister, operatorToDeregisterId, operatorToDeregisterQuorumNumbers); + emit OperatorRemovedFromQuorums( + operatorToDeregister, operatorToDeregisterId, operatorToDeregisterQuorumNumbers + ); - for (uint i = 0; i < operatorToDeregisterQuorumNumbers.length; i++) { + for (uint256 i = 0; i < operatorToDeregisterQuorumNumbers.length; i++) { cheats.expectEmit(true, true, true, true, address(stakeRegistry)); - emit OperatorStakeUpdate(operatorToDeregisterId, uint8(operatorToDeregisterQuorumNumbers[i]), 0); + emit OperatorStakeUpdate( + operatorToDeregisterId, uint8(operatorToDeregisterQuorumNumbers[i]), 0 + ); } cheats.roll(deregistrationBlockNumber); @@ -876,19 +1036,31 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist assertEq( keccak256(abi.encode(registryCoordinator.getOperator(operatorToDeregister))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: operatorToDeregisterId, - status: IRegistryCoordinator.OperatorStatus.DEREGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: operatorToDeregisterId, + status: IRegistryCoordinator.OperatorStatus.DEREGISTERED + }) + ) + ) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToDeregisterId, 0))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(operatorToDeregisterQuorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }))) + keccak256( + abi.encode( + registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToDeregisterId, 0) + ) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(operatorToDeregisterQuorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }) + ) + ) ); } @@ -911,34 +1083,52 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0); // re-register the operator - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); // check success of registration uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId, "1"); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }))), + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: IRegistryCoordinator.OperatorStatus.REGISTERED + }) + ) + ), "2" ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap, "3"); // check that previous entry in bitmap history was not changed assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), keccak256(abi.encode(previousQuorumBitmapUpdate)), "4" ); // check that new entry in bitmap history is as expected - uint historyLength = registryCoordinator.getQuorumBitmapHistoryLength(defaultOperatorId); + uint256 historyLength = registryCoordinator.getQuorumBitmapHistoryLength(defaultOperatorId); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, historyLength - 1))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(reregistrationBlockNumber), - nextUpdateBlockNumber: 0 - }))), + keccak256( + abi.encode( + registryCoordinator.getQuorumBitmapUpdateByIndex( + defaultOperatorId, historyLength - 1 + ) + ) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(reregistrationBlockNumber), + nextUpdateBlockNumber: 0 + }) + ) + ), "5" ); } @@ -956,7 +1146,9 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.roll(registrationBlockNumber); cheats.startPrank(defaultOperator); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); bytes memory emptyQuorumNumbers = new bytes(0); @@ -983,7 +1175,9 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.roll(registrationBlockNumber); cheats.startPrank(defaultOperator); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); bytes memory incorrectQuorum = new bytes(1); incorrectQuorum[0] = bytes1(defaultQuorumNumber + 1); @@ -1010,7 +1204,9 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.prank(defaultOperator); cheats.roll(registrationBlockNumber); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); cheats.prank(ejector); registryCoordinator.ejectOperator(defaultOperator, quorumNumbers); @@ -1018,7 +1214,9 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.prank(defaultOperator); cheats.roll(reregistrationBlockNumber); cheats.expectRevert(bytes4(keccak256("CannotReregisterYet()"))); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); } function test_reregisterOperator_reregistrationDelay() public { @@ -1038,7 +1236,9 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.prank(defaultOperator); cheats.roll(registrationBlockNumber); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); cheats.prank(ejector); registryCoordinator.ejectOperator(defaultOperator, quorumNumbers); @@ -1046,7 +1246,9 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist cheats.prank(defaultOperator); cheats.roll(reregistrationBlockNumber); cheats.warp(block.timestamp + reregistrationDelay + 1); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); } // note: this is not possible to test, because there is no route to getting the operator registered for nonexistent quorums @@ -1066,68 +1268,101 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // filter the other fuzzed input to a subset of the first fuzzed input deregistrationQuorumBitmap = deregistrationQuorumBitmap & registrationQuorumBitmap; cheats.assume(deregistrationQuorumBitmap != 0); - bytes memory registrationquorumNumbers = BitmapUtils.bitmapToBytesArray(registrationQuorumBitmap); + bytes memory registrationquorumNumbers = + BitmapUtils.bitmapToBytesArray(registrationQuorumBitmap); - for (uint i = 0; i < registrationquorumNumbers.length; i++) { + for (uint256 i = 0; i < registrationquorumNumbers.length; i++) { _setOperatorWeight(defaultOperator, uint8(registrationquorumNumbers[i]), defaultStake); } cheats.roll(registrationBlockNumber); cheats.startPrank(defaultOperator); - registryCoordinator.registerOperator(registrationquorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + registrationquorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); - bytes memory deregistrationquorumNumbers = BitmapUtils.bitmapToBytesArray(deregistrationQuorumBitmap); + bytes memory deregistrationquorumNumbers = + BitmapUtils.bitmapToBytesArray(deregistrationQuorumBitmap); cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); - emit OperatorRemovedFromQuorums(defaultOperator, defaultOperatorId, deregistrationquorumNumbers); - for (uint i = 0; i < deregistrationquorumNumbers.length; i++) { + emit OperatorRemovedFromQuorums( + defaultOperator, defaultOperatorId, deregistrationquorumNumbers + ); + for (uint256 i = 0; i < deregistrationquorumNumbers.length; i++) { cheats.expectEmit(true, true, true, true, address(stakeRegistry)); emit OperatorStakeUpdate(defaultOperatorId, uint8(deregistrationquorumNumbers[i]), 0); } cheats.roll(deregistrationBlockNumber); - registryCoordinator._deregisterOperatorExternal(defaultOperator, deregistrationquorumNumbers); + registryCoordinator._deregisterOperatorExternal( + defaultOperator, deregistrationquorumNumbers + ); // check that the operator is marked as 'degregistered' only if deregistered from *all* quorums if (deregistrationQuorumBitmap == registrationQuorumBitmap) { assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.DEREGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: IRegistryCoordinator.OperatorStatus.DEREGISTERED + }) + ) + ) ); } else { assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: IRegistryCoordinator.OperatorStatus.REGISTERED + }) + ) + ) ); } // ensure that the operator's current quorum bitmap matches the expectation - uint256 expectedQuorumBitmap = BitmapUtils.minus(registrationQuorumBitmap, deregistrationQuorumBitmap); - assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), expectedQuorumBitmap); + uint256 expectedQuorumBitmap = + BitmapUtils.minus(registrationQuorumBitmap, deregistrationQuorumBitmap); + assertEq( + registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), expectedQuorumBitmap + ); // check that the quorum bitmap history is as expected assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(registrationQuorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(registrationQuorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }) + ) + ) ); // note: there will be no second entry in the operator's bitmap history in the event that the operator has totally deregistered if (deregistrationQuorumBitmap != registrationQuorumBitmap) { assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(expectedQuorumBitmap), - updateBlockNumber: deregistrationBlockNumber, - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode( + registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1) + ) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(expectedQuorumBitmap), + updateBlockNumber: deregistrationBlockNumber, + nextUpdateBlockNumber: 0 + }) + ) + ) ); } } @@ -1141,7 +1376,9 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); cheats.prank(defaultOperator); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); emit OperatorRemovedFromQuorums(defaultOperator, defaultOperatorId, quorumNumbers); @@ -1156,10 +1393,14 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // make sure the operator is deregistered assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.DEREGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: IRegistryCoordinator.OperatorStatus.DEREGISTERED + }) + ) + ) ); // make sure the operator is not in any quorums assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); @@ -1172,12 +1413,14 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist quorumNumbers[1] = bytes1(defaultQuorumNumber + 1); ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; - for (uint i = 0; i < quorumNumbers.length; i++) { + for (uint256 i = 0; i < quorumNumbers.length; i++) { _setOperatorWeight(defaultOperator, uint8(quorumNumbers[i]), defaultStake); } cheats.prank(defaultOperator); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); // eject from only first quorum bytes memory quorumNumbersToEject = new bytes(1); @@ -1195,16 +1438,21 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // make sure the operator is registered assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: IRegistryCoordinator.OperatorStatus.REGISTERED + }) + ) + ) ); // make sure the operator is properly removed from the quorums assertEq( registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), // quorumsRegisteredFor & ~quorumsEjectedFrom - BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers) & ~BitmapUtils.orderedBytesArrayToBitmap(quorumNumbersToEject) + BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers) + & ~BitmapUtils.orderedBytesArrayToBitmap(quorumNumbersToEject) ); } @@ -1216,7 +1464,9 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); cheats.prank(defaultOperator); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); cheats.expectRevert(bytes4(keccak256("OnlyEjector()"))); cheats.prank(defaultOperator); @@ -1226,7 +1476,9 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist function test_getQuorumBitmapIndicesAtBlockNumber_revert_notRegistered() public { uint32 blockNumber; bytes32[] memory operatorIds = new bytes32[](1); - cheats.expectRevert("RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId"); + cheats.expectRevert( + "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId" + ); registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); } @@ -1240,23 +1492,37 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); cheats.roll(registrationBlockNumber); cheats.startPrank(defaultOperator); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); uint32 blockNumber = 0; bytes32[] memory operatorIds = new bytes32[](1); operatorIds[0] = defaultOperatorId; uint32[] memory returnArray; - cheats.expectRevert("RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId"); + cheats.expectRevert( + "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId" + ); registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); blockNumber = registrationBlockNumber; - returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); - assertEq(returnArray[0], 0, "defaultOperator bitmap index at blockNumber registrationBlockNumber was not 0"); + returnArray = + registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); + assertEq( + returnArray[0], + 0, + "defaultOperator bitmap index at blockNumber registrationBlockNumber was not 0" + ); blockNumber = registrationBlockNumber + 1; - returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); - assertEq(returnArray[0], 0, "defaultOperator bitmap index at blockNumber registrationBlockNumber + 1 was not 0"); + returnArray = + registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); + assertEq( + returnArray[0], + 0, + "defaultOperator bitmap index at blockNumber registrationBlockNumber + 1 was not 0" + ); } // @notice tests for correct reversion and return values in the event that an operator registers and later deregisters @@ -1269,24 +1535,46 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist operatorIds[0] = defaultOperatorId; uint32[] memory returnArray; - cheats.expectRevert("RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId"); + cheats.expectRevert( + "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId" + ); registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); blockNumber = registrationBlockNumber; - returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); - assertEq(returnArray[0], 0, "defaultOperator bitmap index at blockNumber registrationBlockNumber was not 0"); + returnArray = + registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); + assertEq( + returnArray[0], + 0, + "defaultOperator bitmap index at blockNumber registrationBlockNumber was not 0" + ); blockNumber = registrationBlockNumber + 1; - returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); - assertEq(returnArray[0], 0, "defaultOperator bitmap index at blockNumber registrationBlockNumber + 1 was not 0"); + returnArray = + registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); + assertEq( + returnArray[0], + 0, + "defaultOperator bitmap index at blockNumber registrationBlockNumber + 1 was not 0" + ); blockNumber = deregistrationBlockNumber; - returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); - assertEq(returnArray[0], 1, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber was not 1"); + returnArray = + registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); + assertEq( + returnArray[0], + 1, + "defaultOperator bitmap index at blockNumber deregistrationBlockNumber was not 1" + ); blockNumber = deregistrationBlockNumber + 1; - returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); - assertEq(returnArray[0], 1, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber + 1 was not 1"); + returnArray = + registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); + assertEq( + returnArray[0], + 1, + "defaultOperator bitmap index at blockNumber deregistrationBlockNumber + 1 was not 1" + ); } // @notice tests for correct reversion and return values in the event that an operator registers and later deregisters @@ -1303,39 +1591,64 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist // try an incorrect blockNumber input and confirm reversion cheats.expectRevert(QuorumBitmapHistoryLib.BitmapUpdateIsAfterBlockNumber.selector); - uint192 returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); + uint192 returnVal = + registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); blockNumber = registrationBlockNumber; - returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); - assertEq(returnVal, defaultQuorumBitmap, "defaultOperator bitmap index at blockNumber registrationBlockNumber was not defaultQuorumBitmap"); + returnVal = + registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); + assertEq( + returnVal, + defaultQuorumBitmap, + "defaultOperator bitmap index at blockNumber registrationBlockNumber was not defaultQuorumBitmap" + ); blockNumber = registrationBlockNumber + 1; - returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); - assertEq(returnVal, defaultQuorumBitmap, "defaultOperator bitmap index at blockNumber registrationBlockNumber + 1 was not defaultQuorumBitmap"); + returnVal = + registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); + assertEq( + returnVal, + defaultQuorumBitmap, + "defaultOperator bitmap index at blockNumber registrationBlockNumber + 1 was not defaultQuorumBitmap" + ); // try an incorrect index input and confirm reversion index = 1; cheats.expectRevert(QuorumBitmapHistoryLib.BitmapUpdateIsAfterBlockNumber.selector); - returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); + returnVal = + registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); blockNumber = deregistrationBlockNumber; - returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); - assertEq(returnVal, emptyBitmap, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber was not emptyBitmap"); + returnVal = + registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); + assertEq( + returnVal, + emptyBitmap, + "defaultOperator bitmap index at blockNumber deregistrationBlockNumber was not emptyBitmap" + ); blockNumber = deregistrationBlockNumber + 1; - returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); - assertEq(returnVal, emptyBitmap, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber + 1 was not emptyBitmap"); + returnVal = + registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); + assertEq( + returnVal, + emptyBitmap, + "defaultOperator bitmap index at blockNumber deregistrationBlockNumber + 1 was not emptyBitmap" + ); // try an incorrect index input and confirm reversion index = 0; cheats.expectRevert(QuorumBitmapHistoryLib.NextBitmapUpdateIsBeforeBlockNumber.selector); - returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); + returnVal = + registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); } } contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoordinatorUnitTests { // @notice registers an operator for a single quorum, with a fuzzed pubkey, churning out another operator from the quorum - function testFuzz_registerOperatorWithChurn(uint256 pseudoRandomNumber) public { + function testFuzz_registerOperatorWithChurn( + uint256 pseudoRandomNumber + ) public { uint32 numOperators = defaultMaxOperatorCount; uint32 kickRegistrationBlockNumber = 100; uint32 registrationBlockNumber = 200; @@ -1347,23 +1660,27 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord cheats.roll(kickRegistrationBlockNumber); - for (uint i = 0; i < numOperators - 1; i++) { - BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); + for (uint256 i = 0; i < numOperators - 1; i++) { + BN254.G1Point memory pubKey = + BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); address operator = _incrementAddress(defaultOperator, i); _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); } address operatorToRegister = _incrementAddress(defaultOperator, numOperators); - BN254.G1Point memory operatorToRegisterPubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, numOperators))); + BN254.G1Point memory operatorToRegisterPubKey = + BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, numOperators))); bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); bytes32 operatorToKickId; address operatorToKick; // register last operator before kick - IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = new IRegistryCoordinator.OperatorKickParam[](1); + IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = + new IRegistryCoordinator.OperatorKickParam[](1); { - BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, numOperators - 1))); + BN254.G1Point memory pubKey = + BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, numOperators - 1))); operatorToKickId = BN254.hashG1Point(pubKey); operatorToKick = _incrementAddress(defaultOperator, numOperators - 1); @@ -1397,11 +1714,12 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord cheats.expectEmit(true, true, true, true, address(indexRegistry)); emit QuorumIndexUpdate(operatorToRegisterId, defaultQuorumNumber, numOperators); - cheats.expectEmit(true, true, true, true, address(registryCoordinator)); emit OperatorDeregistered(operatorKickParams[0].operator, operatorToKickId); cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); - emit OperatorRemovedFromQuorums(operatorKickParams[0].operator, operatorToKickId, quorumNumbers); + emit OperatorRemovedFromQuorums( + operatorKickParams[0].operator, operatorToKickId, quorumNumbers + ); cheats.expectEmit(true, true, true, true, address(stakeRegistry)); emit OperatorStakeUpdate(operatorToKickId, defaultQuorumNumber, 0); cheats.expectEmit(true, true, true, true, address(indexRegistry)); @@ -1410,7 +1728,13 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord { ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; ISignatureUtils.SignatureWithSaltAndExpiry memory signatureWithExpiry = - _signOperatorChurnApproval(operatorToRegister, operatorToRegisterId, operatorKickParams, defaultSalt, block.timestamp + 10); + _signOperatorChurnApproval( + operatorToRegister, + operatorToRegisterId, + operatorKickParams, + defaultSalt, + block.timestamp + 10 + ); cheats.prank(operatorToRegister); uint256 gasBefore = gasleft(); registryCoordinator.registerOperatorWithChurn( @@ -1427,29 +1751,45 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord assertEq( keccak256(abi.encode(registryCoordinator.getOperator(operatorToRegister))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: operatorToRegisterId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: operatorToRegisterId, + status: IRegistryCoordinator.OperatorStatus.REGISTERED + }) + ) + ) ); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(operatorToKick))), - keccak256(abi.encode(IRegistryCoordinator.OperatorInfo({ - operatorId: operatorToKickId, - status: IRegistryCoordinator.OperatorStatus.DEREGISTERED - }))) + keccak256( + abi.encode( + IRegistryCoordinator.OperatorInfo({ + operatorId: operatorToKickId, + status: IRegistryCoordinator.OperatorStatus.DEREGISTERED + }) + ) + ) ); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToKickId, 0))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: kickRegistrationBlockNumber, - nextUpdateBlockNumber: registrationBlockNumber - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToKickId, 0)) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: kickRegistrationBlockNumber, + nextUpdateBlockNumber: registrationBlockNumber + }) + ) + ) ); } - function test_registerOperatorWithChurn_revert_lessThanKickBIPsOfOperatorStake(uint256 pseudoRandomNumber) public { + function test_registerOperatorWithChurn_revert_lessThanKickBIPsOfOperatorStake( + uint256 pseudoRandomNumber + ) public { bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; @@ -1465,7 +1805,13 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord cheats.roll(registrationBlockNumber); ISignatureUtils.SignatureWithSaltAndExpiry memory signatureWithExpiry = - _signOperatorChurnApproval(operatorToRegister, operatorToRegisterId, operatorKickParams, defaultSalt, block.timestamp + 10); + _signOperatorChurnApproval( + operatorToRegister, + operatorToRegisterId, + operatorKickParams, + defaultSalt, + block.timestamp + 10 + ); cheats.prank(operatorToRegister); cheats.expectRevert(bytes4(keccak256("InsufficientStakeForChurn()"))); registryCoordinator.registerOperatorWithChurn( @@ -1478,7 +1824,9 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ); } - function test_registerOperatorWithChurn_revert_lessThanKickBIPsOfTotalStake(uint256 pseudoRandomNumber) public { + function test_registerOperatorWithChurn_revert_lessThanKickBIPsOfTotalStake( + uint256 pseudoRandomNumber + ) public { bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; @@ -1488,16 +1836,27 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord address operatorToRegister, BN254.G1Point memory operatorToRegisterPubKey, IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams - ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, operatorToKickStake); + ) = _test_registerOperatorWithChurn_SetUp( + pseudoRandomNumber, quorumNumbers, operatorToKickStake + ); bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); - // set the stake of the operator to register to the defaultKickBIPsOfOperatorStake multiple of the operatorToKickStake - _setOperatorWeight(operatorToRegister, defaultQuorumNumber, operatorToKickStake * defaultKickBIPsOfOperatorStake / 10000 + 1); + _setOperatorWeight( + operatorToRegister, + defaultQuorumNumber, + operatorToKickStake * defaultKickBIPsOfOperatorStake / 10_000 + 1 + ); cheats.roll(registrationBlockNumber); ISignatureUtils.SignatureWithSaltAndExpiry memory signatureWithExpiry = - _signOperatorChurnApproval(operatorToRegister, operatorToRegisterId, operatorKickParams, defaultSalt, block.timestamp + 10); + _signOperatorChurnApproval( + operatorToRegister, + operatorToRegisterId, + operatorKickParams, + defaultSalt, + block.timestamp + 10 + ); cheats.prank(operatorToRegister); cheats.expectRevert(bytes4(keccak256("CannotKickOperatorAboveThreshold()"))); registryCoordinator.registerOperatorWithChurn( @@ -1510,7 +1869,9 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ); } - function test_registerOperatorWithChurn_revert_invalidChurnApproverSignature(uint256 pseudoRandomNumber) public { + function test_registerOperatorWithChurn_revert_invalidChurnApproverSignature( + uint256 pseudoRandomNumber + ) public { bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; @@ -1542,7 +1903,9 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ); } - function test_registerOperatorWithChurn_revert_expiredChurnApproverSignature(uint256 pseudoRandomNumber) public { + function test_registerOperatorWithChurn_revert_expiredChurnApproverSignature( + uint256 pseudoRandomNumber + ) public { bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; @@ -1559,7 +1922,13 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord cheats.roll(registrationBlockNumber); ISignatureUtils.SignatureWithSaltAndExpiry memory signatureWithSaltAndExpiry = - _signOperatorChurnApproval(operatorToRegister, operatorToRegisterId, operatorKickParams, defaultSalt, block.timestamp - 1); + _signOperatorChurnApproval( + operatorToRegister, + operatorToRegisterId, + operatorKickParams, + defaultSalt, + block.timestamp - 1 + ); cheats.prank(operatorToRegister); cheats.expectRevert(bytes4(keccak256("SignatureExpired()"))); registryCoordinator.registerOperatorWithChurn( @@ -1595,7 +1964,9 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); cheats.startPrank(defaultOperator); cheats.roll(registrationBlockNumber); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); address[] memory operatorsToUpdate = new address[](1); operatorsToUpdate[0] = defaultOperator; @@ -1605,7 +1976,10 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit // @notice tests the `updateOperators` function with a single registered operator as input // @dev also sets up return data from the StakeRegistry - function testFuzz_updateOperators_singleOperator(uint192 registrationBitmap, uint192 mockReturnData) public { + function testFuzz_updateOperators_singleOperator( + uint192 registrationBitmap, + uint192 mockReturnData + ) public { // filter fuzzed inputs to only valid inputs cheats.assume(registrationBitmap != 0); mockReturnData = (mockReturnData & registrationBitmap); @@ -1620,7 +1994,9 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit } cheats.startPrank(defaultOperator); cheats.roll(registrationBlockNumber); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); address[] memory operatorsToUpdate = new address[](1); operatorsToUpdate[0] = defaultOperator; @@ -1647,7 +2023,9 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit operatorsToUpdate[0] = defaultOperator; // force a staticcall to the `updateOperators` function -- this should *pass* because the call should be a strict no-op! - (bool success, ) = address(registryCoordinator).staticcall(abi.encodeWithSignature("updateOperators(address[])", operatorsToUpdate)); + (bool success,) = address(registryCoordinator).staticcall( + abi.encodeWithSignature("updateOperators(address[])", operatorsToUpdate) + ); require(success, "staticcall failed!"); } @@ -1657,7 +2035,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit address[][] memory operatorsToUpdate = new address[][](1); address[] memory operatorArray = new address[](1); - operatorArray[0] = defaultOperator; + operatorArray[0] = defaultOperator; operatorsToUpdate[0] = operatorArray; bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); @@ -1689,7 +2067,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit function test_updateOperatorsForQuorum_revert_incorrectNumberOfOperators() public { address[][] memory operatorsToUpdate = new address[][](1); address[] memory operatorArray = new address[](1); - operatorArray[0] = defaultOperator; + operatorArray[0] = defaultOperator; operatorsToUpdate[0] = operatorArray; bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); @@ -1707,12 +2085,14 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); cheats.startPrank(defaultOperator); cheats.roll(registrationBlockNumber); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); address[][] memory operatorsToUpdate = new address[][](1); address[] memory operatorArray = new address[](1); // use an unregistered operator address as input - operatorArray[0] = _incrementAddress(defaultOperator, 1); + operatorArray[0] = _incrementAddress(defaultOperator, 1); operatorsToUpdate[0] = operatorArray; cheats.expectRevert(bytes4(keccak256("NotRegisteredForQuorum()"))); @@ -1720,7 +2100,9 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit } // note: there is not an explicit check for duplicates, as checking for explicit ordering covers this - function test_updateOperatorsForQuorum_revert_duplicateOperator(uint256 pseudoRandomNumber) public { + function test_updateOperatorsForQuorum_revert_duplicateOperator( + uint256 pseudoRandomNumber + ) public { // register 2 operators uint32 numOperators = 2; uint32 registrationBlockNumber = 200; @@ -1728,8 +2110,9 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit quorumNumbers[0] = bytes1(defaultQuorumNumber); uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); cheats.roll(registrationBlockNumber); - for (uint i = 0; i < numOperators; i++) { - BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); + for (uint256 i = 0; i < numOperators; i++) { + BN254.G1Point memory pubKey = + BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); address operator = _incrementAddress(defaultOperator, i); _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); @@ -1738,8 +2121,8 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit address[][] memory operatorsToUpdate = new address[][](1); address[] memory operatorArray = new address[](2); // use the same operator address twice as input - operatorArray[0] = defaultOperator; - operatorArray[1] = defaultOperator; + operatorArray[0] = defaultOperator; + operatorArray[1] = defaultOperator; operatorsToUpdate[0] = operatorArray; // note: there is not an explicit check for duplicates, as checking for explicit ordering covers this @@ -1747,7 +2130,9 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); } - function test_updateOperatorsForQuorum_revert_incorrectListOrder(uint256 pseudoRandomNumber) public { + function test_updateOperatorsForQuorum_revert_incorrectListOrder( + uint256 pseudoRandomNumber + ) public { // register 2 operators uint32 numOperators = 2; uint32 registrationBlockNumber = 200; @@ -1755,8 +2140,9 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit quorumNumbers[0] = bytes1(defaultQuorumNumber); uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); cheats.roll(registrationBlockNumber); - for (uint i = 0; i < numOperators; i++) { - BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); + for (uint256 i = 0; i < numOperators; i++) { + BN254.G1Point memory pubKey = + BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); address operator = _incrementAddress(defaultOperator, i); _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); @@ -1765,8 +2151,8 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit address[][] memory operatorsToUpdate = new address[][](1); address[] memory operatorArray = new address[](2); // order the operator addresses in descending order, instead of ascending order - operatorArray[0] = _incrementAddress(defaultOperator, 1); - operatorArray[1] = defaultOperator; + operatorArray[0] = _incrementAddress(defaultOperator, 1); + operatorArray[1] = defaultOperator; operatorsToUpdate[0] = operatorArray; cheats.expectRevert(bytes4(keccak256("NotSorted()"))); @@ -1782,25 +2168,33 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); cheats.startPrank(defaultOperator); cheats.roll(registrationBlockNumber); - registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + registryCoordinator.registerOperator( + quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig + ); address[][] memory operatorsToUpdate = new address[][](1); address[] memory operatorArray = new address[](1); - operatorArray[0] = defaultOperator; + operatorArray[0] = defaultOperator; operatorsToUpdate[0] = operatorArray; - uint256 quorumUpdateBlockNumberBefore = registryCoordinator.quorumUpdateBlockNumber(defaultQuorumNumber); + uint256 quorumUpdateBlockNumberBefore = + registryCoordinator.quorumUpdateBlockNumber(defaultQuorumNumber); require(quorumUpdateBlockNumberBefore != block.number, "bad test setup!"); cheats.expectEmit(true, true, true, true, address(registryCoordinator)); emit QuorumBlockNumberUpdated(defaultQuorumNumber, block.number); registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); - uint256 quorumUpdateBlockNumberAfter = registryCoordinator.quorumUpdateBlockNumber(defaultQuorumNumber); - assertEq(quorumUpdateBlockNumberAfter, block.number, "quorumUpdateBlockNumber not set correctly"); + uint256 quorumUpdateBlockNumberAfter = + registryCoordinator.quorumUpdateBlockNumber(defaultQuorumNumber); + assertEq( + quorumUpdateBlockNumberAfter, block.number, "quorumUpdateBlockNumber not set correctly" + ); } - function test_updateOperatorsForQuorum_twoOperators(uint256 pseudoRandomNumber) public { + function test_updateOperatorsForQuorum_twoOperators( + uint256 pseudoRandomNumber + ) public { // register 2 operators uint32 numOperators = 2; uint32 registrationBlockNumber = 200; @@ -1808,8 +2202,9 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit quorumNumbers[0] = bytes1(defaultQuorumNumber); uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); cheats.roll(registrationBlockNumber); - for (uint i = 0; i < numOperators; i++) { - BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); + for (uint256 i = 0; i < numOperators; i++) { + BN254.G1Point memory pubKey = + BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); address operator = _incrementAddress(defaultOperator, i); _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); @@ -1818,52 +2213,74 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit address[][] memory operatorsToUpdate = new address[][](1); address[] memory operatorArray = new address[](2); // order the operator addresses in descending order, instead of ascending order - operatorArray[0] = defaultOperator; - operatorArray[1] = _incrementAddress(defaultOperator, 1); + operatorArray[0] = defaultOperator; + operatorArray[1] = _incrementAddress(defaultOperator, 1); operatorsToUpdate[0] = operatorArray; - uint256 quorumUpdateBlockNumberBefore = registryCoordinator.quorumUpdateBlockNumber(defaultQuorumNumber); + uint256 quorumUpdateBlockNumberBefore = + registryCoordinator.quorumUpdateBlockNumber(defaultQuorumNumber); require(quorumUpdateBlockNumberBefore != block.number, "bad test setup!"); cheats.expectEmit(true, true, true, true, address(registryCoordinator)); emit QuorumBlockNumberUpdated(defaultQuorumNumber, block.number); registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); - uint256 quorumUpdateBlockNumberAfter = registryCoordinator.quorumUpdateBlockNumber(defaultQuorumNumber); - assertEq(quorumUpdateBlockNumberAfter, block.number, "quorumUpdateBlockNumber not set correctly"); + uint256 quorumUpdateBlockNumberAfter = + registryCoordinator.quorumUpdateBlockNumber(defaultQuorumNumber); + assertEq( + quorumUpdateBlockNumberAfter, block.number, "quorumUpdateBlockNumber not set correctly" + ); } // @notice tests that the internal `_updateOperatorBitmap` function works as expected, for fuzzed inputs - function testFuzz_updateOperatorBitmapInternal_noPreviousEntries(uint192 newBitmap) public { + function testFuzz_updateOperatorBitmapInternal_noPreviousEntries( + uint192 newBitmap + ) public { registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(newBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(newBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }) + ) + ) ); } // @notice tests that the internal `_updateOperatorBitmap` function works as expected, for fuzzed inputs - function testFuzz_updateOperatorBitmapInternal_previousEntryInCurrentBlock(uint192 newBitmap) public { + function testFuzz_updateOperatorBitmapInternal_previousEntryInCurrentBlock( + uint192 newBitmap + ) public { uint192 pastBitmap = 1; testFuzz_updateOperatorBitmapInternal_noPreviousEntries(pastBitmap); registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(newBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(newBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }) + ) + ) ); } // @notice tests that the internal `_updateOperatorBitmap` function works as expected, for fuzzed inputs - function testFuzz_updateOperatorBitmapInternal_previousEntryInPastBlock(uint192 newBitmap) public { + function testFuzz_updateOperatorBitmapInternal_previousEntryInPastBlock( + uint192 newBitmap + ) public { uint192 pastBitmap = 1; testFuzz_updateOperatorBitmapInternal_noPreviousEntries(pastBitmap); @@ -1873,20 +2290,32 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(pastBitmap), - updateBlockNumber: uint32(previousBlockNumber), - nextUpdateBlockNumber: uint32(block.number) - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(pastBitmap), + updateBlockNumber: uint32(previousBlockNumber), + nextUpdateBlockNumber: uint32(block.number) + }) + ) + ) ); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), - keccak256(abi.encode(IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(newBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1)) + ), + keccak256( + abi.encode( + IRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(newBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }) + ) + ) ); } } @@ -1895,7 +2324,9 @@ contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnit function test_registerALMHook_Reverts() public { cheats.prank(address(registryCoordinator.allocationManager())); cheats.expectRevert(); - registryCoordinator.registerOperator(defaultOperator, new uint32[](0), abi.encode(defaultSocket, pubkeyRegistrationParams)); + registryCoordinator.registerOperator( + defaultOperator, new uint32[](0), abi.encode(defaultSocket, pubkeyRegistrationParams) + ); } function test_deregisterALMHook_Reverts() public { @@ -1909,17 +2340,17 @@ contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnit function test_CreateTotalDelegatedStakeQuorum() public { _deployMockEigenLayerAndAVS(0); // Set up test params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator + .OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 0, kickBIPsOfTotalStake: 0 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = IStakeRegistry.StrategyParams({ - strategy: IStrategy(address(0x1)), - multiplier: 1000 - }); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = + IStakeRegistry.StrategyParams({strategy: IStrategy(address(0x1)), multiplier: 1000}); // Get initial quorum count uint8 initialQuorumCount = registryCoordinator.quorumCount(); @@ -1927,16 +2358,15 @@ contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnit // Create quorum with total delegated stake type cheats.prank(registryCoordinatorOwner); registryCoordinator.createTotalDelegatedStakeQuorum( - operatorSetParams, - minimumStake, - strategyParams + operatorSetParams, minimumStake, strategyParams ); // Verify quorum was created assertEq(registryCoordinator.quorumCount(), initialQuorumCount + 1); // Verify quorum params were set correctly - IRegistryCoordinator.OperatorSetParam memory storedParams = registryCoordinator.getOperatorSetParams(initialQuorumCount); + IRegistryCoordinator.OperatorSetParam memory storedParams = + registryCoordinator.getOperatorSetParams(initialQuorumCount); assertEq(storedParams.maxOperatorCount, operatorSetParams.maxOperatorCount); assertEq(storedParams.kickBIPsOfOperatorStake, operatorSetParams.kickBIPsOfOperatorStake); assertEq(storedParams.kickBIPsOfTotalStake, operatorSetParams.kickBIPsOfTotalStake); @@ -1944,27 +2374,24 @@ contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnit function test_CreateSlashableStakeQuorum_Reverts() public { _deployMockEigenLayerAndAVS(0); - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator + .OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 0, kickBIPsOfTotalStake: 0 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = IStakeRegistry.StrategyParams({ - strategy: IStrategy(address(0x1)), - multiplier: 1000 - }); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = + IStakeRegistry.StrategyParams({strategy: IStrategy(address(0x1)), multiplier: 1000}); uint32 lookAheadPeriod = 100; // Attempt to create quorum with slashable stake type before enabling operator sets cheats.prank(registryCoordinatorOwner); cheats.expectRevert(); registryCoordinator.createSlashableStakeQuorum( - operatorSetParams, - minimumStake, - strategyParams, - lookAheadPeriod + operatorSetParams, minimumStake, strategyParams, lookAheadPeriod ); } @@ -1990,25 +2417,14 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT address operatorToRegister = address(420); - ISignatureUtils.SignatureWithSaltAndExpiry memory emptySignature = ISignatureUtils.SignatureWithSaltAndExpiry({ - signature: new bytes(0), - salt: bytes32(0), - expiry: 0 - }); + ISignatureUtils.SignatureWithSaltAndExpiry memory emptySignature = ISignatureUtils + .SignatureWithSaltAndExpiry({signature: new bytes(0), salt: bytes32(0), expiry: 0}); - IBLSApkRegistry.PubkeyRegistrationParams memory operatorRegisterApkParams = IBLSApkRegistry.PubkeyRegistrationParams({ - pubkeyRegistrationSignature: BN254.G1Point({ - X: 0, - Y: 0 - }), - pubkeyG1: BN254.G1Point({ - X: 0, - Y: 0 - }), - pubkeyG2: BN254.G2Point({ - X: [uint256(0), uint256(0)], - Y: [uint256(0), uint256(0)] - }) + IBLSApkRegistry.PubkeyRegistrationParams memory operatorRegisterApkParams = IBLSApkRegistry + .PubkeyRegistrationParams({ + pubkeyRegistrationSignature: BN254.G1Point({X: 0, Y: 0}), + pubkeyG1: BN254.G1Point({X: 0, Y: 0}), + pubkeyG2: BN254.G2Point({X: [uint256(0), uint256(0)], Y: [uint256(0), uint256(0)]}) }); string memory socket = "socket"; @@ -2035,8 +2451,13 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT assertEq(bitmap, 0, "Operator bitmap should be empty after deregistration"); // Verify operator status is NEVER_REGISTERED - IRegistryCoordinator.OperatorStatus status = registryCoordinator.getOperatorStatus(operatorToRegister); - assertEq(uint8(status), uint8(IRegistryCoordinator.OperatorStatus.NEVER_REGISTERED), "Operator status should be NEVER_REGISTERED"); + IRegistryCoordinator.OperatorStatus status = + registryCoordinator.getOperatorStatus(operatorToRegister); + assertEq( + uint8(status), + uint8(IRegistryCoordinator.OperatorStatus.NEVER_REGISTERED), + "Operator status should be NEVER_REGISTERED" + ); } function test_M2_Register_Reverts() public { @@ -2050,10 +2471,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT cheats.expectRevert(); registryCoordinator.registerOperator( - quorumNumbers, - defaultSocket, - params, - operatorSignature + quorumNumbers, defaultSocket, params, operatorSignature ); } @@ -2066,26 +2484,23 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT registryCoordinator.enableOperatorSets(); // Create quorum params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator + .OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = IStakeRegistry.StrategyParams({ - strategy: IStrategy(address(1)), - multiplier: 1 - }); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = + IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 1}); uint32 lookAheadPeriod = 100; // Create slashable stake quorum cheats.prank(registryCoordinatorOwner); registryCoordinator.createSlashableStakeQuorum( - operatorSetParams, - minimumStake, - strategyParams, - lookAheadPeriod + operatorSetParams, minimumStake, strategyParams, lookAheadPeriod ); } @@ -2098,24 +2513,22 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT registryCoordinator.enableOperatorSets(); // Create quorum params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator + .OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = IStakeRegistry.StrategyParams({ - strategy: IStrategy(address(1)), - multiplier: 10000 - }); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = + IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10_000}); // Create total delegated stake quorum cheats.prank(registryCoordinatorOwner); registryCoordinator.createTotalDelegatedStakeQuorum( - operatorSetParams, - minimumStake, - strategyParams + operatorSetParams, minimumStake, strategyParams ); } @@ -2128,27 +2541,22 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT registryCoordinator.enableOperatorSets(); // Create quorum params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator + .OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = IStakeRegistry.StrategyParams({ - strategy: IStrategy(address(1)), - multiplier: 10000 - }); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = + IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10_000}); // Create total delegated stake quorum cheats.prank(registryCoordinatorOwner); - registryCoordinator.createTotalDelegatedStakeQuorum( - operatorSetParams, - 0, - strategyParams - ); - + registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, 0, strategyParams); uint32[] memory operatorSetIds = new uint32[](1); operatorSetIds[0] = 0; @@ -2175,26 +2583,22 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT registryCoordinator.enableOperatorSets(); // Create quorum params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator + .OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = IStakeRegistry.StrategyParams({ - strategy: IStrategy(address(1)), - multiplier: 10000 - }); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = + IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10_000}); // Create total delegated stake quorum cheats.prank(registryCoordinatorOwner); - registryCoordinator.createTotalDelegatedStakeQuorum( - operatorSetParams, - 0, - strategyParams - ); + registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, 0, strategyParams); uint32[] memory operatorSetIds = new uint32[](1); operatorSetIds[0] = 0; @@ -2208,21 +2612,16 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT // pubkeySignature: defaultPubKeySignature // }); - IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = new IRegistryCoordinator.OperatorKickParam[](1); - operatorKickParams[0] = IRegistryCoordinator.OperatorKickParam({ - operator: address(0x1), - quorumNumber: 0 - }); + IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = + new IRegistryCoordinator.OperatorKickParam[](1); + operatorKickParams[0] = + IRegistryCoordinator.OperatorKickParam({operator: address(0x1), quorumNumber: 0}); ISignatureUtils.SignatureWithSaltAndExpiry memory churnApproverSignature; ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; bytes memory registerParams = abi.encode( - socket, - params, - operatorKickParams, - churnApproverSignature, - operatorSignature + socket, params, operatorKickParams, churnApproverSignature, operatorSignature ); // Prank as allocation manager and call register hook @@ -2234,24 +2633,22 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT vm.skip(true); _deployMockEigenLayerAndAVS(0); - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator + .OperatorSetParam({ maxOperatorCount: defaultMaxOperatorCount, kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = IStakeRegistry.StrategyParams({ - strategy: IStrategy(address(1)), - multiplier: 10000 - }); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = + IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10_000}); cheats.prank(registryCoordinatorOwner); registryCoordinator.createTotalDelegatedStakeQuorum( - operatorSetParams, - minimumStake, - strategyParams + operatorSetParams, minimumStake, strategyParams ); uint256 quorumBitmap = 0; @@ -2260,33 +2657,28 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT } function test_deregisterHook() public { - _deployMockEigenLayerAndAVS(0); // Enable operator sets first cheats.prank(registryCoordinatorOwner); registryCoordinator.enableOperatorSets(); // Create quorum params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator + .OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = IStakeRegistry.StrategyParams({ - strategy: IStrategy(address(1)), - multiplier: 10000 - }); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = + IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10_000}); // Create total delegated stake quorum cheats.prank(registryCoordinatorOwner); - registryCoordinator.createTotalDelegatedStakeQuorum( - operatorSetParams, - 0, - strategyParams - ); + registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, 0, strategyParams); // Prank as allocation manager and call register hook uint32[] memory operatorSetIds = new uint32[](1); @@ -2303,7 +2695,6 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT bytes memory data = abi.encode(socket, params); - cheats.startPrank(address(registryCoordinator.allocationManager())); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); @@ -2313,34 +2704,28 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT } function test_registerHook_Reverts_WhenNotALM() public { - _deployMockEigenLayerAndAVS(0); // Enable operator sets first cheats.prank(registryCoordinatorOwner); registryCoordinator.enableOperatorSets(); // Create quorum params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator + .OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = IStakeRegistry.StrategyParams({ - strategy: IStrategy(address(1)), - multiplier: 10000 - }); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = + IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10_000}); // Create total delegated stake quorum cheats.prank(registryCoordinatorOwner); - registryCoordinator.createTotalDelegatedStakeQuorum( - operatorSetParams, - 0, - strategyParams - ); - + registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, 0, strategyParams); uint32[] memory operatorSetIds = new uint32[](1); operatorSetIds[0] = 0; @@ -2361,33 +2746,28 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT } function test_deregisterHook_Reverts_WhenNotALM() public { - _deployMockEigenLayerAndAVS(0); // Enable operator sets first cheats.prank(registryCoordinatorOwner); registryCoordinator.enableOperatorSets(); // Create quorum params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator.OperatorSetParam({ + IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator + .OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = IStakeRegistry.StrategyParams({ - strategy: IStrategy(address(1)), - multiplier: 10000 - }); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](1); + strategyParams[0] = + IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10_000}); // Create total delegated stake quorum cheats.prank(registryCoordinatorOwner); - registryCoordinator.createTotalDelegatedStakeQuorum( - operatorSetParams, - 0, - strategyParams - ); + registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, 0, strategyParams); // Prank as allocation manager and call register hook uint32[] memory operatorSetIds = new uint32[](1); @@ -2404,14 +2784,12 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT bytes memory data = abi.encode(socket, params); - cheats.prank(address(registryCoordinator.allocationManager())); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); cheats.stopPrank(); cheats.expectRevert(); registryCoordinator.deregisterOperator(defaultOperator, operatorSetIds); - } function test_DeregisterHook_Reverts_WhenM2Quorum() public { @@ -2421,5 +2799,4 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT function test_registerHook_Reverts_WhenM2Quorum() public { vm.skip(true); } - } diff --git a/test/unit/ServiceManagerBase.t.sol b/test/unit/ServiceManagerBase.t.sol index 572998ca..74f9e848 100644 --- a/test/unit/ServiceManagerBase.t.sol +++ b/test/unit/ServiceManagerBase.t.sol @@ -8,7 +8,8 @@ import { IRewardsCoordinatorTypes, IERC20 } from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; -import {PermissionController} from "eigenlayer-contracts/src/contracts/permissions/PermissionController.sol"; +import {PermissionController} from + "eigenlayer-contracts/src/contracts/permissions/PermissionController.sol"; import {StrategyBase} from "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; import {IStrategyManager} from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; import {IServiceManagerBaseEvents} from "../events/IServiceManagerBaseEvents.sol"; @@ -25,8 +26,10 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve uint32 MAX_FUTURE_LENGTH = 28 days; uint32 GENESIS_REWARDS_TIMESTAMP = 1_712_188_800; uint256 MAX_REWARDS_AMOUNT = 1e38 - 1; - uint32 OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP = 0; /// TODO: what values should these have - uint32 OPERATOR_SET_MAX_RETROACTIVE_LENGTH = 0; /// TODO: What values these should have + uint32 OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP = 0; + /// TODO: what values should these have + uint32 OPERATOR_SET_MAX_RETROACTIVE_LENGTH = 0; + /// TODO: What values these should have /// @notice Delay in timestamp before a posted root can be claimed against uint32 activationDelay = 7 days; @@ -47,7 +50,9 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve // mapping to setting fuzzed inputs mapping(address => bool) public addressIsExcludedFromFuzzedInputs; - modifier filterFuzzedAddressInputs(address fuzzedAddress) { + modifier filterFuzzedAddressInputs( + address fuzzedAddress + ) { cheats.assume(!addressIsExcludedFromFuzzedInputs[fuzzedAddress]); _; } @@ -99,7 +104,10 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve address(serviceManagerImplementation), address(proxyAdmin), abi.encodeWithSelector( - ServiceManagerMock.initialize.selector, serviceManager.owner(), msg.sender, msg.sender + ServiceManagerMock.initialize.selector, + serviceManager.owner(), + msg.sender, + msg.sender ) ) ) @@ -150,7 +158,8 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve IERC20 token3 = new ERC20PresetFixedSupply( "pepe wif avs", "MOCK3", mockTokenInitialSupply, address(this) ); - strategyImplementation = new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry); + strategyImplementation = + new StrategyBase(IStrategyManager(address(strategyManagerMock)), pauserRegistry); strategyMock1 = StrategyBase( address( new TransparentUpgradeableProxy( @@ -200,7 +209,9 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve } /// @dev Sort to ensure that the array is in ascending order for strategies - function _sortArrayAsc(IStrategy[] memory arr) internal pure returns (IStrategy[] memory) { + function _sortArrayAsc( + IStrategy[] memory arr + ) internal pure returns (IStrategy[] memory) { uint256 l = arr.length; for (uint256 i = 0; i < l; i++) { for (uint256 j = i + 1; j < l; j++) { @@ -218,10 +229,9 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve return timestamp1 > timestamp2 ? timestamp1 : timestamp2; } - function testFuzz_createAVSRewardsSubmission_Revert_WhenNotOwner(address caller) - public - filterFuzzedAddressInputs(caller) - { + function testFuzz_createAVSRewardsSubmission_Revert_WhenNotOwner( + address caller + ) public filterFuzzedAddressInputs(caller) { cheats.assume(caller != rewardsInitiator); IRewardsCoordinator.RewardsSubmission[] memory rewardsSubmissions; @@ -289,15 +299,14 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve rewardToken.approve(address(serviceManager), amount); // 4. call createAVSRewardsSubmission() with expected event emitted - uint256 rewardsInitiatorBalanceBefore = - rewardToken.balanceOf(address(rewardsInitiator)); - uint256 rewardsCoordinatorBalanceBefore = - rewardToken.balanceOf(address(rewardsCoordinator)); + uint256 rewardsInitiatorBalanceBefore = rewardToken.balanceOf(address(rewardsInitiator)); + uint256 rewardsCoordinatorBalanceBefore = rewardToken.balanceOf(address(rewardsCoordinator)); rewardToken.approve(address(rewardsCoordinator), amount); uint256 currSubmissionNonce = rewardsCoordinator.submissionNonce(address(serviceManager)); - bytes32 avsSubmissionHash = - keccak256(abi.encode(address(serviceManager), currSubmissionNonce, rewardsSubmissions[0])); + bytes32 avsSubmissionHash = keccak256( + abi.encode(address(serviceManager), currSubmissionNonce, rewardsSubmissions[0]) + ); cheats.expectEmit(true, true, true, true, address(rewardsCoordinator)); emit AVSRewardsSubmissionCreated( @@ -307,7 +316,9 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve cheats.stopPrank(); assertTrue( - rewardsCoordinator.isAVSRewardsSubmissionHash(address(serviceManager), avsSubmissionHash), + rewardsCoordinator.isAVSRewardsSubmissionHash( + address(serviceManager), avsSubmissionHash + ), "reward submission hash not submitted" ); assertEq( @@ -342,8 +353,7 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve uint256 startSubmissionNonce = rewardsCoordinator.submissionNonce(address(serviceManager)); _deployMockRewardTokens(rewardsInitiator, numSubmissions); - uint256[] memory avsBalancesBefore = - _getBalanceForTokens(rewardTokens, rewardsInitiator); + uint256[] memory avsBalancesBefore = _getBalanceForTokens(rewardTokens, rewardsInitiator); uint256[] memory rewardsCoordinatorBalancesBefore = _getBalanceForTokens(rewardTokens, address(rewardsCoordinator)); uint256[] memory amounts = new uint256[](numSubmissions); @@ -367,7 +377,8 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create reward submission input param - IRewardsCoordinatorTypes.RewardsSubmission memory rewardsSubmission = IRewardsCoordinatorTypes.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission memory rewardsSubmission = + IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardTokens[i], amount: amounts[i], @@ -439,8 +450,7 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve cheats.prank(rewardsInitiator); rewardToken.approve(address(serviceManager), mockTokenInitialSupply); uint256 avsBalanceBefore = rewardToken.balanceOf(rewardsInitiator); - uint256 rewardsCoordinatorBalanceBefore = - rewardToken.balanceOf(address(rewardsCoordinator)); + uint256 rewardsCoordinatorBalanceBefore = rewardToken.balanceOf(address(rewardsCoordinator)); uint256 totalAmount = 0; uint256[] memory amounts = new uint256[](numSubmissions); @@ -465,7 +475,8 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve startTimestamp = startTimestamp - (startTimestamp % CALCULATION_INTERVAL_SECONDS); // 2. Create reward submission input param - IRewardsCoordinatorTypes.RewardsSubmission memory rewardsSubmission = IRewardsCoordinatorTypes.RewardsSubmission({ + IRewardsCoordinatorTypes.RewardsSubmission memory rewardsSubmission = + IRewardsCoordinatorTypes.RewardsSubmission({ strategiesAndMultipliers: defaultStrategyAndMultipliers, token: rewardToken, amount: amounts[i], @@ -532,4 +543,4 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve cheats.prank(caller); serviceManager.setRewardsInitiator(newRewardsInitiator); } -} \ No newline at end of file +} diff --git a/test/unit/ServiceManagerRouter.t.sol b/test/unit/ServiceManagerRouter.t.sol index 2e3d1e94..cb44d6f6 100644 --- a/test/unit/ServiceManagerRouter.t.sol +++ b/test/unit/ServiceManagerRouter.t.sol @@ -49,17 +49,20 @@ contract ServiceManagerRouter_UnitTests is MockAVSDeployer { } function test_getOperatorRestakedStrategies_noStrats() public { - address[] memory strategies = router.getOperatorRestakedStrategies(address(dummyServiceManager), defaultOperator); + address[] memory strategies = + router.getOperatorRestakedStrategies(address(dummyServiceManager), defaultOperator); assertEq(strategies.length, 0); } function test_getOperatorRestakedStrategies_multipleStrats() public { - address[] memory strategies = router.getOperatorRestakedStrategies(address(serviceManager), defaultOperator); + address[] memory strategies = + router.getOperatorRestakedStrategies(address(serviceManager), defaultOperator); assertEq(strategies.length, 192); } function test_getOperatorRestakedStrategies_badImplementation() public { - address[] memory strategies = router.getOperatorRestakedStrategies(address(emptyContract), defaultOperator); + address[] memory strategies = + router.getOperatorRestakedStrategies(address(emptyContract), defaultOperator); assertEq(strategies.length, 1); assertEq(strategies[0], badReturn); } diff --git a/test/unit/StakeRegistryUnit.t.sol b/test/unit/StakeRegistryUnit.t.sol index aefb220e..ef479d7e 100644 --- a/test/unit/StakeRegistryUnit.t.sol +++ b/test/unit/StakeRegistryUnit.t.sol @@ -33,7 +33,9 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { uint256 gasUsed; - modifier fuzzOnlyInitializedQuorums(uint8 quorumNumber) { + modifier fuzzOnlyInitializedQuorums( + uint8 quorumNumber + ) { cheats.assume(initializedQuorumBitmap.isSet(quorumNumber)); _; } @@ -54,7 +56,11 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { ); stakeRegistryImplementation = new StakeRegistryHarness( - IRegistryCoordinator(address(registryCoordinator)), delegationMock, avsDirectoryMock, allocationManager, serviceManager + IRegistryCoordinator(address(registryCoordinator)), + delegationMock, + avsDirectoryMock, + allocationManager, + serviceManager ); stakeRegistry = StakeRegistryHarness( @@ -88,7 +94,9 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { * @dev Initialize a new quorum with `minimumStake` * The new quorum's number is sequential, starting with `nextQuorum` */ - function _initializeQuorum(uint96 minimumStake) internal { + function _initializeQuorum( + uint96 minimumStake + ) internal { uint8 quorumNumber = nextQuorum; IStakeRegistry.StrategyParams[] memory strategyParams = @@ -389,7 +397,9 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { /// @notice Given a fuzzed bitmap input, returns a bitmap and array of quorum numbers /// that are guaranteed to be initialized. - function _fuzz_getQuorums(uint192 fuzzy_Bitmap) internal view returns (uint192, bytes memory) { + function _fuzz_getQuorums( + uint192 fuzzy_Bitmap + ) internal view returns (uint192, bytes memory) { fuzzy_Bitmap &= initializedQuorumBitmap; cheats.assume(!fuzzy_Bitmap.isEmpty()); @@ -399,7 +409,9 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { /// @notice Returns a list of initialized quorums ending in a non-initialized quorum /// @param rand is used to determine how many legitimate quorums to insert, so we can /// check this works for lists of varying lengths - function _fuzz_getInvalidQuorums(bytes32 rand) internal returns (bytes memory) { + function _fuzz_getInvalidQuorums( + bytes32 rand + ) internal returns (bytes memory) { uint256 length = _randUint({rand: rand, min: 1, max: initializedQuorumBytes.length + 1}); bytes memory invalidQuorums = new bytes(length); @@ -431,11 +443,9 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { } /// @dev Return the minimum stakes required for a list of quorums - function _getMinimumStakes(bytes memory quorumNumbers) - internal - view - returns (uint96[] memory) - { + function _getMinimumStakes( + bytes memory quorumNumbers + ) internal view returns (uint96[] memory) { uint96[] memory minimumStakes = new uint96[](quorumNumbers.length); for (uint256 i = 0; i < quorumNumbers.length; i++) { @@ -463,11 +473,9 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { } /// @dev Return the most recent total stake update history entries - function _getLatestTotalStakeUpdates(bytes memory quorumNumbers) - internal - view - returns (IStakeRegistry.StakeUpdate[] memory) - { + function _getLatestTotalStakeUpdates( + bytes memory quorumNumbers + ) internal view returns (IStakeRegistry.StakeUpdate[] memory) { IStakeRegistry.StakeUpdate[] memory stakeUpdates = new IStakeRegistry.StakeUpdate[](quorumNumbers.length); @@ -500,11 +508,9 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { } /// @dev Return the lengths of the total stake update history - function _getTotalStakeHistoryLengths(bytes memory quorumNumbers) - internal - view - returns (uint256[] memory) - { + function _getTotalStakeHistoryLengths( + bytes memory quorumNumbers + ) internal view returns (uint256[] memory) { uint256[] memory historyLengths = new uint256[](quorumNumbers.length); for (uint256 i = 0; i < quorumNumbers.length; i++) { @@ -554,7 +560,9 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { } /// @dev Sort to ensure that the array is in desscending order for removeStrategies - function _sortArrayDesc(uint256[] memory arr) internal pure returns (uint256[] memory) { + function _sortArrayDesc( + uint256[] memory arr + ) internal pure returns (uint256[] memory) { uint256 l = arr.length; for (uint256 i = 0; i < l; i++) { for (uint256 j = i + 1; j < l; j++) { @@ -616,6 +624,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { cheats.prank(address(registryCoordinator)); stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); } + event StakeTypeSet(StakeType newStakeType); function test_initializeDelegatedStakeQuorum() public { @@ -631,11 +640,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { cheats.prank(address(registryCoordinator)); cheats.expectEmit(true, true, true, true); emit StakeTypeSet(StakeType.TOTAL_DELEGATED); - stakeRegistry.initializeDelegatedStakeQuorum( - quorumNumber, - minimumStake, - strategyParams - ); + stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); StakeType stakeType = stakeRegistry.stakeTypePerQuorum(quorumNumber); assertEq(uint8(stakeType), uint8(StakeType.TOTAL_DELEGATED), "invalid stake type"); @@ -655,10 +660,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { cheats.expectEmit(true, true, true, true); emit StakeTypeSet(StakeType.TOTAL_SLASHABLE); stakeRegistry.initializeSlashableStakeQuorum( - quorumNumber, - minimumStake, - 7 days, - strategyParams + quorumNumber, minimumStake, 7 days, strategyParams ); StakeType stakeType = stakeRegistry.stakeTypePerQuorum(quorumNumber); @@ -984,10 +986,9 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { stakeRegistry.modifyStrategyParams(quorumNumber, strategyIndices, newMultipliers); } - function testFuzz_modifyStrategyParams_Revert_WhenEmptyArray(uint8 quorumNumber) - public - fuzzOnlyInitializedQuorums(quorumNumber) - { + function testFuzz_modifyStrategyParams_Revert_WhenEmptyArray( + uint8 quorumNumber + ) public fuzzOnlyInitializedQuorums(quorumNumber) { uint256[] memory strategyIndices = new uint256[](0); uint96[] memory newMultipliers = new uint96[](0); cheats.expectRevert(IStakeRegistryErrors.InputArrayLengthZero.selector); @@ -1065,7 +1066,9 @@ contract StakeRegistryUnitTests_Register is StakeRegistryUnitTests { stakeRegistry.registerOperator(operator, operatorId, initializedQuorumBytes); } - function testFuzz_Revert_WhenQuorumDoesNotExist(bytes32 rand) public { + function testFuzz_Revert_WhenQuorumDoesNotExist( + bytes32 rand + ) public { RegisterSetup memory setup = _fuzz_setupRegisterOperator(initializedQuorumBitmap, 0); // Get a list of valid quorums ending in an invalid quorum number @@ -1078,10 +1081,9 @@ contract StakeRegistryUnitTests_Register is StakeRegistryUnitTests { /// @dev Attempt to register for all quorums, selecting one quorum to attempt with /// insufficient stake - function testFuzz_registerOperator_Revert_WhenInsufficientStake(uint8 failingQuorum) - public - fuzzOnlyInitializedQuorums(failingQuorum) - { + function testFuzz_registerOperator_Revert_WhenInsufficientStake( + uint8 failingQuorum + ) public fuzzOnlyInitializedQuorums(failingQuorum) { (address operator, bytes32 operatorId) = _selectNewOperator(); bytes memory quorumNumbers = initializedQuorumBytes; uint96[] memory minimumStakes = _getMinimumStakes(quorumNumbers); @@ -1415,7 +1417,9 @@ contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { stakeRegistry.deregisterOperator(setup.operatorId, setup.quorumsToRemove); } - function testFuzz_deregisterOperator_Revert_WhenQuorumDoesNotExist(bytes32 rand) public { + function testFuzz_deregisterOperator_Revert_WhenQuorumDoesNotExist( + bytes32 rand + ) public { // Create a new operator registered for all quorums DeregisterSetup memory setup = _fuzz_setupDeregisterOperator({ registeredFor: initializedQuorumBitmap, @@ -1777,7 +1781,9 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { stakeRegistry.updateOperatorStake(setup.operator, setup.operatorId, setup.quorumNumbers); } - function testFuzz_updateOperatorStake_Revert_WhenQuorumDoesNotExist(bytes32 rand) public { + function testFuzz_updateOperatorStake_Revert_WhenQuorumDoesNotExist( + bytes32 rand + ) public { // Create a new operator registered for all quorums UpdateSetup memory setup = _fuzz_setupUpdateOperatorStake({registeredFor: initializedQuorumBitmap, fuzzy_Delta: 0}); @@ -1798,7 +1804,9 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { * updateOperatorStake should then update the operator's stake using the new weight - we test * what happens when the operator remains at/above minimum stake, vs dipping below */ - function testFuzz_updateOperatorStake_SingleOperator_SingleBlock(int8 stakeDelta) public { + function testFuzz_updateOperatorStake_SingleOperator_SingleBlock( + int8 stakeDelta + ) public { UpdateSetup memory setup = _fuzz_setupUpdateOperatorStake({ registeredFor: initializedQuorumBitmap, fuzzy_Delta: stakeDelta @@ -2183,7 +2191,9 @@ contract StakeRegistryUnitTests_weightOfOperatorForQuorum is StakeRegistryUnitTe } cheats.prank(address(registryCoordinator)); uint8 quorumNumber = nextQuorum; - stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, 0, /* minimumStake */ strategyParams); + stakeRegistry.initializeDelegatedStakeQuorum( + quorumNumber, 0, /* minimumStake */ strategyParams + ); // set the operator shares for (uint256 i = 0; i < strategyParams.length; i++) { @@ -2230,7 +2240,9 @@ contract StakeRegistryUnitTests_weightOfOperatorForQuorum is StakeRegistryUnitTe // create a valid quorum cheats.prank(address(registryCoordinator)); uint8 quorumNumber = nextQuorum; - stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, 0, /* minimumStake */ strategyParams); + stakeRegistry.initializeDelegatedStakeQuorum( + quorumNumber, 0, /* minimumStake */ strategyParams + ); // set the operator shares for (uint256 i = 0; i < strategyParams.length; i++) { diff --git a/test/unit/UpgradeableProxyLib.sol b/test/unit/UpgradeableProxyLib.sol index 15fd49d8..0f0986f5 100644 --- a/test/unit/UpgradeableProxyLib.sol +++ b/test/unit/UpgradeableProxyLib.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.0; + import {Vm} from "forge-std/Vm.sol"; import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; import {TransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; -contract EmptyContract { -} +contract EmptyContract {} library UpgradeableProxyLib { bytes32 internal constant IMPLEMENTATION_SLOT = @@ -14,33 +14,39 @@ library UpgradeableProxyLib { bytes32 internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; Vm internal constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + function deployProxyAdmin() internal returns (address) { return address(new ProxyAdmin()); } + function setUpEmptyProxy( address admin ) internal returns (address) { address emptyContract = address(new EmptyContract()); return address(new TransparentUpgradeableProxy(emptyContract, admin, "")); } + function upgrade(address proxy, address impl) internal { ProxyAdmin admin = getProxyAdmin(proxy); admin.upgrade(TransparentUpgradeableProxy(payable(proxy)), impl); } + function upgradeAndCall(address proxy, address impl, bytes memory initData) internal { ProxyAdmin admin = getProxyAdmin(proxy); admin.upgradeAndCall(TransparentUpgradeableProxy(payable(proxy)), impl, initData); } + function getImplementation( address proxy ) internal view returns (address) { bytes32 value = vm.load(proxy, IMPLEMENTATION_SLOT); return address(uint160(uint256(value))); } + function getProxyAdmin( address proxy ) internal view returns (ProxyAdmin) { bytes32 value = vm.load(proxy, ADMIN_SLOT); return ProxyAdmin(address(uint160(uint256(value)))); } -} \ No newline at end of file +} diff --git a/test/unit/Utils.sol b/test/unit/Utils.sol index 6e085215..463d8a3b 100644 --- a/test/unit/Utils.sol +++ b/test/unit/Utils.sol @@ -6,16 +6,15 @@ import "eigenlayer-contracts/src/contracts/strategies/StrategyBase.sol"; contract Utils { address constant dummyAdmin = address(uint160(uint256(keccak256("DummyAdmin")))); - function deployNewStrategy(IERC20 token, IStrategyManager strategyManager, IPauserRegistry pauserRegistry, address admin) public returns (StrategyBase) { + function deployNewStrategy( + IERC20 token, + IStrategyManager strategyManager, + IPauserRegistry pauserRegistry, + address admin + ) public returns (StrategyBase) { StrategyBase newStrategy = new StrategyBase(strategyManager, pauserRegistry); newStrategy = StrategyBase( - address( - new TransparentUpgradeableProxy( - address(newStrategy), - address(admin), - "" - ) - ) + address(new TransparentUpgradeableProxy(address(newStrategy), address(admin), "")) ); newStrategy.initialize(token); return newStrategy; diff --git a/test/utils/BLSMockAVSDeployer.sol b/test/utils/BLSMockAVSDeployer.sol index 7923fca4..84890944 100644 --- a/test/utils/BLSMockAVSDeployer.sol +++ b/test/utils/BLSMockAVSDeployer.sol @@ -16,55 +16,73 @@ contract BLSMockAVSDeployer is MockAVSDeployer { BN254.G2Point oneHundredQuorumApkG2; BN254.G1Point sigma; - function _setUpBLSMockAVSDeployer() virtual public { + function _setUpBLSMockAVSDeployer() public virtual { _deployMockEigenLayerAndAVS(); _setAggregatePublicKeysAndSignature(); } - function _setUpBLSMockAVSDeployer(uint8 numQuorumsToAdd) virtual public { + function _setUpBLSMockAVSDeployer( + uint8 numQuorumsToAdd + ) public virtual { _deployMockEigenLayerAndAVS(numQuorumsToAdd); _setAggregatePublicKeysAndSignature(); } function _setAggregatePublicKeysAndSignature() internal { // aggSignerPrivKey*g2 - aggSignerApkG2.X[1] = 19101821850089705274637533855249918363070101489527618151493230256975900223847; - aggSignerApkG2.X[0] = 5334410886741819556325359147377682006012228123419628681352847439302316235957; - aggSignerApkG2.Y[1] = 354176189041917478648604979334478067325821134838555150300539079146482658331; - aggSignerApkG2.Y[0] = 4185483097059047421902184823581361466320657066600218863748375739772335928910; + aggSignerApkG2.X[1] = + 19_101_821_850_089_705_274_637_533_855_249_918_363_070_101_489_527_618_151_493_230_256_975_900_223_847; + aggSignerApkG2.X[0] = + 5_334_410_886_741_819_556_325_359_147_377_682_006_012_228_123_419_628_681_352_847_439_302_316_235_957; + aggSignerApkG2.Y[1] = + 354_176_189_041_917_478_648_604_979_334_478_067_325_821_134_838_555_150_300_539_079_146_482_658_331; + aggSignerApkG2.Y[0] = + 4_185_483_097_059_047_421_902_184_823_581_361_466_320_657_066_600_218_863_748_375_739_772_335_928_910; // 100*aggSignerPrivKey*g2 - oneHundredQuorumApkG2.X[1] = 6187649255575786743153792867265230878737103598736372524337965086852090105771; - oneHundredQuorumApkG2.X[0] = 5334877400925935887383922877430837542135722474116902175395820705628447222839; - oneHundredQuorumApkG2.Y[1] = 4668116328019846503695710811760363536142902258271850958815598072072236299223; - oneHundredQuorumApkG2.Y[0] = 21446056442597180561077194011672151329458819211586246807143487001691968661015; + oneHundredQuorumApkG2.X[1] = + 6_187_649_255_575_786_743_153_792_867_265_230_878_737_103_598_736_372_524_337_965_086_852_090_105_771; + oneHundredQuorumApkG2.X[0] = + 5_334_877_400_925_935_887_383_922_877_430_837_542_135_722_474_116_902_175_395_820_705_628_447_222_839; + oneHundredQuorumApkG2.Y[1] = + 4_668_116_328_019_846_503_695_710_811_760_363_536_142_902_258_271_850_958_815_598_072_072_236_299_223; + oneHundredQuorumApkG2.Y[0] = + 21_446_056_442_597_180_561_077_194_011_672_151_329_458_819_211_586_246_807_143_487_001_691_968_661_015; sigma = BN254.hashToG1(msgHash).scalar_mul(aggSignerPrivKey); } - - function _generateSignerAndNonSignerPrivateKeys(uint256 pseudoRandomNumber, uint256 numSigners, uint256 numNonSigners) internal view returns (uint256[] memory, uint256[] memory) { + function _generateSignerAndNonSignerPrivateKeys( + uint256 pseudoRandomNumber, + uint256 numSigners, + uint256 numNonSigners + ) internal view returns (uint256[] memory, uint256[] memory) { uint256[] memory signerPrivateKeys = new uint256[](numSigners); // generate numSigners numbers that add up to aggSignerPrivKey mod BN254.FR_MODULUS uint256 sum = 0; - for (uint i = 0; i < numSigners - 1; i++) { - signerPrivateKeys[i] = uint256(keccak256(abi.encodePacked("signerPrivateKey", pseudoRandomNumber, i))) % BN254.FR_MODULUS; + for (uint256 i = 0; i < numSigners - 1; i++) { + signerPrivateKeys[i] = uint256( + keccak256(abi.encodePacked("signerPrivateKey", pseudoRandomNumber, i)) + ) % BN254.FR_MODULUS; sum = addmod(sum, signerPrivateKeys[i], BN254.FR_MODULUS); } // signer private keys need to add to aggSignerPrivKey - signerPrivateKeys[numSigners - 1] = addmod(aggSignerPrivKey, BN254.FR_MODULUS - sum % BN254.FR_MODULUS, BN254.FR_MODULUS); + signerPrivateKeys[numSigners - 1] = + addmod(aggSignerPrivKey, BN254.FR_MODULUS - sum % BN254.FR_MODULUS, BN254.FR_MODULUS); uint256[] memory nonSignerPrivateKeys = new uint256[](numNonSigners); - for (uint i = 0; i < numNonSigners; i++) { - nonSignerPrivateKeys[i] = uint256(keccak256(abi.encodePacked("nonSignerPrivateKey", pseudoRandomNumber, i))) % BN254.FR_MODULUS; + for (uint256 i = 0; i < numNonSigners; i++) { + nonSignerPrivateKeys[i] = uint256( + keccak256(abi.encodePacked("nonSignerPrivateKey", pseudoRandomNumber, i)) + ) % BN254.FR_MODULUS; } // Sort nonSignerPrivateKeys in order of ascending pubkeyHash // Uses insertion sort to sort array in place - for (uint i = 1; i < nonSignerPrivateKeys.length; i++) { - uint privateKey = nonSignerPrivateKeys[i]; + for (uint256 i = 1; i < nonSignerPrivateKeys.length; i++) { + uint256 privateKey = nonSignerPrivateKeys[i]; bytes32 pubkeyHash = _toPubkeyHash(privateKey); - uint j = i; + uint256 j = i; // Move elements of nonSignerPrivateKeys[0..i-1] that are greater than the current key // to one position ahead of their current position @@ -78,8 +96,15 @@ contract BLSMockAVSDeployer is MockAVSDeployer { return (signerPrivateKeys, nonSignerPrivateKeys); } - function _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom(uint256 pseudoRandomNumber, uint256 numNonSigners, uint256 quorumBitmap) internal returns(uint32, BLSSignatureChecker.NonSignerStakesAndSignature memory) { - (uint256[] memory signerPrivateKeys, uint256[] memory nonSignerPrivateKeys) = _generateSignerAndNonSignerPrivateKeys(pseudoRandomNumber, maxOperatorsToRegister - numNonSigners, numNonSigners); + function _registerSignatoriesAndGetNonSignerStakeAndSignatureRandom( + uint256 pseudoRandomNumber, + uint256 numNonSigners, + uint256 quorumBitmap + ) internal returns (uint32, BLSSignatureChecker.NonSignerStakesAndSignature memory) { + (uint256[] memory signerPrivateKeys, uint256[] memory nonSignerPrivateKeys) = + _generateSignerAndNonSignerPrivateKeys( + pseudoRandomNumber, maxOperatorsToRegister - numNonSigners, numNonSigners + ); bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); // randomly combine signer and non-signer private keys @@ -94,15 +119,17 @@ contract BLSMockAVSDeployer is MockAVSDeployer { { uint256 signerIndex = 0; uint256 nonSignerIndex = 0; - for (uint i = 0; i < maxOperatorsToRegister; i++) { + for (uint256 i = 0; i < maxOperatorsToRegister; i++) { uint256 randomSeed = uint256(keccak256(abi.encodePacked("privKeyCombination", i))); if (randomSeed % 2 == 0 && signerIndex < signerPrivateKeys.length) { privateKeys[i] = signerPrivateKeys[signerIndex]; signerIndex++; } else if (nonSignerIndex < nonSignerPrivateKeys.length) { privateKeys[i] = nonSignerPrivateKeys[nonSignerIndex]; - nonSignerStakesAndSignature.nonSignerPubkeys[nonSignerIndex] = BN254.generatorG1().scalar_mul(privateKeys[i]); - nonSignerOperatorIds[nonSignerIndex] = nonSignerStakesAndSignature.nonSignerPubkeys[nonSignerIndex].hashG1Point(); + nonSignerStakesAndSignature.nonSignerPubkeys[nonSignerIndex] = + BN254.generatorG1().scalar_mul(privateKeys[i]); + nonSignerOperatorIds[nonSignerIndex] = + nonSignerStakesAndSignature.nonSignerPubkeys[nonSignerIndex].hashG1Point(); nonSignerIndex++; } else { privateKeys[i] = signerPrivateKeys[signerIndex]; @@ -113,39 +140,43 @@ contract BLSMockAVSDeployer is MockAVSDeployer { pubkeys[i] = BN254.generatorG1().scalar_mul(privateKeys[i]); // add the public key to each quorum - for (uint j = 0; j < nonSignerStakesAndSignature.quorumApks.length; j++) { - nonSignerStakesAndSignature.quorumApks[j] = nonSignerStakesAndSignature.quorumApks[j].plus(pubkeys[i]); + for (uint256 j = 0; j < nonSignerStakesAndSignature.quorumApks.length; j++) { + nonSignerStakesAndSignature.quorumApks[j] = + nonSignerStakesAndSignature.quorumApks[j].plus(pubkeys[i]); } } } // register all operators for the first quorum - for (uint i = 0; i < maxOperatorsToRegister; i++) { + for (uint256 i = 0; i < maxOperatorsToRegister; i++) { cheats.roll(registrationBlockNumber + blocksBetweenRegistrations * i); _registerOperatorWithCoordinator(operators[i], quorumBitmap, pubkeys[i], defaultStake); } - uint32 referenceBlockNumber = registrationBlockNumber + blocksBetweenRegistrations * uint32(maxOperatorsToRegister) + 1; + uint32 referenceBlockNumber = registrationBlockNumber + + blocksBetweenRegistrations * uint32(maxOperatorsToRegister) + 1; cheats.roll(referenceBlockNumber + 100); - OperatorStateRetriever.CheckSignaturesIndices memory checkSignaturesIndices = operatorStateRetriever.getCheckSignaturesIndices( - registryCoordinator, - referenceBlockNumber, - quorumNumbers, - nonSignerOperatorIds + OperatorStateRetriever.CheckSignaturesIndices memory checkSignaturesIndices = + operatorStateRetriever.getCheckSignaturesIndices( + registryCoordinator, referenceBlockNumber, quorumNumbers, nonSignerOperatorIds ); - nonSignerStakesAndSignature.nonSignerQuorumBitmapIndices = checkSignaturesIndices.nonSignerQuorumBitmapIndices; + nonSignerStakesAndSignature.nonSignerQuorumBitmapIndices = + checkSignaturesIndices.nonSignerQuorumBitmapIndices; nonSignerStakesAndSignature.apkG2 = aggSignerApkG2; nonSignerStakesAndSignature.sigma = sigma; nonSignerStakesAndSignature.quorumApkIndices = checkSignaturesIndices.quorumApkIndices; nonSignerStakesAndSignature.totalStakeIndices = checkSignaturesIndices.totalStakeIndices; - nonSignerStakesAndSignature.nonSignerStakeIndices = checkSignaturesIndices.nonSignerStakeIndices; + nonSignerStakesAndSignature.nonSignerStakeIndices = + checkSignaturesIndices.nonSignerStakeIndices; return (referenceBlockNumber, nonSignerStakesAndSignature); } - function _toPubkeyHash(uint privKey) internal view returns (bytes32) { + function _toPubkeyHash( + uint256 privKey + ) internal view returns (bytes32) { return BN254.generatorG1().scalar_mul(privKey).hashG1Point(); } } diff --git a/test/utils/CoreDeployLib.sol b/test/utils/CoreDeployLib.sol index d88f6ff6..d25dd95a 100644 --- a/test/utils/CoreDeployLib.sol +++ b/test/utils/CoreDeployLib.sol @@ -268,4 +268,4 @@ // return result; // } -// } \ No newline at end of file +// } diff --git a/test/utils/MockAVSDeployer.sol b/test/utils/MockAVSDeployer.sol index a0ef478e..15e6d425 100644 --- a/test/utils/MockAVSDeployer.sol +++ b/test/utils/MockAVSDeployer.sol @@ -35,7 +35,8 @@ import {RewardsCoordinatorMock} from "../mocks/RewardsCoordinatorMock.sol"; import {PermissionControllerMock} from "../mocks/PermissionControllerMock.sol"; import {RewardsCoordinator} from "eigenlayer-contracts/src/contracts/core/RewardsCoordinator.sol"; -import {PermissionController} from "eigenlayer-contracts/src/contracts/permissions/PermissionController.sol"; +import {PermissionController} from + "eigenlayer-contracts/src/contracts/permissions/PermissionController.sol"; import {AllocationManager} from "eigenlayer-contracts/src/contracts/core/AllocationManager.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; @@ -137,7 +138,9 @@ contract MockAVSDeployer is Test { _deployMockEigenLayerAndAVS(numQuorums); } - function _deployMockEigenLayerAndAVS(uint8 numQuorumsToAdd) internal { + function _deployMockEigenLayerAndAVS( + uint8 numQuorumsToAdd + ) internal { emptyContract = new EmptyContract(); defaultOperatorId = defaultPubKey.hashG1Point(); @@ -205,8 +208,13 @@ contract MockAVSDeployer is Test { cheats.startPrank(proxyAdminOwner); - stakeRegistryImplementation = - new StakeRegistryHarness(IRegistryCoordinator(registryCoordinator), delegationMock, avsDirectory, allocationManagerMock, serviceManager); + stakeRegistryImplementation = new StakeRegistryHarness( + IRegistryCoordinator(registryCoordinator), + delegationMock, + avsDirectory, + allocationManagerMock, + serviceManager + ); proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(stakeRegistry))), address(stakeRegistryImplementation) @@ -241,7 +249,7 @@ contract MockAVSDeployer is Test { pauserRegistry, permissionControllerMock, uint32(7 days), // DEALLOCATION_DELAY - uint32(1 days) // ALLOCATION_CONFIGURATION_DELAY + uint32(1 days) // ALLOCATION_CONFIGURATION_DELAY ); proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(allocationManager))), @@ -273,7 +281,12 @@ contract MockAVSDeployer is Test { } registryCoordinatorImplementation = new RegistryCoordinatorHarness( - serviceManager, stakeRegistry, blsApkRegistry, indexRegistry, allocationManagerMock, pauserRegistry + serviceManager, + stakeRegistry, + blsApkRegistry, + indexRegistry, + allocationManagerMock, + pauserRegistry ); { delete operatorSetParams; @@ -314,7 +327,8 @@ contract MockAVSDeployer is Test { quorumStakeTypes, // _stakeTypes slashableStakeQuorumLookAheadPeriods // _lookAheadPeriods ) - )); + ) + ); } operatorStateRetriever = new OperatorStateRetriever(); @@ -410,10 +424,9 @@ contract MockAVSDeployer is Test { ); } - function _registerRandomOperators(uint256 pseudoRandomNumber) - internal - returns (OperatorMetadata[] memory, uint256[][] memory) - { + function _registerRandomOperators( + uint256 pseudoRandomNumber + ) internal returns (OperatorMetadata[] memory, uint256[][] memory) { OperatorMetadata[] memory operatorMetadatas = new OperatorMetadata[](maxOperatorsToRegister); for (uint256 i = 0; i < operatorMetadatas.length; i++) { // limit to 16 quorums so we don't run out of gas, make them all register for quorum 0 as well diff --git a/test/utils/Operators.sol b/test/utils/Operators.sol index 266ed8d8..05a2ad78 100644 --- a/test/utils/Operators.sol +++ b/test/utils/Operators.sol @@ -12,19 +12,26 @@ contract Operators is Test { operatorConfigJson = vm.readFile("./src/test/test-data/operators.json"); } - function operatorPrefix(uint256 index) public pure returns(string memory) { + function operatorPrefix( + uint256 index + ) public pure returns (string memory) { return string.concat(".operators[", string.concat(vm.toString(index), "].")); } - function getNumOperators() public view returns(uint256) { + function getNumOperators() public view returns (uint256) { return stdJson.readUint(operatorConfigJson, ".numOperators"); } - function getOperatorAddress(uint256 index) public view returns(address) { - return stdJson.readAddress(operatorConfigJson, string.concat(operatorPrefix(index), "Address")); + function getOperatorAddress( + uint256 index + ) public view returns (address) { + return + stdJson.readAddress(operatorConfigJson, string.concat(operatorPrefix(index), "Address")); } - function getOperatorSchnorrSignature(uint256 index) public view returns(uint256, BN254.G1Point memory) { + function getOperatorSchnorrSignature( + uint256 index + ) public view returns (uint256, BN254.G1Point memory) { uint256 s = readUint(operatorConfigJson, index, "SField"); BN254.G1Point memory pubkey = BN254.G1Point({ X: readUint(operatorConfigJson, index, "RPoint.X"), @@ -33,11 +40,15 @@ contract Operators is Test { return (s, pubkey); } - function getOperatorSecretKey(uint256 index) public view returns(uint256) { + function getOperatorSecretKey( + uint256 index + ) public view returns (uint256) { return readUint(operatorConfigJson, index, "SecretKey"); } - function getOperatorPubkeyG1(uint256 index) public view returns(BN254.G1Point memory) { + function getOperatorPubkeyG1( + uint256 index + ) public view returns (BN254.G1Point memory) { BN254.G1Point memory pubkey = BN254.G1Point({ X: readUint(operatorConfigJson, index, "PubkeyG1.X"), Y: readUint(operatorConfigJson, index, "PubkeyG1.Y") @@ -45,7 +56,9 @@ contract Operators is Test { return pubkey; } - function getOperatorPubkeyG2(uint256 index) public view returns(BN254.G2Point memory) { + function getOperatorPubkeyG2( + uint256 index + ) public view returns (BN254.G2Point memory) { BN254.G2Point memory pubkey = BN254.G2Point({ X: [ readUint(operatorConfigJson, index, "PubkeyG2.X.A1"), @@ -59,11 +72,17 @@ contract Operators is Test { return pubkey; } - function readUint(string memory json, uint256 index, string memory key) public pure returns (uint256) { + function readUint( + string memory json, + uint256 index, + string memory key + ) public pure returns (uint256) { return stringToUint(stdJson.readString(json, string.concat(operatorPrefix(index), key))); } - function stringToUint(string memory s) public pure returns (uint256) { + function stringToUint( + string memory s + ) public pure returns (uint256) { bytes memory b = bytes(s); uint256 result = 0; for (uint256 i = 0; i < b.length; i++) { @@ -73,7 +92,10 @@ contract Operators is Test { } return result; } - function setOperatorJsonFilePath(string memory filepath) public { + + function setOperatorJsonFilePath( + string memory filepath + ) public { operatorConfigJson = vm.readFile(filepath); } } diff --git a/test/utils/Owners.sol b/test/utils/Owners.sol index cdb3add2..88155fa3 100644 --- a/test/utils/Owners.sol +++ b/test/utils/Owners.sol @@ -13,26 +13,30 @@ contract Owners is Test { ownersConfigJson = vm.readFile("./src/test/test-data/owners.json"); } - function ownerPrefix(uint256 index) public pure returns(string memory) { + function ownerPrefix( + uint256 index + ) public pure returns (string memory) { return string.concat(".owners[", string.concat(vm.toString(index), "].")); } - function getNumOperators() public view returns(uint256) { + function getNumOperators() public view returns (uint256) { return stdJson.readUint(ownersConfigJson, ".numOwners"); } - function getOwnerAddress(uint256 index) public view returns(address) { + function getOwnerAddress( + uint256 index + ) public view returns (address) { return stdJson.readAddress(ownersConfigJson, string.concat(ownerPrefix(index), "Address")); } - function getOwnerAddresses() public returns(address[] memory) { + function getOwnerAddresses() public returns (address[] memory) { for (uint256 i = 0; i < getNumOperators(); i++) { addresses.push(getOwnerAddress(i)); } return addresses; } - function getReputedOwnerAddresses() public returns(address[] memory) { + function getReputedOwnerAddresses() public returns (address[] memory) { resetOwnersConfigJson("reputedOwners.json"); for (uint256 i = 0; i < getNumOperators(); i++) { addresses.push(getOwnerAddress(i)); @@ -40,8 +44,9 @@ contract Owners is Test { return addresses; } - function resetOwnersConfigJson(string memory newConfig) public { + function resetOwnersConfigJson( + string memory newConfig + ) public { ownersConfigJson = vm.readFile(newConfig); } - } diff --git a/test/utils/ProofParsing.sol b/test/utils/ProofParsing.sol index 14ad89c6..cec8283f 100644 --- a/test/utils/ProofParsing.sol +++ b/test/utils/ProofParsing.sol @@ -5,8 +5,7 @@ import "../../src/libraries/BN254.sol"; import "forge-std/Test.sol"; import "forge-std/StdJson.sol"; - -contract ProofParsing is Test{ +contract ProofParsing is Test { string internal proofConfigJson; string prefix; @@ -16,184 +15,186 @@ contract ProofParsing is Test{ bytes32[46] validatorProof; bytes32[44] historicalSummaryProof; - - bytes32[7] executionPayloadProof; bytes32[4] timestampProofs; - bytes32 slotRoot; bytes32 executionPayloadRoot; - function setJSON(string memory path) public { + function setJSON( + string memory path + ) public { proofConfigJson = vm.readFile(path); } - function getSlot() public view returns(uint256) { + function getSlot() public view returns (uint256) { return stdJson.readUint(proofConfigJson, ".slot"); } - function getValidatorIndex() public view returns(uint256) { + function getValidatorIndex() public view returns (uint256) { return stdJson.readUint(proofConfigJson, ".validatorIndex"); } - function getValidatorPubkeyHash() public view returns(bytes32) { + function getValidatorPubkeyHash() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".ValidatorFields[0]"); } - function getWithdrawalIndex() public view returns(uint256) { + function getWithdrawalIndex() public view returns (uint256) { return stdJson.readUint(proofConfigJson, ".withdrawalIndex"); } - function getBlockRootIndex() public view returns(uint256) { + function getBlockRootIndex() public view returns (uint256) { return stdJson.readUint(proofConfigJson, ".blockHeaderRootIndex"); } - function getHistoricalSummaryIndex() public view returns(uint256) { + function getHistoricalSummaryIndex() public view returns (uint256) { return stdJson.readUint(proofConfigJson, ".historicalSummaryIndex"); } - function getBeaconStateRoot() public view returns(bytes32) { + function getBeaconStateRoot() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".beaconStateRoot"); } - function getBlockRoot() public view returns(bytes32) { + function getBlockRoot() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".blockHeaderRoot"); } - function getSlotRoot() public view returns(bytes32) { + function getSlotRoot() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".slotRoot"); } - function getBalanceRoot() public view returns(bytes32) { + function getBalanceRoot() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".balanceRoot"); } - function getTimestampRoot() public view returns(bytes32) { + function getTimestampRoot() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".timestampRoot"); } - function getExecutionPayloadRoot() public view returns(bytes32) { + function getExecutionPayloadRoot() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".executionPayloadRoot"); } - function getLatestBlockRoot() public view returns(bytes32) { + function getLatestBlockRoot() public view returns (bytes32) { return stdJson.readBytes32(proofConfigJson, ".latestBlockHeaderRoot"); } - function getExecutionPayloadProof () public returns(bytes32[7] memory) { - for (uint i = 0; i < 7; i++) { + + function getExecutionPayloadProof() public returns (bytes32[7] memory) { + for (uint256 i = 0; i < 7; i++) { prefix = string.concat(".ExecutionPayloadProof[", string.concat(vm.toString(i), "]")); executionPayloadProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return executionPayloadProof; } - function getTimestampProof() public returns(bytes32[4] memory) { - for (uint i = 0; i < 4; i++) { + function getTimestampProof() public returns (bytes32[4] memory) { + for (uint256 i = 0; i < 4; i++) { prefix = string.concat(".TimestampProof[", string.concat(vm.toString(i), "]")); timestampProofs[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return timestampProofs; } - function getBlockHeaderProof() public returns(bytes32[18] memory) { - for (uint i = 0; i < 18; i++) { + function getBlockHeaderProof() public returns (bytes32[18] memory) { + for (uint256 i = 0; i < 18; i++) { prefix = string.concat(".BlockHeaderProof[", string.concat(vm.toString(i), "]")); blockHeaderProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return blockHeaderProof; } - function getSlotProof() public returns(bytes32[3] memory) { - for (uint i = 0; i < 3; i++) { + function getSlotProof() public returns (bytes32[3] memory) { + for (uint256 i = 0; i < 3; i++) { prefix = string.concat(".SlotProof[", string.concat(vm.toString(i), "]")); slotProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return slotProof; } - function getStateRootProof() public returns(bytes32[] memory) { + function getStateRootProof() public returns (bytes32[] memory) { bytes32[] memory stateRootProof = new bytes32[](3); - for (uint i = 0; i < 3; i++) { - prefix = string.concat(".StateRootAgainstLatestBlockHeaderProof[", string.concat(vm.toString(i), "]")); + for (uint256 i = 0; i < 3; i++) { + prefix = string.concat( + ".StateRootAgainstLatestBlockHeaderProof[", string.concat(vm.toString(i), "]") + ); stateRootProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return stateRootProof; } - function getWithdrawalProof() public returns(bytes32[9] memory) { - for (uint i = 0; i < 9; i++) { + function getWithdrawalProof() public returns (bytes32[9] memory) { + for (uint256 i = 0; i < 9; i++) { prefix = string.concat(".WithdrawalProof[", string.concat(vm.toString(i), "]")); withdrawalProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return withdrawalProof; } - function getValidatorProof() public returns(bytes32[46] memory) { - for (uint i = 0; i < 46; i++) { + function getValidatorProof() public returns (bytes32[46] memory) { + for (uint256 i = 0; i < 46; i++) { prefix = string.concat(".ValidatorProof[", string.concat(vm.toString(i), "]")); validatorProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return validatorProof; } - function getHistoricalSummaryProof() public returns(bytes32[44] memory) { - for (uint i = 0; i < 44; i++) { + function getHistoricalSummaryProof() public returns (bytes32[44] memory) { + for (uint256 i = 0; i < 44; i++) { prefix = string.concat(".HistoricalSummaryProof[", string.concat(vm.toString(i), "]")); historicalSummaryProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return historicalSummaryProof; } - function getWithdrawalFields() public returns(bytes32[] memory) { + function getWithdrawalFields() public returns (bytes32[] memory) { bytes32[] memory withdrawalFields = new bytes32[](4); - for (uint i = 0; i < 4; i++) { + for (uint256 i = 0; i < 4; i++) { prefix = string.concat(".WithdrawalFields[", string.concat(vm.toString(i), "]")); withdrawalFields[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } - return withdrawalFields; - + return withdrawalFields; } - function getValidatorFields() public returns(bytes32[] memory) { + function getValidatorFields() public returns (bytes32[] memory) { bytes32[] memory validatorFields = new bytes32[](8); - for (uint i = 0; i < 8; i++) { + for (uint256 i = 0; i < 8; i++) { prefix = string.concat(".ValidatorFields[", string.concat(vm.toString(i), "]")); validatorFields[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return validatorFields; } - function getValidatorBalanceProof() public returns(bytes32[] memory) { + function getValidatorBalanceProof() public returns (bytes32[] memory) { bytes32[] memory validatorBalanceProof = new bytes32[](44); - for (uint i = 0; i < 44; i++) { + for (uint256 i = 0; i < 44; i++) { prefix = string.concat(".ValidatorBalanceProof[", string.concat(vm.toString(i), "]")); validatorBalanceProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return validatorBalanceProof; } - function getBalanceUpdateSlotProof() public returns(bytes32[] memory) { + function getBalanceUpdateSlotProof() public returns (bytes32[] memory) { bytes32[] memory balanceUpdateSlotProof = new bytes32[](5); - for (uint i = 0; i < 5; i++) { + for (uint256 i = 0; i < 5; i++) { prefix = string.concat(".slotProof[", string.concat(vm.toString(i), "]")); balanceUpdateSlotProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return balanceUpdateSlotProof; } - function getWithdrawalCredentialProof() public returns(bytes32[] memory) { + function getWithdrawalCredentialProof() public returns (bytes32[] memory) { bytes32[] memory withdrawalCredenitalProof = new bytes32[](46); - for (uint i = 0; i < 46; i++) { - prefix = string.concat(".WithdrawalCredentialProof[", string.concat(vm.toString(i), "]")); + for (uint256 i = 0; i < 46; i++) { + prefix = + string.concat(".WithdrawalCredentialProof[", string.concat(vm.toString(i), "]")); withdrawalCredenitalProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } return withdrawalCredenitalProof; } - function getValidatorFieldsProof() public returns(bytes32[] memory) { + function getValidatorFieldsProof() public returns (bytes32[] memory) { bytes32[] memory validatorFieldsProof = new bytes32[](46); - for (uint i = 0; i < 46; i++) { + for (uint256 i = 0; i < 46; i++) { prefix = string.concat(".ValidatorFieldsProof[", string.concat(vm.toString(i), "]")); validatorFieldsProof[i] = (stdJson.readBytes32(proofConfigJson, prefix)); } diff --git a/test/utils/SignatureCompaction.sol b/test/utils/SignatureCompaction.sol index 0bb98a1c..eac87690 100644 --- a/test/utils/SignatureCompaction.sol +++ b/test/utils/SignatureCompaction.sol @@ -5,7 +5,8 @@ import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; //small library for dealing with efficiently-packed signatures, where parameters v,r,s are packed into vs and r (64 bytes instead of 65) library SignatureCompaction { - bytes32 internal constant HALF_CURVE_ORDER = 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0; + bytes32 internal constant HALF_CURVE_ORDER = + 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0; function ecrecoverPacked(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) { (address recovered, ECDSA.RecoverError err) = ECDSA.tryRecover(hash, r, vs); @@ -13,7 +14,11 @@ library SignatureCompaction { return recovered; } - function packSignature(bytes32 r, bytes32 s, uint8 v) internal pure returns (bytes32, bytes32) { + function packSignature( + bytes32 r, + bytes32 s, + uint8 v + ) internal pure returns (bytes32, bytes32) { require(s <= HALF_CURVE_ORDER, "malleable signature, s too high"); //v parity is a single bit, encoded as either v = 27 or v = 28 -- in order to recover the bit we subtract 27 bytes32 vs = bytes32(uint256(bytes32(uint256(v) - 27) << 255) | uint256(s)); From 7e8aefffb5caa7f775a42e84833cc33142f62e4b Mon Sep 17 00:00:00 2001 From: steven <12021290+stevennevins@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:00:14 -0500 Subject: [PATCH 45/52] feat: add register with churn type (#360) * feat: add register with churn type * fix: tests for encoded registration type * feat: add ejector support for operator sets * refactor: handle operator set dereg * fix: dereg on churn from ALM if needed --- src/RegistryCoordinator.sol | 147 ++++++++++++++++++--- src/ServiceManagerBase.sol | 27 +++- src/ServiceManagerBaseStorage.sol | 15 ++- src/interfaces/IServiceManager.sol | 14 +- test/integration/CoreRegistration.t.sol | 3 +- test/integration/IntegrationDeployer.t.sol | 3 +- test/mocks/ECDSAServiceManagerMock.sol | 2 + test/mocks/ServiceManagerMock.sol | 6 +- test/unit/RegistryCoordinatorUnit.t.sol | 54 ++++++-- test/unit/ServiceManagerBase.t.sol | 3 +- test/unit/ServiceManagerRouter.t.sol | 3 +- test/utils/MockAVSDeployer.sol | 3 +- 12 files changed, 230 insertions(+), 50 deletions(-) diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 7b906a70..fbcb154a 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -298,36 +298,117 @@ contract RegistryCoordinator is // Enable operator sets mode isOperatorSetAVS = true; } + enum RegistrationType { + NORMAL, + CHURN + } + + error InvalidRegistrationType(); function registerOperator( address operator, uint32[] memory operatorSetIds, - bytes memory data + bytes calldata data ) external override onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { require(isUsingOperatorSets(), OperatorSetsNotEnabled()); for (uint256 i = 0; i < operatorSetIds.length; i++) { require(!isM2Quorum[uint8(operatorSetIds[i])], OperatorSetsNotSupported()); } _checkAllocationManager(); - - // Decode registration data from bytes - (string memory socket, IBLSApkRegistry.PubkeyRegistrationParams memory params) = - abi.decode(data, (string, IBLSApkRegistry.PubkeyRegistrationParams)); - - // Get operator ID from BLS registry - bytes32 operatorId = _getOrCreateOperatorId(operator, params); bytes memory quorumNumbers = new bytes(operatorSetIds.length); for (uint256 i = 0; i < operatorSetIds.length; i++) { quorumNumbers[i] = bytes1(uint8(operatorSetIds[i])); } - // Register operator with decoded parameters - _registerOperatorToOperatorSet({ - operator: operator, - operatorId: operatorId, - quorumNumbers: quorumNumbers, - socket: socket + // Handle churn or normal registration based on first byte in `data` + RegistrationType registrationType = RegistrationType(uint8(bytes1(data[0:1]))); + if (registrationType == RegistrationType.NORMAL) { + (, string memory socket, IBLSApkRegistry.PubkeyRegistrationParams memory params) = abi.decode(data, (RegistrationType, string, IBLSApkRegistry.PubkeyRegistrationParams)); + bytes32 operatorId = _getOrCreateOperatorId(operator, params); + _registerOperatorToOperatorSet(operator, operatorId, quorumNumbers, socket); + } else if (registrationType == RegistrationType.CHURN) { + // Decode registration data from bytes + ( + , + string memory socket, + IBLSApkRegistry.PubkeyRegistrationParams memory params, + OperatorKickParam[] memory operatorKickParams, + SignatureWithSaltAndExpiry memory churnApproverSignature + ) = abi.decode( + data, + ( + RegistrationType, + string, + IBLSApkRegistry.PubkeyRegistrationParams, + OperatorKickParam[], + SignatureWithSaltAndExpiry + ) + ); + + _registerOperatorWithChurn(operator, quorumNumbers, socket, params, operatorKickParams, churnApproverSignature); + } else { + revert InvalidRegistrationType(); + } + } + + function _registerOperatorWithChurn( + address operator, + bytes memory quorumNumbers, + string memory socket, + IBLSApkRegistry.PubkeyRegistrationParams memory params, + OperatorKickParam[] memory operatorKickParams, + SignatureWithSaltAndExpiry memory churnApproverSignature + ) internal virtual { + require(operatorKickParams.length == quorumNumbers.length, InputLengthMismatch()); + + /** + * If the operator has NEVER registered a pubkey before, use `params` to register + * their pubkey in blsApkRegistry + * + * If the operator HAS registered a pubkey, `params` is ignored and the pubkey hash + * (operatorId) is fetched instead + */ + bytes32 operatorId = _getOrCreateOperatorId(operator, params); + + // Verify the churn approver's signature for the registering operator and kick params + _verifyChurnApproverSignature({ + registeringOperator: operator, + registeringOperatorId: operatorId, + operatorKickParams: operatorKickParams, + churnApproverSignature: churnApproverSignature }); + + // Register the operator in each of the registry contracts and update the operator's + // quorum bitmap and registration status + RegisterResults memory results = _registerOperatorToOperatorSet(operator, operatorId, quorumNumbers, socket); + + // Check that each quorum's operator count is below the configured maximum. If the max + // is exceeded, use `operatorKickParams` to deregister an existing operator to make space + for (uint256 i = 0; i < quorumNumbers.length; i++) { + OperatorSetParam memory operatorSetParams = _quorumParams[uint8(quorumNumbers[i])]; + + /** + * If the new operator count for any quorum exceeds the maximum, validate + * that churn can be performed, then deregister the specified operator + */ + if (results.numOperatorsPerQuorum[i] > operatorSetParams.maxOperatorCount) { + _validateChurn({ + quorumNumber: uint8(quorumNumbers[i]), + totalQuorumStake: results.totalStakes[i], + newOperator: operator, + newOperatorStake: results.operatorStakes[i], + kickParams: operatorKickParams[i], + setParams: operatorSetParams + }); + + bytes memory singleQuorumNumber = new bytes(1); + singleQuorumNumber[0] = quorumNumbers[i]; + _deregisterOperator(operatorKickParams[i].operator, singleQuorumNumber); + if (isUsingOperatorSets()) { + _handleOperatorSetDeregistration(operatorKickParams[i].operator, singleQuorumNumber); + } + } + } } function deregisterOperator( @@ -471,10 +552,42 @@ contract RegistryCoordinator is operatorInfo.status == OperatorStatus.REGISTERED && !quorumsToRemove.isEmpty() && quorumsToRemove.isSubsetOf(currentBitmap) ) { + // If using operator sets, check for non-M2 quorums + if (isUsingOperatorSets()) { + _handleOperatorSetDeregistration(operator, quorumNumbers); + } + _deregisterOperator({operator: operator, quorumNumbers: quorumNumbers}); } } + /** + * @notice Helper function to handle operator set deregistration for non-M2 quorums + * @param operator The operator to deregister + * @param quorumNumbers The quorum numbers to check + */ + function _handleOperatorSetDeregistration(address operator, bytes memory quorumNumbers) internal { + uint32[] memory nonM2OperatorSetIds = new uint32[](quorumNumbers.length); + uint256 numNonM2Quorums; + + // Check each quorum's stake type + for (uint256 i = 0; i < quorumNumbers.length; i++) { + uint8 quorumNumber = uint8(quorumNumbers[i]); + if (isM2Quorum[quorumNumber]) { + nonM2OperatorSetIds[numNonM2Quorums++] = quorumNumber; + } + } + + // If any non-M2 quorums found, deregister from AVS + if (numNonM2Quorums > 0) { + // Resize array to exact size needed + assembly { + mstore(nonM2OperatorSetIds, numNonM2Quorums) + } + serviceManager.deregisterOperatorFromOperatorSets(operator, nonM2OperatorSetIds); + } + } + /** * * EXTERNAL FUNCTIONS - OWNER @@ -558,10 +671,8 @@ contract RegistryCoordinator is * seconds afer ejection before registering for any quorum * @param _ejectionCooldown the new ejection cooldown in seconds * @dev only callable by the owner - */ - function setEjectionCooldown( - uint256 _ejectionCooldown - ) external onlyOwner { + */ + function setEjectionCooldown(uint256 _ejectionCooldown) external onlyOwner { ejectionCooldown = _ejectionCooldown; } diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index a7be2742..4c5866c4 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -7,6 +7,9 @@ import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSD import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import {IAllocationManager, IAllocationManagerTypes} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IPermissionController} from "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; import {IPermissionController} from "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; @@ -46,14 +49,16 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { IRewardsCoordinator __rewardsCoordinator, IRegistryCoordinator __registryCoordinator, IStakeRegistry __stakeRegistry, - IPermissionController __permissionController + IPermissionController __permissionController, + IAllocationManager __allocationManager ) ServiceManagerBaseStorage( __avsDirectory, __rewardsCoordinator, __registryCoordinator, __stakeRegistry, - __permissionController + __permissionController, + __allocationManager ) { _disableInitializers(); @@ -68,10 +73,11 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { } /// @inheritdoc IServiceManager - function addPendingAdmin( - address admin - ) external onlyOwner { - _permissionController.addPendingAdmin({account: address(this), admin: admin}); + function addPendingAdmin(address admin) external onlyOwner { + _permissionController.addPendingAdmin({ + account: address(this), + admin: admin + }); } /// @inheritdoc IServiceManager @@ -175,6 +181,15 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _avsDirectory.deregisterOperatorFromAVS(operator); } + function deregisterOperatorFromOperatorSets(address operator, uint32[] memory operatorSetIds) public virtual onlyRegistryCoordinator { + IAllocationManager.DeregisterParams memory params = IAllocationManagerTypes.DeregisterParams({ + operator: operator, + avs: address(this), + operatorSetIds: operatorSetIds + }); + _allocationManager.deregisterFromOperatorSets(params); + } + /** * @notice Sets the rewards initiator address * @param newRewardsInitiator The new rewards initiator address diff --git a/src/ServiceManagerBaseStorage.sol b/src/ServiceManagerBaseStorage.sol index a94212ef..ca548ea2 100644 --- a/src/ServiceManagerBaseStorage.sol +++ b/src/ServiceManagerBaseStorage.sol @@ -8,12 +8,10 @@ import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; -import {IRewardsCoordinator} from - "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; -import {IAllocationManager} from - "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IPermissionController} from - "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; +import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IPermissionController} from "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; /** * @title Storage variables for the `ServiceManagerBase` contract. @@ -27,6 +25,7 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab * */ IAVSDirectory internal immutable _avsDirectory; + IAllocationManager internal immutable _allocationManager; IRewardsCoordinator internal immutable _rewardsCoordinator; IRegistryCoordinator internal immutable _registryCoordinator; IStakeRegistry internal immutable _stakeRegistry; @@ -59,13 +58,15 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab IRewardsCoordinator __rewardsCoordinator, IRegistryCoordinator __registryCoordinator, IStakeRegistry __stakeRegistry, - IPermissionController __permissionController + IPermissionController __permissionController, + IAllocationManager __allocationManager ) { _avsDirectory = __avsDirectory; _rewardsCoordinator = __rewardsCoordinator; _registryCoordinator = __registryCoordinator; _stakeRegistry = __stakeRegistry; _permissionController = __permissionController; + _allocationManager = __allocationManager; } // storage gap for upgradeability diff --git a/src/interfaces/IServiceManager.sol b/src/interfaces/IServiceManager.sol index 28d9c2db..6d3cbaa8 100644 --- a/src/interfaces/IServiceManager.sol +++ b/src/interfaces/IServiceManager.sol @@ -101,5 +101,17 @@ interface IServiceManager is IServiceManagerUI, IServiceManagerErrors { * @param selector The function selector to remove the appointee for * @dev Only callable by the owner of the contract */ - function removeAppointee(address appointee, address target, bytes4 selector) external; + function removeAppointee( + address appointee, + address target, + bytes4 selector + ) external; + + /** + * @notice Deregisters an operator from specified operator sets + * @param operator The address of the operator to deregister + * @param operatorSetIds The IDs of the operator sets to deregister from + * @dev Only callable by the RegistryCoordinator + */ + function deregisterOperatorFromOperatorSets(address operator, uint32[] memory operatorSetIds) external; } diff --git a/test/integration/CoreRegistration.t.sol b/test/integration/CoreRegistration.t.sol index 6599af9c..d3bffe8d 100644 --- a/test/integration/CoreRegistration.t.sol +++ b/test/integration/CoreRegistration.t.sol @@ -92,7 +92,8 @@ contract Test_CoreRegistration is MockAVSDeployer { rewardsCoordinatorMock, registryCoordinator, stakeRegistry, - permissionController + permissionController, + allocationManager ); registryCoordinatorImplementation = new RegistryCoordinatorHarness( diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index 5d5ffadd..f1899fe7 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -355,7 +355,8 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { rewardsCoordinator, IRegistryCoordinator(registryCoordinator), stakeRegistry, - permissionController + permissionController, + allocationManager ); proxyAdmin.upgrade( diff --git a/test/mocks/ECDSAServiceManagerMock.sol b/test/mocks/ECDSAServiceManagerMock.sol index 488e5eef..d77fc961 100644 --- a/test/mocks/ECDSAServiceManagerMock.sol +++ b/test/mocks/ECDSAServiceManagerMock.sol @@ -37,6 +37,8 @@ contract ECDSAServiceManagerMock is ECDSAServiceManagerBase { address pendingAdmin ) external {} + function deregisterOperatorFromOperatorSets(address operator, uint32[] memory operatorSetIds) external {} + function removeAdmin( address admin ) external {} diff --git a/test/mocks/ServiceManagerMock.sol b/test/mocks/ServiceManagerMock.sol index 423c08ec..68fbdf4c 100644 --- a/test/mocks/ServiceManagerMock.sol +++ b/test/mocks/ServiceManagerMock.sol @@ -9,14 +9,16 @@ contract ServiceManagerMock is ServiceManagerBase { IRewardsCoordinator _rewardsCoordinator, IRegistryCoordinator _registryCoordinator, IStakeRegistry _stakeRegistry, - IPermissionController _permissionController + IPermissionController _permissionController, + IAllocationManager _allocationManager ) ServiceManagerBase( _avsDirectory, _rewardsCoordinator, _registryCoordinator, _stakeRegistry, - _permissionController + _permissionController, + _allocationManager ) {} diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index 3b62098d..4afc62bf 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -2556,7 +2556,11 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT // Create total delegated stake quorum cheats.prank(registryCoordinatorOwner); - registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, 0, strategyParams); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams, + 0, + strategyParams + ); uint32[] memory operatorSetIds = new uint32[](1); operatorSetIds[0] = 0; @@ -2570,7 +2574,12 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT // pubkeySignature: defaultPubKeySignature // }); - bytes memory data = abi.encode(socket, params); + // Encode with RegistrationType.NORMAL + bytes memory data = abi.encode( + RegistryCoordinator.RegistrationType.NORMAL, + socket, + params + ); cheats.prank(address(registryCoordinator.allocationManager())); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); @@ -2618,15 +2627,19 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT IRegistryCoordinator.OperatorKickParam({operator: address(0x1), quorumNumber: 0}); ISignatureUtils.SignatureWithSaltAndExpiry memory churnApproverSignature; - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; - bytes memory registerParams = abi.encode( - socket, params, operatorKickParams, churnApproverSignature, operatorSignature + // Encode with RegistrationType.CHURN + bytes memory data = abi.encode( + RegistryCoordinator.RegistrationType.CHURN, + socket, + params, + operatorKickParams, + churnApproverSignature ); // Prank as allocation manager and call register hook cheats.prank(address(registryCoordinator.allocationManager())); - registryCoordinator.registerOperator(defaultOperator, operatorSetIds, registerParams); + registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); } function test_updateStakesForQuorum() public { @@ -2693,12 +2706,17 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT // pubkeySignature: defaultPubKeySignature // }); - bytes memory data = abi.encode(socket, params); + // Encode with RegistrationType.NORMAL + bytes memory data = abi.encode( + RegistryCoordinator.RegistrationType.NORMAL, + socket, + params + ); cheats.startPrank(address(registryCoordinator.allocationManager())); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); - registryCoordinator.deregisterOperator(defaultOperator, operatorSetIds); + // registryCoordinator.deregisterOperator(defaultOperator, operatorSetIds); cheats.stopPrank(); } @@ -2725,7 +2743,11 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT // Create total delegated stake quorum cheats.prank(registryCoordinatorOwner); - registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, 0, strategyParams); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams, + 0, + strategyParams + ); uint32[] memory operatorSetIds = new uint32[](1); operatorSetIds[0] = 0; @@ -2739,7 +2761,12 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT // pubkeySignature: defaultPubKeySignature // }); - bytes memory data = abi.encode(socket, params); + // Encode with RegistrationType.NORMAL + bytes memory data = abi.encode( + RegistryCoordinator.RegistrationType.NORMAL, + socket, + params + ); vm.expectRevert(); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); @@ -2782,7 +2809,12 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT // pubkeySignature: defaultPubKeySignature // }); - bytes memory data = abi.encode(socket, params); + // Encode with RegistrationType.NORMAL + bytes memory data = abi.encode( + RegistryCoordinator.RegistrationType.NORMAL, + socket, + params + ); cheats.prank(address(registryCoordinator.allocationManager())); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); diff --git a/test/unit/ServiceManagerBase.t.sol b/test/unit/ServiceManagerBase.t.sol index 74f9e848..d293f088 100644 --- a/test/unit/ServiceManagerBase.t.sol +++ b/test/unit/ServiceManagerBase.t.sol @@ -95,7 +95,8 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve rewardsCoordinator, registryCoordinatorImplementation, stakeRegistryImplementation, - permissionControllerMock + permissionControllerMock, + allocationManagerMock ); serviceManager = ServiceManagerMock( diff --git a/test/unit/ServiceManagerRouter.t.sol b/test/unit/ServiceManagerRouter.t.sol index cb44d6f6..3e83f1c4 100644 --- a/test/unit/ServiceManagerRouter.t.sol +++ b/test/unit/ServiceManagerRouter.t.sol @@ -20,7 +20,8 @@ contract ServiceManagerRouter_UnitTests is MockAVSDeployer { rewardsCoordinatorImplementation, registryCoordinatorImplementation, stakeRegistryImplementation, - permissionControllerMock + permissionControllerMock, + allocationManagerMock ); _registerOperatorWithCoordinator(defaultOperator, MAX_QUORUM_BITMAP, defaultPubKey); diff --git a/test/utils/MockAVSDeployer.sol b/test/utils/MockAVSDeployer.sol index 15e6d425..a593e23e 100644 --- a/test/utils/MockAVSDeployer.sol +++ b/test/utils/MockAVSDeployer.sol @@ -237,7 +237,8 @@ contract MockAVSDeployer is Test { IRewardsCoordinator(address(rewardsCoordinatorMock)), registryCoordinator, stakeRegistry, - permissionControllerMock + permissionControllerMock, + allocationManagerMock ); proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(serviceManager))), From 57f70bac4b7809d694fd78a4bd1407bffa9b7811 Mon Sep 17 00:00:00 2001 From: Michael Sun <35479365+8sunyuan@users.noreply.github.com> Date: Fri, 24 Jan 2025 12:37:53 -0500 Subject: [PATCH 46/52] refactor: slashing registry coordinator (#361) * refactor: slashing registry coordinator refactor: registry coordinator refactor: remove sm calls fix: tests wip * fix: integration tests * refactor: internal functions * fix: remove unused block * fix: comment out test for now * build: fmt check run only on src contracts * fix: call SM only based on m2 quorums (#369) * feat: update enableOperatorSets flow (#367) * feat: update enableOperatorSets flow * fix: dereg op check * chore: renamed m2 quorums * fix: msg.sender -> operator * chore: forge fmt * fix: tests --------- Co-authored-by: Yash Patil <40046473+ypatil12@users.noreply.github.com> --- .github/workflows/forge-fmt.yml | 2 +- docs/storage-report/BLSApkRegistry.md | 21 - docs/storage-report/BLSApkRegistryStorage.md | 21 - docs/storage-report/BLSSignatureChecker.md | 9 - docs/storage-report/EjectionManager.md | 21 - docs/storage-report/IndexRegistry.md | 17 - docs/storage-report/IndexRegistryStorage.md | 17 - docs/storage-report/InstantSlasher.md | 15 - docs/storage-report/OperatorStateRetriever.md | 6 - docs/storage-report/RegistryCoordinator.md | 49 - .../RegistryCoordinatorStorage.md | 2 +- docs/storage-report/ServiceManagerBase.md | 27 - .../ServiceManagerBaseStorage.md | 27 - docs/storage-report/SlasherBase.md | 15 - docs/storage-report/SlasherStorage.md | 11 - .../SlashingRegistryCoordinator.md | 0 .../SlashingRegistryCoordinatorStorage.md | 0 docs/storage-report/StakeRegistry.md | 21 - docs/storage-report/StakeRegistryStorage.md | 21 - docs/storage-report/VetoableSlasher.md | 19 - src/AVSRegistrar.sol | 21 - src/BLSApkRegistry.sol | 6 +- src/BLSApkRegistryStorage.sol | 6 +- src/BLSSignatureChecker.sol | 6 +- src/EjectionManager.sol | 6 +- src/IndexRegistry.sol | 6 +- src/IndexRegistryStorage.sol | 6 +- src/OperatorStateRetriever.sol | 14 +- src/RegistryCoordinator.sol | 1203 +------- src/ServiceManagerBase.sol | 27 +- src/ServiceManagerBaseStorage.sol | 18 +- src/SlashingRegistryCoordinator.sol | 1122 ++++++++ ...=> SlashingRegistryCoordinatorStorage.sol} | 29 +- src/StakeRegistry.sol | 51 +- src/StakeRegistryStorage.sol | 14 +- src/interfaces/IBLSSignatureChecker.sol | 4 +- src/interfaces/IRegistryCoordinator.sol | 249 +- src/interfaces/IServiceManager.sol | 11 +- .../ISlashingRegistryCoordinator.sol | 239 ++ src/interfaces/IStakeRegistry.sol | 4 +- src/libraries/QuorumBitmapHistoryLib.sol | 21 +- src/slashers/InstantSlasher.sol | 6 +- src/slashers/VetoableSlasher.sol | 6 +- src/slashers/base/SlasherBase.sol | 12 +- src/slashers/base/SlasherStorage.sol | 14 +- test/ffi/BLSPubKeyCompendiumFFI.t.sol | 3 +- test/harnesses/BLSApkRegistryHarness.sol | 4 +- .../RegistryCoordinatorHarness.t.sol | 10 +- test/harnesses/StakeRegistryHarness.sol | 16 +- test/integration/IntegrationBase.t.sol | 26 +- test/integration/IntegrationConfig.t.sol | 17 +- test/integration/IntegrationDeployer.t.sol | 85 +- test/integration/User.t.sol | 22 +- test/mocks/AVSDirectoryMock.sol | 2 +- test/mocks/AVSRegistrarMock.sol | 5 +- test/mocks/RegistryCoordinatorMock.sol | 36 +- test/mocks/ServiceManagerMock.sol | 4 +- test/unit/EjectionManagerUnit.t.sol | 123 +- test/unit/OperatorStateRetrieverUnit.t.sol | 9 +- test/unit/RegistryCoordinatorUnit.t.sol | 691 ++--- .../SlashingRegistryCoordinatorUnit.t.sol | 2421 +++++++++++++++++ test/unit/StakeRegistryUnit.t.sol | 22 +- test/utils/MockAVSDeployer.sol | 68 +- 63 files changed, 4526 insertions(+), 2460 deletions(-) create mode 100644 docs/storage-report/SlashingRegistryCoordinator.md create mode 100644 docs/storage-report/SlashingRegistryCoordinatorStorage.md delete mode 100644 src/AVSRegistrar.sol create mode 100644 src/SlashingRegistryCoordinator.sol rename src/{RegistryCoordinatorStorage.sol => SlashingRegistryCoordinatorStorage.sol} (81%) create mode 100644 src/interfaces/ISlashingRegistryCoordinator.sol create mode 100644 test/unit/SlashingRegistryCoordinatorUnit.t.sol diff --git a/.github/workflows/forge-fmt.yml b/.github/workflows/forge-fmt.yml index f1fa3cc6..c70bfe53 100644 --- a/.github/workflows/forge-fmt.yml +++ b/.github/workflows/forge-fmt.yml @@ -26,5 +26,5 @@ jobs: version: nightly - name: Run forge fmt run: | - forge fmt --check + forge fmt --check src id: fmt \ No newline at end of file diff --git a/docs/storage-report/BLSApkRegistry.md b/docs/storage-report/BLSApkRegistry.md index 69239c7c..e69de29b 100644 --- a/docs/storage-report/BLSApkRegistry.md +++ b/docs/storage-report/BLSApkRegistry.md @@ -1,21 +0,0 @@ - -╭----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+=============================================================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/BLSApkRegistry.sol:BLSApkRegistry | -|----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/BLSApkRegistry.sol:BLSApkRegistry | -|----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------| -| operatorToPubkeyHash | mapping(address => bytes32) | 1 | 0 | 32 | src/BLSApkRegistry.sol:BLSApkRegistry | -|----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------| -| pubkeyHashToOperator | mapping(bytes32 => address) | 2 | 0 | 32 | src/BLSApkRegistry.sol:BLSApkRegistry | -|----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------| -| operatorToPubkey | mapping(address => struct BN254.G1Point) | 3 | 0 | 32 | src/BLSApkRegistry.sol:BLSApkRegistry | -|----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------| -| apkHistory | mapping(uint8 => struct IBLSApkRegistry.ApkUpdate[]) | 4 | 0 | 32 | src/BLSApkRegistry.sol:BLSApkRegistry | -|----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------| -| currentApk | mapping(uint8 => struct BN254.G1Point) | 5 | 0 | 32 | src/BLSApkRegistry.sol:BLSApkRegistry | -|----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------| -| __GAP | uint256[45] | 6 | 0 | 1440 | src/BLSApkRegistry.sol:BLSApkRegistry | -╰----------------------+------------------------------------------------------+------+--------+-------+---------------------------------------╯ - diff --git a/docs/storage-report/BLSApkRegistryStorage.md b/docs/storage-report/BLSApkRegistryStorage.md index 3b5b9e61..e69de29b 100644 --- a/docs/storage-report/BLSApkRegistryStorage.md +++ b/docs/storage-report/BLSApkRegistryStorage.md @@ -1,21 +0,0 @@ - -╭----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+===========================================================================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | -|----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | -|----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------| -| operatorToPubkeyHash | mapping(address => bytes32) | 1 | 0 | 32 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | -|----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------| -| pubkeyHashToOperator | mapping(bytes32 => address) | 2 | 0 | 32 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | -|----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------| -| operatorToPubkey | mapping(address => struct BN254.G1Point) | 3 | 0 | 32 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | -|----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------| -| apkHistory | mapping(uint8 => struct IBLSApkRegistry.ApkUpdate[]) | 4 | 0 | 32 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | -|----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------| -| currentApk | mapping(uint8 => struct BN254.G1Point) | 5 | 0 | 32 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | -|----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------| -| __GAP | uint256[45] | 6 | 0 | 1440 | src/BLSApkRegistryStorage.sol:BLSApkRegistryStorage | -╰----------------------+------------------------------------------------------+------+--------+-------+-----------------------------------------------------╯ - diff --git a/docs/storage-report/BLSSignatureChecker.md b/docs/storage-report/BLSSignatureChecker.md index 19b3473b..e69de29b 100644 --- a/docs/storage-report/BLSSignatureChecker.md +++ b/docs/storage-report/BLSSignatureChecker.md @@ -1,9 +0,0 @@ - -╭----------------------+-------------+------+--------+-------+-------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+==============================================================================================================+ -| staleStakesForbidden | bool | 0 | 0 | 1 | src/BLSSignatureChecker.sol:BLSSignatureChecker | -|----------------------+-------------+------+--------+-------+-------------------------------------------------| -| __GAP | uint256[49] | 1 | 0 | 1568 | src/BLSSignatureChecker.sol:BLSSignatureChecker | -╰----------------------+-------------+------+--------+-------+-------------------------------------------------╯ - diff --git a/docs/storage-report/EjectionManager.md b/docs/storage-report/EjectionManager.md index 55e2a2df..e69de29b 100644 --- a/docs/storage-report/EjectionManager.md +++ b/docs/storage-report/EjectionManager.md @@ -1,21 +0,0 @@ - -╭-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+==========================================================================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/EjectionManager.sol:EjectionManager | -|-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/EjectionManager.sol:EjectionManager | -|-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------| -| __gap | uint256[50] | 1 | 0 | 1600 | src/EjectionManager.sol:EjectionManager | -|-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------| -| _owner | address | 51 | 0 | 20 | src/EjectionManager.sol:EjectionManager | -|-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------| -| __gap | uint256[49] | 52 | 0 | 1568 | src/EjectionManager.sol:EjectionManager | -|-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------| -| isEjector | mapping(address => bool) | 101 | 0 | 32 | src/EjectionManager.sol:EjectionManager | -|-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------| -| stakeEjectedForQuorum | mapping(uint8 => struct IEjectionManager.StakeEjection[]) | 102 | 0 | 32 | src/EjectionManager.sol:EjectionManager | -|-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------| -| quorumEjectionParams | mapping(uint8 => struct IEjectionManager.QuorumEjectionParams) | 103 | 0 | 32 | src/EjectionManager.sol:EjectionManager | -╰-----------------------+----------------------------------------------------------------+------+--------+-------+-----------------------------------------╯ - diff --git a/docs/storage-report/IndexRegistry.md b/docs/storage-report/IndexRegistry.md index 3415bdcd..e69de29b 100644 --- a/docs/storage-report/IndexRegistry.md +++ b/docs/storage-report/IndexRegistry.md @@ -1,17 +0,0 @@ - -╭-----------------------+-----------------------------------------------------------------------------+------+--------+-------+-------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+===================================================================================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/IndexRegistry.sol:IndexRegistry | -|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+-------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/IndexRegistry.sol:IndexRegistry | -|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+-------------------------------------| -| currentOperatorIndex | mapping(uint8 => mapping(bytes32 => uint32)) | 1 | 0 | 32 | src/IndexRegistry.sol:IndexRegistry | -|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+-------------------------------------| -| _operatorIndexHistory | mapping(uint8 => mapping(uint32 => struct IIndexRegistry.OperatorUpdate[])) | 2 | 0 | 32 | src/IndexRegistry.sol:IndexRegistry | -|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+-------------------------------------| -| _operatorCountHistory | mapping(uint8 => struct IIndexRegistry.QuorumUpdate[]) | 3 | 0 | 32 | src/IndexRegistry.sol:IndexRegistry | -|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+-------------------------------------| -| __GAP | uint256[47] | 4 | 0 | 1504 | src/IndexRegistry.sol:IndexRegistry | -╰-----------------------+-----------------------------------------------------------------------------+------+--------+-------+-------------------------------------╯ - diff --git a/docs/storage-report/IndexRegistryStorage.md b/docs/storage-report/IndexRegistryStorage.md index 9581f514..e69de29b 100644 --- a/docs/storage-report/IndexRegistryStorage.md +++ b/docs/storage-report/IndexRegistryStorage.md @@ -1,17 +0,0 @@ - -╭-----------------------+-----------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+=================================================================================================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/IndexRegistryStorage.sol:IndexRegistryStorage | -|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/IndexRegistryStorage.sol:IndexRegistryStorage | -|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| -| currentOperatorIndex | mapping(uint8 => mapping(bytes32 => uint32)) | 1 | 0 | 32 | src/IndexRegistryStorage.sol:IndexRegistryStorage | -|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| -| _operatorIndexHistory | mapping(uint8 => mapping(uint32 => struct IIndexRegistry.OperatorUpdate[])) | 2 | 0 | 32 | src/IndexRegistryStorage.sol:IndexRegistryStorage | -|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| -| _operatorCountHistory | mapping(uint8 => struct IIndexRegistry.QuorumUpdate[]) | 3 | 0 | 32 | src/IndexRegistryStorage.sol:IndexRegistryStorage | -|-----------------------+-----------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| -| __GAP | uint256[47] | 4 | 0 | 1504 | src/IndexRegistryStorage.sol:IndexRegistryStorage | -╰-----------------------+-----------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------╯ - diff --git a/docs/storage-report/InstantSlasher.md b/docs/storage-report/InstantSlasher.md index 7fb6cd76..e69de29b 100644 --- a/docs/storage-report/InstantSlasher.md +++ b/docs/storage-report/InstantSlasher.md @@ -1,15 +0,0 @@ - -╭---------------+-------------+------+--------+-------+------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+======================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/slashers/InstantSlasher.sol:InstantSlasher | -|---------------+-------------+------+--------+-------+------------------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/slashers/InstantSlasher.sol:InstantSlasher | -|---------------+-------------+------+--------+-------+------------------------------------------------| -| slasher | address | 0 | 2 | 20 | src/slashers/InstantSlasher.sol:InstantSlasher | -|---------------+-------------+------+--------+-------+------------------------------------------------| -| nextRequestId | uint256 | 1 | 0 | 32 | src/slashers/InstantSlasher.sol:InstantSlasher | -|---------------+-------------+------+--------+-------+------------------------------------------------| -| __gap | uint256[48] | 2 | 0 | 1536 | src/slashers/InstantSlasher.sol:InstantSlasher | -╰---------------+-------------+------+--------+-------+------------------------------------------------╯ - diff --git a/docs/storage-report/OperatorStateRetriever.md b/docs/storage-report/OperatorStateRetriever.md index 1ec5dc07..e69de29b 100644 --- a/docs/storage-report/OperatorStateRetriever.md +++ b/docs/storage-report/OperatorStateRetriever.md @@ -1,6 +0,0 @@ - -╭------+------+------+--------+-------+----------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+================================================+ -╰------+------+------+--------+-------+----------╯ - diff --git a/docs/storage-report/RegistryCoordinator.md b/docs/storage-report/RegistryCoordinator.md index 1adff5f4..e69de29b 100644 --- a/docs/storage-report/RegistryCoordinator.md +++ b/docs/storage-report/RegistryCoordinator.md @@ -1,49 +0,0 @@ - -╭-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+==============================================================================================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| __deprecated_pauserRegistry | contract IPauserRegistry | 0 | 2 | 20 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| _paused | uint256 | 1 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| __gap | uint256[48] | 2 | 0 | 1536 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| __gap | uint256[50] | 50 | 0 | 1600 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| _owner | address | 100 | 0 | 20 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| __gap | uint256[49] | 101 | 0 | 1568 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| quorumCount | uint8 | 150 | 0 | 1 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| _quorumParams | mapping(uint8 => struct IRegistryCoordinator.OperatorSetParam) | 151 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| _operatorBitmapHistory | mapping(bytes32 => struct IRegistryCoordinator.QuorumBitmapUpdate[]) | 152 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| _operatorInfo | mapping(address => struct IRegistryCoordinator.OperatorInfo) | 153 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| isChurnApproverSaltUsed | mapping(bytes32 => bool) | 154 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| quorumUpdateBlockNumber | mapping(uint8 => uint256) | 155 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| registries | address[] | 156 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| churnApprover | address | 157 | 0 | 20 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| ejector | address | 158 | 0 | 20 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| lastEjectionTimestamp | mapping(address => uint256) | 159 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| ejectionCooldown | uint256 | 160 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| isOperatorSetAVS | bool | 161 | 0 | 1 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| isM2Quorum | mapping(uint8 => bool) | 162 | 0 | 32 | src/RegistryCoordinator.sol:RegistryCoordinator | -|-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------| -| __GAP | uint256[37] | 163 | 0 | 1184 | src/RegistryCoordinator.sol:RegistryCoordinator | -╰-----------------------------+----------------------------------------------------------------------+------+--------+-------+-------------------------------------------------╯ - diff --git a/docs/storage-report/RegistryCoordinatorStorage.md b/docs/storage-report/RegistryCoordinatorStorage.md index 1e9fc25d..47e30da8 100644 --- a/docs/storage-report/RegistryCoordinatorStorage.md +++ b/docs/storage-report/RegistryCoordinatorStorage.md @@ -24,7 +24,7 @@ |-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| | ejectionCooldown | uint256 | 10 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | |-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| -| isOperatorSetAVS | bool | 11 | 0 | 1 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +| operatorSetsEnabled | bool | 11 | 0 | 1 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | |-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| | isM2Quorum | mapping(uint8 => bool) | 12 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | |-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| diff --git a/docs/storage-report/ServiceManagerBase.md b/docs/storage-report/ServiceManagerBase.md index 61ef533a..e69de29b 100644 --- a/docs/storage-report/ServiceManagerBase.md +++ b/docs/storage-report/ServiceManagerBase.md @@ -1,27 +0,0 @@ - -╭--------------------------+-------------+------+--------+-------+-----------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+================================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/ServiceManagerBase.sol:ServiceManagerBase | -|--------------------------+-------------+------+--------+-------+-----------------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/ServiceManagerBase.sol:ServiceManagerBase | -|--------------------------+-------------+------+--------+-------+-----------------------------------------------| -| __gap | uint256[50] | 1 | 0 | 1600 | src/ServiceManagerBase.sol:ServiceManagerBase | -|--------------------------+-------------+------+--------+-------+-----------------------------------------------| -| _owner | address | 51 | 0 | 20 | src/ServiceManagerBase.sol:ServiceManagerBase | -|--------------------------+-------------+------+--------+-------+-----------------------------------------------| -| __gap | uint256[49] | 52 | 0 | 1568 | src/ServiceManagerBase.sol:ServiceManagerBase | -|--------------------------+-------------+------+--------+-------+-----------------------------------------------| -| rewardsInitiator | address | 101 | 0 | 20 | src/ServiceManagerBase.sol:ServiceManagerBase | -|--------------------------+-------------+------+--------+-------+-----------------------------------------------| -| slasher | address | 102 | 0 | 20 | src/ServiceManagerBase.sol:ServiceManagerBase | -|--------------------------+-------------+------+--------+-------+-----------------------------------------------| -| proposedSlasher | address | 103 | 0 | 20 | src/ServiceManagerBase.sol:ServiceManagerBase | -|--------------------------+-------------+------+--------+-------+-----------------------------------------------| -| slasherProposalTimestamp | uint256 | 104 | 0 | 32 | src/ServiceManagerBase.sol:ServiceManagerBase | -|--------------------------+-------------+------+--------+-------+-----------------------------------------------| -| migrationFinalized | bool | 105 | 0 | 1 | src/ServiceManagerBase.sol:ServiceManagerBase | -|--------------------------+-------------+------+--------+-------+-----------------------------------------------| -| __GAP | uint256[45] | 106 | 0 | 1440 | src/ServiceManagerBase.sol:ServiceManagerBase | -╰--------------------------+-------------+------+--------+-------+-----------------------------------------------╯ - diff --git a/docs/storage-report/ServiceManagerBaseStorage.md b/docs/storage-report/ServiceManagerBaseStorage.md index baa458fa..e69de29b 100644 --- a/docs/storage-report/ServiceManagerBaseStorage.md +++ b/docs/storage-report/ServiceManagerBaseStorage.md @@ -1,27 +0,0 @@ - -╭--------------------------+-------------+------+--------+-------+-------------------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+==============================================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | -|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | -|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| -| __gap | uint256[50] | 1 | 0 | 1600 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | -|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| -| _owner | address | 51 | 0 | 20 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | -|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| -| __gap | uint256[49] | 52 | 0 | 1568 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | -|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| -| rewardsInitiator | address | 101 | 0 | 20 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | -|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| -| slasher | address | 102 | 0 | 20 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | -|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| -| proposedSlasher | address | 103 | 0 | 20 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | -|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| -| slasherProposalTimestamp | uint256 | 104 | 0 | 32 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | -|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| -| migrationFinalized | bool | 105 | 0 | 1 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | -|--------------------------+-------------+------+--------+-------+-------------------------------------------------------------| -| __GAP | uint256[45] | 106 | 0 | 1440 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | -╰--------------------------+-------------+------+--------+-------+-------------------------------------------------------------╯ - diff --git a/docs/storage-report/SlasherBase.md b/docs/storage-report/SlasherBase.md index 2e2c0eb9..e69de29b 100644 --- a/docs/storage-report/SlasherBase.md +++ b/docs/storage-report/SlasherBase.md @@ -1,15 +0,0 @@ - -╭---------------+-------------+------+--------+-------+-----------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+=====================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/slashers/base/SlasherBase.sol:SlasherBase | -|---------------+-------------+------+--------+-------+-----------------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/slashers/base/SlasherBase.sol:SlasherBase | -|---------------+-------------+------+--------+-------+-----------------------------------------------| -| slasher | address | 0 | 2 | 20 | src/slashers/base/SlasherBase.sol:SlasherBase | -|---------------+-------------+------+--------+-------+-----------------------------------------------| -| nextRequestId | uint256 | 1 | 0 | 32 | src/slashers/base/SlasherBase.sol:SlasherBase | -|---------------+-------------+------+--------+-------+-----------------------------------------------| -| __gap | uint256[48] | 2 | 0 | 1536 | src/slashers/base/SlasherBase.sol:SlasherBase | -╰---------------+-------------+------+--------+-------+-----------------------------------------------╯ - diff --git a/docs/storage-report/SlasherStorage.md b/docs/storage-report/SlasherStorage.md index 6c947c7b..e69de29b 100644 --- a/docs/storage-report/SlasherStorage.md +++ b/docs/storage-report/SlasherStorage.md @@ -1,11 +0,0 @@ - -╭---------------+-------------+------+--------+-------+-----------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+===========================================================================================================+ -| slasher | address | 0 | 0 | 20 | src/slashers/base/SlasherStorage.sol:SlasherStorage | -|---------------+-------------+------+--------+-------+-----------------------------------------------------| -| nextRequestId | uint256 | 1 | 0 | 32 | src/slashers/base/SlasherStorage.sol:SlasherStorage | -|---------------+-------------+------+--------+-------+-----------------------------------------------------| -| __gap | uint256[48] | 2 | 0 | 1536 | src/slashers/base/SlasherStorage.sol:SlasherStorage | -╰---------------+-------------+------+--------+-------+-----------------------------------------------------╯ - diff --git a/docs/storage-report/SlashingRegistryCoordinator.md b/docs/storage-report/SlashingRegistryCoordinator.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/storage-report/SlashingRegistryCoordinatorStorage.md b/docs/storage-report/SlashingRegistryCoordinatorStorage.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/storage-report/StakeRegistry.md b/docs/storage-report/StakeRegistry.md index 820aaba6..e69de29b 100644 --- a/docs/storage-report/StakeRegistry.md +++ b/docs/storage-report/StakeRegistry.md @@ -1,21 +0,0 @@ - -╭----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+============================================================================================================================================================================+ -| minimumStakeForQuorum | mapping(uint8 => uint96) | 0 | 0 | 32 | src/StakeRegistry.sol:StakeRegistry | -|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------| -| _totalStakeHistory | mapping(uint8 => struct IStakeRegistry.StakeUpdate[]) | 1 | 0 | 32 | src/StakeRegistry.sol:StakeRegistry | -|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------| -| operatorStakeHistory | mapping(bytes32 => mapping(uint8 => struct IStakeRegistry.StakeUpdate[])) | 2 | 0 | 32 | src/StakeRegistry.sol:StakeRegistry | -|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------| -| strategyParams | mapping(uint8 => struct IStakeRegistry.StrategyParams[]) | 3 | 0 | 32 | src/StakeRegistry.sol:StakeRegistry | -|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------| -| strategiesPerQuorum | mapping(uint8 => contract IStrategy[]) | 4 | 0 | 32 | src/StakeRegistry.sol:StakeRegistry | -|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------| -| stakeTypePerQuorum | mapping(uint8 => enum StakeType) | 5 | 0 | 32 | src/StakeRegistry.sol:StakeRegistry | -|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------| -| slashableStakeLookAheadPerQuorum | mapping(uint8 => uint32) | 6 | 0 | 32 | src/StakeRegistry.sol:StakeRegistry | -|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------| -| __GAP | uint256[43] | 7 | 0 | 1376 | src/StakeRegistry.sol:StakeRegistry | -╰----------------------------------+---------------------------------------------------------------------------+------+--------+-------+-------------------------------------╯ - diff --git a/docs/storage-report/StakeRegistryStorage.md b/docs/storage-report/StakeRegistryStorage.md index 4a545513..e69de29b 100644 --- a/docs/storage-report/StakeRegistryStorage.md +++ b/docs/storage-report/StakeRegistryStorage.md @@ -1,21 +0,0 @@ - -╭----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+==========================================================================================================================================================================================+ -| minimumStakeForQuorum | mapping(uint8 => uint96) | 0 | 0 | 32 | src/StakeRegistryStorage.sol:StakeRegistryStorage | -|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| -| _totalStakeHistory | mapping(uint8 => struct IStakeRegistry.StakeUpdate[]) | 1 | 0 | 32 | src/StakeRegistryStorage.sol:StakeRegistryStorage | -|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| -| operatorStakeHistory | mapping(bytes32 => mapping(uint8 => struct IStakeRegistry.StakeUpdate[])) | 2 | 0 | 32 | src/StakeRegistryStorage.sol:StakeRegistryStorage | -|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| -| strategyParams | mapping(uint8 => struct IStakeRegistry.StrategyParams[]) | 3 | 0 | 32 | src/StakeRegistryStorage.sol:StakeRegistryStorage | -|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| -| strategiesPerQuorum | mapping(uint8 => contract IStrategy[]) | 4 | 0 | 32 | src/StakeRegistryStorage.sol:StakeRegistryStorage | -|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| -| stakeTypePerQuorum | mapping(uint8 => enum StakeType) | 5 | 0 | 32 | src/StakeRegistryStorage.sol:StakeRegistryStorage | -|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| -| slashableStakeLookAheadPerQuorum | mapping(uint8 => uint32) | 6 | 0 | 32 | src/StakeRegistryStorage.sol:StakeRegistryStorage | -|----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------| -| __GAP | uint256[43] | 7 | 0 | 1376 | src/StakeRegistryStorage.sol:StakeRegistryStorage | -╰----------------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------╯ - diff --git a/docs/storage-report/VetoableSlasher.md b/docs/storage-report/VetoableSlasher.md index 4d316b89..e69de29b 100644 --- a/docs/storage-report/VetoableSlasher.md +++ b/docs/storage-report/VetoableSlasher.md @@ -1,19 +0,0 @@ - -╭------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+========================================================================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/slashers/VetoableSlasher.sol:VetoableSlasher | -|------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/slashers/VetoableSlasher.sol:VetoableSlasher | -|------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------| -| slasher | address | 0 | 2 | 20 | src/slashers/VetoableSlasher.sol:VetoableSlasher | -|------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------| -| nextRequestId | uint256 | 1 | 0 | 32 | src/slashers/VetoableSlasher.sol:VetoableSlasher | -|------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------| -| __gap | uint256[48] | 2 | 0 | 1536 | src/slashers/VetoableSlasher.sol:VetoableSlasher | -|------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------| -| vetoCommittee | address | 50 | 0 | 20 | src/slashers/VetoableSlasher.sol:VetoableSlasher | -|------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------| -| slashingRequests | mapping(uint256 => struct ISlasherTypes.SlashingRequest) | 51 | 0 | 32 | src/slashers/VetoableSlasher.sol:VetoableSlasher | -╰------------------+----------------------------------------------------------+------+--------+-------+--------------------------------------------------╯ - diff --git a/src/AVSRegistrar.sol b/src/AVSRegistrar.sol deleted file mode 100644 index 9a81e129..00000000 --- a/src/AVSRegistrar.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.27; - -import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; -import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; -import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; -import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; -import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; - -abstract contract AVSRegistrar is IAVSRegistrar { - function registerOperator( - address operator, - uint32[] calldata operatorSetIds, - bytes calldata data - ) external virtual; - - function deregisterOperator( - address operator, - uint32[] calldata operatorSetIds - ) external virtual; -} diff --git a/src/BLSApkRegistry.sol b/src/BLSApkRegistry.sol index 93972f5c..65d125fb 100644 --- a/src/BLSApkRegistry.sol +++ b/src/BLSApkRegistry.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.27; import {BLSApkRegistryStorage} from "./BLSApkRegistryStorage.sol"; -import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; import {BN254} from "./libraries/BN254.sol"; @@ -18,8 +18,8 @@ contract BLSApkRegistry is BLSApkRegistryStorage { /// @notice Sets the (immutable) `registryCoordinator` address constructor( - IRegistryCoordinator _registryCoordinator - ) BLSApkRegistryStorage(_registryCoordinator) {} + ISlashingRegistryCoordinator _slashingRegistryCoordinator + ) BLSApkRegistryStorage(_slashingRegistryCoordinator) {} /** * diff --git a/src/BLSApkRegistryStorage.sol b/src/BLSApkRegistryStorage.sol index 5007367a..ffbd075d 100644 --- a/src/BLSApkRegistryStorage.sol +++ b/src/BLSApkRegistryStorage.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.27; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; -import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; @@ -31,9 +31,9 @@ abstract contract BLSApkRegistryStorage is Initializable, IBLSApkRegistry { mapping(uint8 => BN254.G1Point) public currentApk; constructor( - IRegistryCoordinator _registryCoordinator + ISlashingRegistryCoordinator _slashingRegistryCoordinator ) { - registryCoordinator = address(_registryCoordinator); + registryCoordinator = address(_slashingRegistryCoordinator); // disable initializers so that the implementation contract cannot be initialized _disableInitializers(); } diff --git a/src/BLSSignatureChecker.sol b/src/BLSSignatureChecker.sol index 2ff55e37..aaaa094e 100644 --- a/src/BLSSignatureChecker.sol +++ b/src/BLSSignatureChecker.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.27; import {IBLSSignatureChecker} from "./interfaces/IBLSSignatureChecker.sol"; -import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry, IDelegationManager} from "./interfaces/IStakeRegistry.sol"; @@ -23,7 +23,7 @@ contract BLSSignatureChecker is IBLSSignatureChecker { // gas cost of multiplying 2 pairings uint256 internal constant PAIRING_EQUALITY_CHECK_GAS = 120_000; - IRegistryCoordinator public immutable registryCoordinator; + ISlashingRegistryCoordinator public immutable registryCoordinator; IStakeRegistry public immutable stakeRegistry; IBLSApkRegistry public immutable blsApkRegistry; IDelegationManager public immutable delegation; @@ -36,7 +36,7 @@ contract BLSSignatureChecker is IBLSSignatureChecker { } constructor( - IRegistryCoordinator _registryCoordinator + ISlashingRegistryCoordinator _registryCoordinator ) { registryCoordinator = _registryCoordinator; stakeRegistry = _registryCoordinator.stakeRegistry(); diff --git a/src/EjectionManager.sol b/src/EjectionManager.sol index f7d3d55d..578a2222 100644 --- a/src/EjectionManager.sol +++ b/src/EjectionManager.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.27; import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import {IEjectionManager} from "./interfaces/IEjectionManager.sol"; -import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; /** @@ -18,7 +18,7 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { uint8 internal constant MAX_QUORUM_COUNT = 192; /// @notice the RegistryCoordinator contract that is the entry point for ejection - IRegistryCoordinator public immutable registryCoordinator; + ISlashingRegistryCoordinator public immutable registryCoordinator; /// @notice the StakeRegistry contract that keeps track of quorum stake IStakeRegistry public immutable stakeRegistry; @@ -30,7 +30,7 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { /// @notice Ratelimit parameters for each quorum mapping(uint8 => QuorumEjectionParams) public quorumEjectionParams; - constructor(IRegistryCoordinator _registryCoordinator, IStakeRegistry _stakeRegistry) { + constructor(ISlashingRegistryCoordinator _registryCoordinator, IStakeRegistry _stakeRegistry) { registryCoordinator = _registryCoordinator; stakeRegistry = _stakeRegistry; diff --git a/src/IndexRegistry.sol b/src/IndexRegistry.sol index c8b46061..ef9b0c49 100644 --- a/src/IndexRegistry.sol +++ b/src/IndexRegistry.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.27; import {IndexRegistryStorage} from "./IndexRegistryStorage.sol"; -import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; /** * @title A `Registry` that keeps track of an ordered list of operators for each quorum @@ -17,8 +17,8 @@ contract IndexRegistry is IndexRegistryStorage { /// @notice sets the (immutable) `registryCoordinator` address constructor( - IRegistryCoordinator _registryCoordinator - ) IndexRegistryStorage(_registryCoordinator) {} + ISlashingRegistryCoordinator _slashingRegistryCoordinator + ) IndexRegistryStorage(_slashingRegistryCoordinator) {} /** * diff --git a/src/IndexRegistryStorage.sol b/src/IndexRegistryStorage.sol index 95f39e34..f2c1e3e6 100644 --- a/src/IndexRegistryStorage.sol +++ b/src/IndexRegistryStorage.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.27; import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; -import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; /** @@ -30,9 +30,9 @@ abstract contract IndexRegistryStorage is Initializable, IIndexRegistry { mapping(uint8 => QuorumUpdate[]) internal _operatorCountHistory; constructor( - IRegistryCoordinator _registryCoordinator + ISlashingRegistryCoordinator _slashingRegistryCoordinator ) { - registryCoordinator = address(_registryCoordinator); + registryCoordinator = address(_slashingRegistryCoordinator); // disable initializers so that the implementation contract cannot be initialized _disableInitializers(); } diff --git a/src/OperatorStateRetriever.sol b/src/OperatorStateRetriever.sol index 82dc8d6e..d3e06490 100644 --- a/src/OperatorStateRetriever.sol +++ b/src/OperatorStateRetriever.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; @@ -40,7 +40,7 @@ contract OperatorStateRetriever { * was a part of at `blockNumber`, an ordered list of operators. */ function getOperatorState( - IRegistryCoordinator registryCoordinator, + ISlashingRegistryCoordinator registryCoordinator, bytes32 operatorId, uint32 blockNumber ) external view returns (uint256, Operator[][] memory) { @@ -66,7 +66,7 @@ contract OperatorStateRetriever { * @return 2d array of Operators. For each quorum, an ordered list of Operators */ function getOperatorState( - IRegistryCoordinator registryCoordinator, + ISlashingRegistryCoordinator registryCoordinator, bytes memory quorumNumbers, uint32 blockNumber ) public view returns (Operator[][] memory) { @@ -109,7 +109,7 @@ contract OperatorStateRetriever { * 4) the indices of the quorum apks for each of the provided quorums at the given blocknumber */ function getCheckSignaturesIndices( - IRegistryCoordinator registryCoordinator, + ISlashingRegistryCoordinator registryCoordinator, uint32 referenceBlockNumber, bytes calldata quorumNumbers, bytes32[] calldata nonSignerOperatorIds @@ -185,7 +185,7 @@ contract OperatorStateRetriever { * @param blockNumber is the block number to get the quorumBitmaps for */ function getQuorumBitmapsAtBlockNumber( - IRegistryCoordinator registryCoordinator, + ISlashingRegistryCoordinator registryCoordinator, bytes32[] memory operatorIds, uint32 blockNumber ) external view returns (uint256[] memory) { @@ -207,7 +207,7 @@ contract OperatorStateRetriever { * @dev if an operator is not registered, the operatorId will be 0 */ function getBatchOperatorId( - IRegistryCoordinator registryCoordinator, + ISlashingRegistryCoordinator registryCoordinator, address[] memory operators ) external view returns (bytes32[] memory operatorIds) { operatorIds = new bytes32[](operators.length); @@ -223,7 +223,7 @@ contract OperatorStateRetriever { * @dev if an operator is not registered, the operator address will be 0 */ function getBatchOperatorFromId( - IRegistryCoordinator registryCoordinator, + ISlashingRegistryCoordinator registryCoordinator, bytes32[] memory operatorIds ) external view returns (address[] memory operators) { operators = new address[](operatorIds.length); diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index fbcb154a..5dade2dd 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -2,33 +2,16 @@ pragma solidity ^0.8.27; import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; -import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; -import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; -import { - IAllocationManager, - OperatorSet, - IAllocationManagerTypes -} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {ISocketUpdater} from "./interfaces/ISocketUpdater.sol"; +import {IAllocationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; -import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; +import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; import {BitmapUtils} from "./libraries/BitmapUtils.sol"; -import {BN254} from "./libraries/BN254.sol"; -import {SignatureCheckerLib} from "./libraries/SignatureCheckerLib.sol"; -import {QuorumBitmapHistoryLib} from "./libraries/QuorumBitmapHistoryLib.sol"; -import {AVSRegistrar} from "./AVSRegistrar.sol"; - -import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; -import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; -import {EIP712} from "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol"; - -import {Pausable} from "eigenlayer-contracts/src/contracts/permissions/Pausable.sol"; -import {RegistryCoordinatorStorage} from "./RegistryCoordinatorStorage.sol"; -import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; +import {SlashingRegistryCoordinator} from "./SlashingRegistryCoordinator.sol"; /** * @title A `RegistryCoordinator` that has three registries: @@ -38,32 +21,11 @@ import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSR * * @author Layr Labs, Inc. */ -contract RegistryCoordinator is - EIP712, - Initializable, - Pausable, - OwnableUpgradeable, - RegistryCoordinatorStorage, - AVSRegistrar, - ISocketUpdater, - ISignatureUtils -{ +contract RegistryCoordinator is SlashingRegistryCoordinator, IRegistryCoordinator { using BitmapUtils for *; - using BN254 for BN254.G1Point; - - modifier onlyEjector() { - _checkEjector(); - _; - } - /// @dev Checks that `quorumNumber` corresponds to a quorum that has been created - /// via `initialize` or `createQuorum` - modifier quorumExists( - uint8 quorumNumber - ) { - _checkQuorumExists(quorumNumber); - _; - } + /// @notice the ServiceManager for this AVS, which forwards calls onto EigenLayer's core contracts + IServiceManager public immutable serviceManager; constructor( IServiceManager _serviceManager, @@ -73,69 +35,15 @@ contract RegistryCoordinator is IAllocationManager _allocationManager, IPauserRegistry _pauserRegistry ) - RegistryCoordinatorStorage( - _serviceManager, + SlashingRegistryCoordinator( _stakeRegistry, _blsApkRegistry, _indexRegistry, - _allocationManager + _allocationManager, + _pauserRegistry ) - EIP712("AVSRegistryCoordinator", "v0.0.1") - Pausable(_pauserRegistry) { - _disableInitializers(); - } - - /** - * @param _initialOwner will hold the owner role - * @param _churnApprover will hold the churnApprover role, which authorizes registering with churn - * @param _ejector will hold the ejector role, which can force-eject operators from quorums - * @param _initialPausedStatus pause status after calling initialize - * Config for initial quorums (see `createQuorum`): - * @param _operatorSetParams max operator count and operator churn parameters - * @param _minimumStakes minimum stake weight to allow an operator to register - * @param _strategyParams which Strategies/multipliers a quorum considers when calculating stake weight - */ - function initialize( - address _initialOwner, - address _churnApprover, - address _ejector, - uint256 _initialPausedStatus, - OperatorSetParam[] memory _operatorSetParams, - uint96[] memory _minimumStakes, - IStakeRegistry.StrategyParams[][] memory _strategyParams, - StakeType[] memory _stakeTypes, - uint32[] memory _lookAheadPeriods - ) external initializer { - require( - _operatorSetParams.length == _minimumStakes.length - && _minimumStakes.length == _strategyParams.length - && _strategyParams.length == _stakeTypes.length - && _stakeTypes.length == _lookAheadPeriods.length, - InputLengthMismatch() - ); - - // Initialize roles - _transferOwnership(_initialOwner); - _setChurnApprover(_churnApprover); - _setPausedStatus(_initialPausedStatus); - _setEjector(_ejector); - - // Add registry contracts to the registries array - registries.push(address(stakeRegistry)); - registries.push(address(blsApkRegistry)); - registries.push(address(indexRegistry)); - - // Create quorums - for (uint256 i = 0; i < _operatorSetParams.length; i++) { - _createQuorum( - _operatorSetParams[i], - _minimumStakes[i], - _strategyParams[i], - _stakeTypes[i], - _lookAheadPeriods[i] - ); - } + serviceManager = _serviceManager; } /** @@ -144,23 +52,14 @@ contract RegistryCoordinator is * */ - /** - * @notice Registers msg.sender as an operator for one or more quorums. If any quorum exceeds its maximum - * operator capacity after the operator is registered, this method will fail. - * @param quorumNumbers is an ordered byte array containing the quorum numbers being registered for - * @param socket is the socket of the operator (typically an IP address) - * @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership - * @param operatorSignature is the signature of the operator used by the AVS to register the operator in the delegation manager - * @dev `params` is ignored if the caller has previously registered a public key - * @dev `operatorSignature` is ignored if the operator's status is already REGISTERED - */ + /// @inheritdoc IRegistryCoordinator function registerOperator( bytes memory quorumNumbers, string memory socket, IBLSApkRegistry.PubkeyRegistrationParams memory params, SignatureWithSaltAndExpiry memory operatorSignature ) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { - require(!isUsingOperatorSets(), OperatorSetsEnabled()); + require(!m2QuorumsDisabled, M2QuorumsAlreadyDisabled()); /** * If the operator has NEVER registered a pubkey before, use `params` to register * their pubkey in blsApkRegistry @@ -176,8 +75,7 @@ contract RegistryCoordinator is operator: msg.sender, operatorId: operatorId, quorumNumbers: quorumNumbers, - socket: socket, - operatorSignature: operatorSignature + socket: socket }).numOperatorsPerQuorum; // For each quorum, validate that the new operator count does not exceed the maximum @@ -190,20 +88,19 @@ contract RegistryCoordinator is MaxQuorumsReached() ); } + + // If the operator wasn't registered for any quorums, update their status + // and register them with this AVS in EigenLayer core (DelegationManager) + if (_operatorInfo[msg.sender].status != OperatorStatus.REGISTERED) { + _operatorInfo[msg.sender] = + OperatorInfo({operatorId: operatorId, status: OperatorStatus.REGISTERED}); + + serviceManager.registerOperatorToAVS(msg.sender, operatorSignature); + emit OperatorRegistered(msg.sender, operatorId); + } } - /** - * @notice Registers msg.sender as an operator for one or more quorums. If any quorum reaches its maximum operator - * capacity, `operatorKickParams` is used to replace an old operator with the new one. - * @param quorumNumbers is an ordered byte array containing the quorum numbers being registered for - * @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership - * @param operatorKickParams used to determine which operator is removed to maintain quorum capacity as the - * operator registers for quorums - * @param churnApproverSignature is the signature of the churnApprover over the `operatorKickParams` - * @param operatorSignature is the signature of the operator used by the AVS to register the operator in the delegation manager - * @dev `params` is ignored if the caller has previously registered a public key - * @dev `operatorSignature` is ignored if the operator's status is already REGISTERED - */ + /// @inheritdoc IRegistryCoordinator function registerOperatorWithChurn( bytes calldata quorumNumbers, string memory socket, @@ -212,8 +109,7 @@ contract RegistryCoordinator is SignatureWithSaltAndExpiry memory churnApproverSignature, SignatureWithSaltAndExpiry memory operatorSignature ) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { - require(!isUsingOperatorSets(), OperatorSetsEnabled()); - require(operatorKickParams.length == quorumNumbers.length, InputLengthMismatch()); + require(!m2QuorumsDisabled, M2QuorumsAlreadyDisabled()); /** * If the operator has NEVER registered a pubkey before, use `params` to register @@ -224,1044 +120,87 @@ contract RegistryCoordinator is */ bytes32 operatorId = _getOrCreateOperatorId(msg.sender, params); - // Verify the churn approver's signature for the registering operator and kick params - _verifyChurnApproverSignature({ - registeringOperator: msg.sender, - registeringOperatorId: operatorId, - operatorKickParams: operatorKickParams, - churnApproverSignature: churnApproverSignature - }); - - // Register the operator in each of the registry contracts and update the operator's - // quorum bitmap and registration status - RegisterResults memory results = _registerOperator({ + _registerOperatorWithChurn({ operator: msg.sender, operatorId: operatorId, quorumNumbers: quorumNumbers, socket: socket, - operatorSignature: operatorSignature + operatorKickParams: operatorKickParams, + churnApproverSignature: churnApproverSignature }); - // Check that each quorum's operator count is below the configured maximum. If the max - // is exceeded, use `operatorKickParams` to deregister an existing operator to make space - for (uint256 i = 0; i < quorumNumbers.length; i++) { - OperatorSetParam memory operatorSetParams = _quorumParams[uint8(quorumNumbers[i])]; - - /** - * If the new operator count for any quorum exceeds the maximum, validate - * that churn can be performed, then deregister the specified operator - */ - if (results.numOperatorsPerQuorum[i] > operatorSetParams.maxOperatorCount) { - _validateChurn({ - quorumNumber: uint8(quorumNumbers[i]), - totalQuorumStake: results.totalStakes[i], - newOperator: msg.sender, - newOperatorStake: results.operatorStakes[i], - kickParams: operatorKickParams[i], - setParams: operatorSetParams - }); + // If the operator wasn't registered for any quorums, update their status + // and register them with this AVS in EigenLayer core (DelegationManager) + if (_operatorInfo[msg.sender].status != OperatorStatus.REGISTERED) { + _operatorInfo[msg.sender] = + OperatorInfo({operatorId: operatorId, status: OperatorStatus.REGISTERED}); - _deregisterOperator(operatorKickParams[i].operator, quorumNumbers[i:i + 1]); - } + serviceManager.registerOperatorToAVS(msg.sender, operatorSignature); + emit OperatorRegistered(msg.sender, operatorId); } } - /** - * @notice Deregisters the caller from one or more quorums - * @param quorumNumbers is an ordered byte array containing the quorum numbers being deregistered from - */ + /// @inheritdoc IRegistryCoordinator function deregisterOperator( bytes memory quorumNumbers ) external onlyWhenNotPaused(PAUSED_DEREGISTER_OPERATOR) { - // Check that either: - // 1. The AVS hasn't migrated to operator sets yet (!isOperatorSetAVS), or - // 2. The AVS has migrated but this is an M2 quorum + // Check that the quorum numbers are M2 quorums for (uint256 i = 0; i < quorumNumbers.length; i++) { - uint8 quorumNumber = uint8(quorumNumbers[i]); - require(!isOperatorSetAVS || isM2Quorum[quorumNumber], OperatorSetsEnabled()); + require( + !operatorSetsEnabled || _isM2Quorum(uint8(quorumNumbers[i])), + OperatorSetsAlreadyEnabled() + ); } _deregisterOperator({operator: msg.sender, quorumNumbers: quorumNumbers}); } - function isUsingOperatorSets() public view returns (bool) { - return isOperatorSetAVS; - } - + /// @inheritdoc IRegistryCoordinator function enableOperatorSets() external onlyOwner { - require(!isOperatorSetAVS, OperatorSetsEnabled()); + require(!operatorSetsEnabled, OperatorSetsAlreadyEnabled()); - // Set all existing quorums as m2 quorums - for (uint8 i = 0; i < quorumCount; i++) { - isM2Quorum[i] = true; - } + // Set the bitmap for M2 quorums + M2quorumBitmap = _getQuorumBitmap(quorumCount); // Enable operator sets mode - isOperatorSetAVS = true; - } - enum RegistrationType { - NORMAL, - CHURN - } + operatorSetsEnabled = true; - error InvalidRegistrationType(); - - function registerOperator( - address operator, - uint32[] memory operatorSetIds, - bytes calldata data - ) external override onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { - require(isUsingOperatorSets(), OperatorSetsNotEnabled()); - for (uint256 i = 0; i < operatorSetIds.length; i++) { - require(!isM2Quorum[uint8(operatorSetIds[i])], OperatorSetsNotSupported()); - } - _checkAllocationManager(); - bytes memory quorumNumbers = new bytes(operatorSetIds.length); - for (uint256 i = 0; i < operatorSetIds.length; i++) { - quorumNumbers[i] = bytes1(uint8(operatorSetIds[i])); - } - - // Handle churn or normal registration based on first byte in `data` - RegistrationType registrationType = RegistrationType(uint8(bytes1(data[0:1]))); - if (registrationType == RegistrationType.NORMAL) { - (, string memory socket, IBLSApkRegistry.PubkeyRegistrationParams memory params) = abi.decode(data, (RegistrationType, string, IBLSApkRegistry.PubkeyRegistrationParams)); - bytes32 operatorId = _getOrCreateOperatorId(operator, params); - _registerOperatorToOperatorSet(operator, operatorId, quorumNumbers, socket); - } else if (registrationType == RegistrationType.CHURN) { - // Decode registration data from bytes - ( - , - string memory socket, - IBLSApkRegistry.PubkeyRegistrationParams memory params, - OperatorKickParam[] memory operatorKickParams, - SignatureWithSaltAndExpiry memory churnApproverSignature - ) = abi.decode( - data, - ( - RegistrationType, - string, - IBLSApkRegistry.PubkeyRegistrationParams, - OperatorKickParam[], - SignatureWithSaltAndExpiry - ) - ); - - _registerOperatorWithChurn(operator, quorumNumbers, socket, params, operatorKickParams, churnApproverSignature); - } else { - revert InvalidRegistrationType(); - } + emit OperatorSetsEnabled(); } - function _registerOperatorWithChurn( - address operator, - bytes memory quorumNumbers, - string memory socket, - IBLSApkRegistry.PubkeyRegistrationParams memory params, - OperatorKickParam[] memory operatorKickParams, - SignatureWithSaltAndExpiry memory churnApproverSignature - ) internal virtual { - require(operatorKickParams.length == quorumNumbers.length, InputLengthMismatch()); + /// @inheritdoc IRegistryCoordinator + function disableM2QuorumRegistration() external onlyOwner { + require(operatorSetsEnabled, OperatorSetsNotEnabled()); - /** - * If the operator has NEVER registered a pubkey before, use `params` to register - * their pubkey in blsApkRegistry - * - * If the operator HAS registered a pubkey, `params` is ignored and the pubkey hash - * (operatorId) is fetched instead - */ - bytes32 operatorId = _getOrCreateOperatorId(operator, params); - - // Verify the churn approver's signature for the registering operator and kick params - _verifyChurnApproverSignature({ - registeringOperator: operator, - registeringOperatorId: operatorId, - operatorKickParams: operatorKickParams, - churnApproverSignature: churnApproverSignature - }); + m2QuorumsDisabled = true; - // Register the operator in each of the registry contracts and update the operator's - // quorum bitmap and registration status - RegisterResults memory results = _registerOperatorToOperatorSet(operator, operatorId, quorumNumbers, socket); - - // Check that each quorum's operator count is below the configured maximum. If the max - // is exceeded, use `operatorKickParams` to deregister an existing operator to make space - for (uint256 i = 0; i < quorumNumbers.length; i++) { - OperatorSetParam memory operatorSetParams = _quorumParams[uint8(quorumNumbers[i])]; - - /** - * If the new operator count for any quorum exceeds the maximum, validate - * that churn can be performed, then deregister the specified operator - */ - if (results.numOperatorsPerQuorum[i] > operatorSetParams.maxOperatorCount) { - _validateChurn({ - quorumNumber: uint8(quorumNumbers[i]), - totalQuorumStake: results.totalStakes[i], - newOperator: operator, - newOperatorStake: results.operatorStakes[i], - kickParams: operatorKickParams[i], - setParams: operatorSetParams - }); - - bytes memory singleQuorumNumber = new bytes(1); - singleQuorumNumber[0] = quorumNumbers[i]; - _deregisterOperator(operatorKickParams[i].operator, singleQuorumNumber); - if (isUsingOperatorSets()) { - _handleOperatorSetDeregistration(operatorKickParams[i].operator, singleQuorumNumber); - } - } - } + emit M2QuorumsDisabled(); } - function deregisterOperator( - address operator, - uint32[] memory operatorSetIds - ) external override onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { - require(isUsingOperatorSets(), OperatorSetsNotEnabled()); - for (uint256 i = 0; i < operatorSetIds.length; i++) { - require(!isM2Quorum[uint8(operatorSetIds[i])], OperatorSetsNotSupported()); - } - _checkAllocationManager(); - bytes memory quorumNumbers = new bytes(operatorSetIds.length); - for (uint256 i = 0; i < operatorSetIds.length; i++) { - quorumNumbers[i] = bytes1(uint8(operatorSetIds[i])); - } - - _deregisterOperator(operator, quorumNumbers); - } - - /** - * @notice Updates the StakeRegistry's view of one or more operators' stakes. If any operator - * is found to be below the minimum stake for the quorum, they are deregistered. - * @dev stakes are queried from the Eigenlayer core DelegationManager contract - * @param operators a list of operator addresses to update - */ - function updateOperators( - address[] memory operators - ) external onlyWhenNotPaused(PAUSED_UPDATE_OPERATOR) { - for (uint256 i = 0; i < operators.length; i++) { - address operator = operators[i]; - OperatorInfo memory operatorInfo = _operatorInfo[operator]; - bytes32 operatorId = operatorInfo.operatorId; - - // Update the operator's stake for their active quorums - uint192 currentBitmap = _currentOperatorBitmap(operatorId); - bytes memory quorumsToUpdate = BitmapUtils.bitmapToBytesArray(currentBitmap); - _updateOperator(operator, operatorInfo, quorumsToUpdate); - } - } - - /** - * @notice For each quorum in `quorumNumbers`, updates the StakeRegistry's view of ALL its registered operators' stakes. - * Each quorum's `quorumUpdateBlockNumber` is also updated, which tracks the most recent block number when ALL registered - * operators were updated. - * @dev stakes are queried from the Eigenlayer core DelegationManager contract - * @param operatorsPerQuorum for each quorum in `quorumNumbers`, this has a corresponding list of operators to update. - * @dev Each list of operator addresses MUST be sorted in ascending order - * @dev Each list of operator addresses MUST represent the entire list of registered operators for the corresponding quorum - * @param quorumNumbers is an ordered byte array containing the quorum numbers being updated - * @dev invariant: Each list of `operatorsPerQuorum` MUST be a sorted version of `IndexRegistry.getOperatorListAtBlockNumber` - * for the corresponding quorum. - * @dev note on race condition: if an operator registers/deregisters for any quorum in `quorumNumbers` after a txn to - * this method is broadcast (but before it is executed), the method will fail - */ - function updateOperatorsForQuorum( - address[][] memory operatorsPerQuorum, - bytes calldata quorumNumbers - ) external onlyWhenNotPaused(PAUSED_UPDATE_OPERATOR) { - // Input validation - // - all quorums should exist (checked against `quorumCount` in orderedBytesArrayToBitmap) - // - there should be no duplicates in `quorumNumbers` - // - there should be one list of operators per quorum - BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount); - require(operatorsPerQuorum.length == quorumNumbers.length, InputLengthMismatch()); - - // For each quorum, update ALL registered operators - for (uint256 i = 0; i < quorumNumbers.length; ++i) { - uint8 quorumNumber = uint8(quorumNumbers[i]); - - // Ensure we've passed in the correct number of operators for this quorum - address[] memory currQuorumOperators = operatorsPerQuorum[i]; - require( - currQuorumOperators.length == indexRegistry.totalOperatorsForQuorum(quorumNumber), - QuorumOperatorCountMismatch() - ); - - address prevOperatorAddress = address(0); - // For each operator: - // - check that they are registered for this quorum - // - check that their address is strictly greater than the last operator - // ... then, update their stakes - for (uint256 j = 0; j < currQuorumOperators.length; ++j) { - address operator = currQuorumOperators[j]; - - OperatorInfo memory operatorInfo = _operatorInfo[operator]; - bytes32 operatorId = operatorInfo.operatorId; - - { - uint192 currentBitmap = _currentOperatorBitmap(operatorId); - // Check that the operator is registered - require( - BitmapUtils.isSet(currentBitmap, quorumNumber), NotRegisteredForQuorum() - ); - // Prevent duplicate operators - require(operator > prevOperatorAddress, NotSorted()); - } - - // Update the operator - _updateOperator(operator, operatorInfo, quorumNumbers[i:i + 1]); - prevOperatorAddress = operator; - } - - // Update timestamp that all operators in quorum have been updated all at once - quorumUpdateBlockNumber[quorumNumber] = block.number; - emit QuorumBlockNumberUpdated(quorumNumber, block.number); - } - } - - /** - * @notice Updates the socket of the msg.sender given they are a registered operator - * @param socket is the new socket of the operator - */ - function updateSocket( - string memory socket - ) external { - require(_operatorInfo[msg.sender].status == OperatorStatus.REGISTERED, NotRegistered()); - emit OperatorSocketUpdate(_operatorInfo[msg.sender].operatorId, socket); - } - - /** - * - * EXTERNAL FUNCTIONS - EJECTOR - * - */ - - /** - * @notice Forcibly deregisters an operator from one or more quorums - * @param operator the operator to eject - * @param quorumNumbers the quorum numbers to eject the operator from - * @dev possible race condition if prior to being ejected for a set of quorums the operator self deregisters from a subset - */ - function ejectOperator(address operator, bytes memory quorumNumbers) external onlyEjector { - lastEjectionTimestamp[operator] = block.timestamp; - - OperatorInfo storage operatorInfo = _operatorInfo[operator]; - bytes32 operatorId = operatorInfo.operatorId; - uint192 quorumsToRemove = - uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); - uint192 currentBitmap = _currentOperatorBitmap(operatorId); - if ( - operatorInfo.status == OperatorStatus.REGISTERED && !quorumsToRemove.isEmpty() - && quorumsToRemove.isSubsetOf(currentBitmap) - ) { - // If using operator sets, check for non-M2 quorums - if (isUsingOperatorSets()) { - _handleOperatorSetDeregistration(operator, quorumNumbers); - } - - _deregisterOperator({operator: operator, quorumNumbers: quorumNumbers}); - } - } - - /** - * @notice Helper function to handle operator set deregistration for non-M2 quorums - * @param operator The operator to deregister - * @param quorumNumbers The quorum numbers to check - */ - function _handleOperatorSetDeregistration(address operator, bytes memory quorumNumbers) internal { - uint32[] memory nonM2OperatorSetIds = new uint32[](quorumNumbers.length); - uint256 numNonM2Quorums; - - // Check each quorum's stake type - for (uint256 i = 0; i < quorumNumbers.length; i++) { - uint8 quorumNumber = uint8(quorumNumbers[i]); - if (isM2Quorum[quorumNumber]) { - nonM2OperatorSetIds[numNonM2Quorums++] = quorumNumber; - } - } - - // If any non-M2 quorums found, deregister from AVS - if (numNonM2Quorums > 0) { - // Resize array to exact size needed - assembly { - mstore(nonM2OperatorSetIds, numNonM2Quorums) - } - serviceManager.deregisterOperatorFromOperatorSets(operator, nonM2OperatorSetIds); - } - } - - /** - * - * EXTERNAL FUNCTIONS - OWNER - * - */ - - /** - * @notice Creates a quorum and initializes it in each registry contract - * @param operatorSetParams configures the quorum's max operator count and churn parameters - * @param minimumStake sets the minimum stake required for an operator to register or remain - * registered - * @param strategyParams a list of strategies and multipliers used by the StakeRegistry to - * calculate an operator's stake weight for the quorum - * @dev For m2 AVS this function has the same behavior as createQuorum before - * For migrated AVS that enable operator sets this will create a quorum that measures total delegated stake for operator set - * - */ - function createTotalDelegatedStakeQuorum( - OperatorSetParam memory operatorSetParams, - uint96 minimumStake, - IStakeRegistry.StrategyParams[] memory strategyParams - ) external virtual onlyOwner { - _createQuorum(operatorSetParams, minimumStake, strategyParams, StakeType.TOTAL_DELEGATED, 0); - } - - function createSlashableStakeQuorum( - OperatorSetParam memory operatorSetParams, - uint96 minimumStake, - IStakeRegistry.StrategyParams[] memory strategyParams, - uint32 lookAheadPeriod - ) external virtual onlyOwner { - require(isUsingOperatorSets(), OperatorSetsNotEnabled()); - _createQuorum( - operatorSetParams, - minimumStake, - strategyParams, - StakeType.TOTAL_SLASHABLE, - lookAheadPeriod - ); - } - - /** - * @notice Updates an existing quorum's configuration with a new max operator count - * and operator churn parameters - * @param quorumNumber the quorum number to update - * @param operatorSetParams the new config - * @dev only callable by the owner - */ - function setOperatorSetParams( - uint8 quorumNumber, - OperatorSetParam memory operatorSetParams - ) external onlyOwner quorumExists(quorumNumber) { - _setOperatorSetParams(quorumNumber, operatorSetParams); - } - - /** - * @notice Sets the churnApprover, which approves operator registration with churn - * (see `registerOperatorWithChurn`) - * @param _churnApprover the new churn approver - * @dev only callable by the owner - */ - function setChurnApprover( - address _churnApprover - ) external onlyOwner { - _setChurnApprover(_churnApprover); - } - - /** - * @notice Sets the ejector, which can force-deregister operators from quorums - * @param _ejector the new ejector - * @dev only callable by the owner - */ - function setEjector( - address _ejector - ) external onlyOwner { - _setEjector(_ejector); - } - - /** - * @notice Sets the ejection cooldown, which is the time an operator must wait in - * seconds afer ejection before registering for any quorum - * @param _ejectionCooldown the new ejection cooldown in seconds - * @dev only callable by the owner - */ - function setEjectionCooldown(uint256 _ejectionCooldown) external onlyOwner { - ejectionCooldown = _ejectionCooldown; - } - - /** - * - * INTERNAL FUNCTIONS - * - */ - struct RegisterResults { - uint32[] numOperatorsPerQuorum; - uint96[] operatorStakes; - uint96[] totalStakes; - } - - /** - * @notice Register the operator for one or more quorums. This method updates the - * operator's quorum bitmap, socket, and status, then registers them with each registry. - */ - function _registerOperator( - address operator, - bytes32 operatorId, - bytes memory quorumNumbers, - string memory socket, - SignatureWithSaltAndExpiry memory operatorSignature - ) internal virtual returns (RegisterResults memory results) { - /** - * Get bitmap of quorums to register for and operator's current bitmap. Validate that: - * - we're trying to register for at least 1 quorum - * - the quorums we're registering for exist (checked against `quorumCount` in orderedBytesArrayToBitmap) - * - the operator is not currently registered for any quorums we're registering for - * Then, calculate the operator's new bitmap after registration - */ - uint192 quorumsToAdd = - uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); - uint192 currentBitmap = _currentOperatorBitmap(operatorId); - require(!quorumsToAdd.isEmpty(), BitmapEmpty()); - require(quorumsToAdd.noBitsInCommon(currentBitmap), AlreadyRegisteredForQuorums()); - uint192 newBitmap = uint192(currentBitmap.plus(quorumsToAdd)); - - // Check that the operator can reregister if ejected - require( - lastEjectionTimestamp[operator] + ejectionCooldown < block.timestamp, - CannotReregisterYet() - ); - - /** - * Update operator's bitmap, socket, and status. Only update operatorInfo if needed: - * if we're `REGISTERED`, the operatorId and status are already correct. - */ - _updateOperatorBitmap({operatorId: operatorId, newBitmap: newBitmap}); - - emit OperatorSocketUpdate(operatorId, socket); - - // If the operator wasn't registered for any quorums, update their status - // and register them with this AVS in EigenLayer core (DelegationManager) - if (_operatorInfo[operator].status != OperatorStatus.REGISTERED) { - _operatorInfo[operator] = - OperatorInfo({operatorId: operatorId, status: OperatorStatus.REGISTERED}); - - serviceManager.registerOperatorToAVS(operator, operatorSignature); - emit OperatorRegistered(operator, operatorId); - } - - // Register the operator with the BLSApkRegistry, StakeRegistry, and IndexRegistry - blsApkRegistry.registerOperator(operator, quorumNumbers); - (results.operatorStakes, results.totalStakes) = - stakeRegistry.registerOperator(operator, operatorId, quorumNumbers); - results.numOperatorsPerQuorum = indexRegistry.registerOperator(operatorId, quorumNumbers); - - return results; - } - - /** - * @notice Register the operator for one or more quorums. This method updates the - * operator's quorum bitmap, socket, and status, then registers them with each registry. - */ - function _registerOperatorToOperatorSet( + /// @dev Hook to allow for any post-deregister logic + function _afterDeregisterOperator( address operator, bytes32 operatorId, bytes memory quorumNumbers, - string memory socket - ) internal virtual returns (RegisterResults memory results) { - /** - * Get bitmap of quorums to register for and operator's current bitmap. Validate that: - * - we're trying to register for at least 1 quorum - * - the quorums we're registering for exist (checked against `quorumCount` in orderedBytesArrayToBitmap) - * - the operator is not currently registered for any quorums we're registering for - * Then, calculate the operator's new bitmap after registration - */ - uint192 quorumsToAdd = - uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); - uint192 currentBitmap = _currentOperatorBitmap(operatorId); - require(!quorumsToAdd.isEmpty(), BitmapEmpty()); - require(quorumsToAdd.noBitsInCommon(currentBitmap), AlreadyRegisteredForQuorums()); - uint192 newBitmap = uint192(currentBitmap.plus(quorumsToAdd)); - - // Check that the operator can reregister if ejected - require( - lastEjectionTimestamp[operator] + ejectionCooldown < block.timestamp, - CannotReregisterYet() - ); - - /** - * Update operator's bitmap, socket, and status. Only update operatorInfo if needed: - * if we're `REGISTERED`, the operatorId and status are already correct. - */ - _updateOperatorBitmap({operatorId: operatorId, newBitmap: newBitmap}); - - emit OperatorSocketUpdate(operatorId, socket); - - // If the operator wasn't registered for any quorums, update their status - // and register them with this AVS in EigenLayer core (DelegationManager) - if (_operatorInfo[operator].status != OperatorStatus.REGISTERED) { - _operatorInfo[operator] = OperatorInfo(operatorId, OperatorStatus.REGISTERED); - } - - // Register the operator with the BLSApkRegistry, StakeRegistry, and IndexRegistry - blsApkRegistry.registerOperator(operator, quorumNumbers); - (results.operatorStakes, results.totalStakes) = - stakeRegistry.registerOperator(operator, operatorId, quorumNumbers); - results.numOperatorsPerQuorum = indexRegistry.registerOperator(operatorId, quorumNumbers); - - return results; - } - - /** - * @notice Checks if the caller is the ejector - * @dev Reverts if the caller is not the ejector - */ - function _checkEjector() internal view { - require(msg.sender == ejector, OnlyEjector()); - } - - function _checkAllocationManager() internal view { - require(msg.sender == address(allocationManager), OnlyAllocationManager()); - } - - /** - * @notice Checks if a quorum exists - * @param quorumNumber The quorum number to check - * @dev Reverts if the quorum does not exist - */ - function _checkQuorumExists( - uint8 quorumNumber - ) internal view { - require(quorumNumber < quorumCount, QuorumDoesNotExist()); - } - - /** - * @notice Fetches an operator's pubkey hash from the BLSApkRegistry. If the - * operator has not registered a pubkey, attempts to register a pubkey using - * `params` - * @param operator the operator whose pubkey to query from the BLSApkRegistry - * @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership - * @dev `params` can be empty if the operator has already registered a pubkey in the BLSApkRegistry - */ - function _getOrCreateOperatorId( - address operator, - IBLSApkRegistry.PubkeyRegistrationParams memory params - ) internal returns (bytes32 operatorId) { - operatorId = blsApkRegistry.getOperatorId(operator); - if (operatorId == 0) { - operatorId = blsApkRegistry.registerBLSPublicKey( - operator, params, pubkeyRegistrationMessageHash(operator) - ); - } - return operatorId; - } - - /** - * @notice Validates that an incoming operator is eligible to replace an existing - * operator based on the stake of both - * @dev In order to churn, the incoming operator needs to have more stake than the - * existing operator by a proportion given by `kickBIPsOfOperatorStake` - * @dev In order to be churned out, the existing operator needs to have a proportion - * of the total quorum stake less than `kickBIPsOfTotalStake` - * @param quorumNumber `newOperator` is trying to replace an operator in this quorum - * @param totalQuorumStake the total stake of all operators in the quorum, after the - * `newOperator` registers - * @param newOperator the incoming operator - * @param newOperatorStake the incoming operator's stake - * @param kickParams the quorum number and existing operator to replace - * @dev the existing operator's registration to this quorum isn't checked here, but - * if we attempt to deregister them, this will be checked in `_deregisterOperator` - * @param setParams config for this quorum containing `kickBIPsX` stake proportions - * mentioned above - */ - function _validateChurn( - uint8 quorumNumber, - uint96 totalQuorumStake, - address newOperator, - uint96 newOperatorStake, - OperatorKickParam memory kickParams, - OperatorSetParam memory setParams - ) internal view { - address operatorToKick = kickParams.operator; - bytes32 idToKick = _operatorInfo[operatorToKick].operatorId; - require(newOperator != operatorToKick, CannotChurnSelf()); - require(kickParams.quorumNumber == quorumNumber, QuorumOperatorCountMismatch()); - - // Get the target operator's stake and check that it is below the kick thresholds - uint96 operatorToKickStake = stakeRegistry.getCurrentStake(idToKick, quorumNumber); - require( - newOperatorStake > _individualKickThreshold(operatorToKickStake, setParams), - InsufficientStakeForChurn() - ); - require( - operatorToKickStake < _totalKickThreshold(totalQuorumStake, setParams), - CannotKickOperatorAboveThreshold() - ); - } - - /** - * @dev Deregister the operator from one or more quorums - * This method updates the operator's quorum bitmap and status, then deregisters - * the operator with the BLSApkRegistry, IndexRegistry, and StakeRegistry - */ - function _deregisterOperator(address operator, bytes memory quorumNumbers) internal virtual { - // Fetch the operator's info and ensure they are registered - OperatorInfo storage operatorInfo = _operatorInfo[operator]; - bytes32 operatorId = operatorInfo.operatorId; - require(operatorInfo.status == OperatorStatus.REGISTERED, NotRegistered()); - - /** - * Get bitmap of quorums to deregister from and operator's current bitmap. Validate that: - * - we're trying to deregister from at least 1 quorum - * - the quorums we're deregistering from exist (checked against `quorumCount` in orderedBytesArrayToBitmap) - * - the operator is currently registered for any quorums we're trying to deregister from - * Then, calculate the operator's new bitmap after deregistration - */ - uint192 quorumsToRemove = - uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); - uint192 currentBitmap = _currentOperatorBitmap(operatorId); - require(!quorumsToRemove.isEmpty(), BitmapCannotBeZero()); - require(quorumsToRemove.isSubsetOf(currentBitmap), NotRegisteredForQuorum()); - uint192 newBitmap = uint192(currentBitmap.minus(quorumsToRemove)); - - // Update operator's bitmap and status - _updateOperatorBitmap({operatorId: operatorId, newBitmap: newBitmap}); - - // If the operator is no longer registered for any quorums, update their status and deregister + uint192 newBitmap + ) internal virtual override { + uint256 operatorM2QuorumBitmap = newBitmap.minus(M2quorumBitmap); + // If the operator is no longer registered for any M2 quorums, update their status and deregister // them from the AVS via the EigenLayer core contracts - if (newBitmap.isEmpty()) { - operatorInfo.status = OperatorStatus.DEREGISTERED; + if (operatorM2QuorumBitmap.isEmpty()) { serviceManager.deregisterOperatorFromAVS(operator); - emit OperatorDeregistered(operator, operatorId); - } - - // Deregister operator with each of the registry contracts - blsApkRegistry.deregisterOperator(operator, quorumNumbers); - stakeRegistry.deregisterOperator(operatorId, quorumNumbers); - indexRegistry.deregisterOperator(operatorId, quorumNumbers); - } - - /** - * @notice Updates the StakeRegistry's view of the operator's stake in one or more quorums. - * For any quorums where the StakeRegistry finds the operator is under the configured minimum - * stake, `quorumsToRemove` is returned and used to deregister the operator from those quorums - * @dev does nothing if operator is not registered for any quorums. - */ - function _updateOperator( - address operator, - OperatorInfo memory operatorInfo, - bytes memory quorumsToUpdate - ) internal { - if (operatorInfo.status != OperatorStatus.REGISTERED) { - return; - } - bytes32 operatorId = operatorInfo.operatorId; - uint192 quorumsToRemove = - stakeRegistry.updateOperatorStake(operator, operatorId, quorumsToUpdate); - - if (!quorumsToRemove.isEmpty()) { - _deregisterOperator({ - operator: operator, - quorumNumbers: BitmapUtils.bitmapToBytesArray(quorumsToRemove) - }); } } - /** - * @notice Returns the stake threshold required for an incoming operator to replace an existing operator - * The incoming operator must have more stake than the return value. - */ - function _individualKickThreshold( - uint96 operatorStake, - OperatorSetParam memory setParams - ) internal pure returns (uint96) { - return operatorStake * setParams.kickBIPsOfOperatorStake / BIPS_DENOMINATOR; - } - - /** - * @notice Returns the total stake threshold required for an operator to remain in a quorum. - * The operator must have at least the returned stake amount to keep their position. - */ - function _totalKickThreshold( - uint96 totalStake, - OperatorSetParam memory setParams - ) internal pure returns (uint96) { - return totalStake * setParams.kickBIPsOfTotalStake / BIPS_DENOMINATOR; - } - - /// @notice verifies churnApprover's signature on operator churn approval and increments the churnApprover nonce - function _verifyChurnApproverSignature( - address registeringOperator, - bytes32 registeringOperatorId, - OperatorKickParam[] memory operatorKickParams, - SignatureWithSaltAndExpiry memory churnApproverSignature - ) internal { - // make sure the salt hasn't been used already - require(!isChurnApproverSaltUsed[churnApproverSignature.salt], ChurnApproverSaltUsed()); - require(churnApproverSignature.expiry >= block.timestamp, SignatureExpired()); - - // set salt used to true - isChurnApproverSaltUsed[churnApproverSignature.salt] = true; - - // check the churnApprover's signature - SignatureCheckerLib.isValidSignature( - churnApprover, - calculateOperatorChurnApprovalDigestHash( - registeringOperator, - registeringOperatorId, - operatorKickParams, - churnApproverSignature.salt, - churnApproverSignature.expiry - ), - churnApproverSignature.signature - ); - } - - /** - * @notice Creates a quorum and initializes it in each registry contract - * @param operatorSetParams configures the quorum's max operator count and churn parameters - * @param minimumStake sets the minimum stake required for an operator to register or remain - * registered - * @param strategyParams a list of strategies and multipliers used by the StakeRegistry to - * calculate an operator's stake weight for the quorum - */ - function _createQuorum( - OperatorSetParam memory operatorSetParams, - uint96 minimumStake, - IStakeRegistry.StrategyParams[] memory strategyParams, - StakeType stakeType, - uint32 lookAheadPeriod - ) internal { - // Increment the total quorum count. Fails if we're already at the max - uint8 prevQuorumCount = quorumCount; - require(prevQuorumCount < MAX_QUORUM_COUNT, MaxQuorumsReached()); - quorumCount = prevQuorumCount + 1; - - // The previous count is the new quorum's number - uint8 quorumNumber = prevQuorumCount; - - // Initialize the quorum here and in each registry - _setOperatorSetParams(quorumNumber, operatorSetParams); - - /// Update the AllocationManager if operatorSetQuorum - if (isOperatorSetAVS && !isM2Quorum[quorumNumber]) { - // Create array of CreateSetParams for the new quorum - IAllocationManagerTypes.CreateSetParams[] memory createSetParams = - new IAllocationManagerTypes.CreateSetParams[](1); - - // Extract strategies from strategyParams - IStrategy[] memory strategies = new IStrategy[](strategyParams.length); - for (uint256 i = 0; i < strategyParams.length; i++) { - strategies[i] = strategyParams[i].strategy; - } - - // Initialize CreateSetParams with quorumNumber as operatorSetId - createSetParams[0] = IAllocationManagerTypes.CreateSetParams({ - operatorSetId: quorumNumber, - strategies: strategies - }); - allocationManager.createOperatorSets({ - avs: address(serviceManager), - params: createSetParams - }); - } - // Initialize stake registry based on stake type - if (stakeType == StakeType.TOTAL_DELEGATED) { - stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); - } else if (stakeType == StakeType.TOTAL_SLASHABLE) { - stakeRegistry.initializeSlashableStakeQuorum( - quorumNumber, minimumStake, lookAheadPeriod, strategyParams - ); - } - - indexRegistry.initializeQuorum(quorumNumber); - blsApkRegistry.initializeQuorum(quorumNumber); - } - - /** - * @notice Record an update to an operator's quorum bitmap. - * @param newBitmap is the most up-to-date set of bitmaps the operator is registered for - */ - function _updateOperatorBitmap(bytes32 operatorId, uint192 newBitmap) internal { - QuorumBitmapHistoryLib.updateOperatorBitmap(_operatorBitmapHistory, operatorId, newBitmap); - } - - /// @notice Get the most recent bitmap for the operator, returning an empty bitmap if - /// the operator is not registered. - function _currentOperatorBitmap( - bytes32 operatorId - ) internal view returns (uint192) { - return QuorumBitmapHistoryLib.currentOperatorBitmap(_operatorBitmapHistory, operatorId); - } - - /** - * @notice Returns the index of the quorumBitmap for the provided `operatorId` at the given `blockNumber` - * @dev Reverts if the operator had not yet (ever) registered at `blockNumber` - * @dev This function is designed to find proper inputs to the `getQuorumBitmapAtBlockNumberByIndex` function - */ - function _getQuorumBitmapIndexAtBlockNumber( - uint32 blockNumber, - bytes32 operatorId - ) internal view returns (uint32 index) { - return QuorumBitmapHistoryLib.getQuorumBitmapIndexAtBlockNumber( - _operatorBitmapHistory, blockNumber, operatorId - ); - } - - function _setOperatorSetParams( - uint8 quorumNumber, - OperatorSetParam memory operatorSetParams - ) internal { - _quorumParams[quorumNumber] = operatorSetParams; - emit OperatorSetParamsUpdated(quorumNumber, operatorSetParams); - } - - function _setChurnApprover( - address newChurnApprover - ) internal { - emit ChurnApproverUpdated(churnApprover, newChurnApprover); - churnApprover = newChurnApprover; - } - - function _setEjector( - address newEjector - ) internal { - emit EjectorUpdated(ejector, newEjector); - ejector = newEjector; - } - - /** - * - * VIEW FUNCTIONS - * - */ - - /// @notice Returns the operator set params for the given `quorumNumber` - function getOperatorSetParams( - uint8 quorumNumber - ) external view returns (OperatorSetParam memory) { - return _quorumParams[quorumNumber]; - } - - /// @notice Returns the operator struct for the given `operator` - function getOperator( - address operator - ) external view returns (OperatorInfo memory) { - return _operatorInfo[operator]; - } - - /// @notice Returns the operatorId for the given `operator` - function getOperatorId( - address operator - ) external view returns (bytes32) { - return _operatorInfo[operator].operatorId; - } - - /// @notice Returns the operator address for the given `operatorId` - function getOperatorFromId( - bytes32 operatorId - ) external view returns (address) { - return blsApkRegistry.getOperatorFromPubkeyHash(operatorId); - } - - /// @notice Returns the status for the given `operator` - function getOperatorStatus( - address operator - ) external view returns (IRegistryCoordinator.OperatorStatus) { - return _operatorInfo[operator].status; - } - - /** - * @notice Returns the indices of the quorumBitmaps for the provided `operatorIds` at the given `blockNumber` - * @dev Reverts if any of the `operatorIds` was not (yet) registered at `blockNumber` - * @dev This function is designed to find proper inputs to the `getQuorumBitmapAtBlockNumberByIndex` function - */ - function getQuorumBitmapIndicesAtBlockNumber( - uint32 blockNumber, - bytes32[] memory operatorIds - ) external view returns (uint32[] memory) { - return QuorumBitmapHistoryLib.getQuorumBitmapIndicesAtBlockNumber( - _operatorBitmapHistory, blockNumber, operatorIds - ); - } - - /** - * @notice Returns the quorum bitmap for the given `operatorId` at the given `blockNumber` via the `index`, - * reverting if `index` is incorrect - * @dev This function is meant to be used in concert with `getQuorumBitmapIndicesAtBlockNumber`, which - * helps off-chain processes to fetch the correct `index` input - */ - function getQuorumBitmapAtBlockNumberByIndex( - bytes32 operatorId, - uint32 blockNumber, - uint256 index - ) external view returns (uint192) { - return QuorumBitmapHistoryLib.getQuorumBitmapAtBlockNumberByIndex( - _operatorBitmapHistory, operatorId, blockNumber, index - ); - } - - /// @notice Returns the `index`th entry in the operator with `operatorId`'s bitmap history - function getQuorumBitmapUpdateByIndex( - bytes32 operatorId, - uint256 index - ) external view returns (QuorumBitmapUpdate memory) { - return _operatorBitmapHistory[operatorId][index]; - } - - /// @notice Returns the current quorum bitmap for the given `operatorId` or 0 if the operator is not registered for any quorum - function getCurrentQuorumBitmap( - bytes32 operatorId - ) external view returns (uint192) { - return _currentOperatorBitmap(operatorId); - } - - /// @notice Returns the length of the quorum bitmap history for the given `operatorId` - function getQuorumBitmapHistoryLength( - bytes32 operatorId - ) external view returns (uint256) { - return _operatorBitmapHistory[operatorId].length; - } - - /// @notice Returns the number of registries - function numRegistries() external view returns (uint256) { - return registries.length; - } - - /** - * @notice Public function for the the churnApprover signature hash calculation when operators are being kicked from quorums - * @param registeringOperatorId The id of the registering operator - * @param operatorKickParams The parameters needed to kick the operator from the quorums that have reached their caps - * @param salt The salt to use for the churnApprover's signature - * @param expiry The desired expiry time of the churnApprover's signature - */ - function calculateOperatorChurnApprovalDigestHash( - address registeringOperator, - bytes32 registeringOperatorId, - OperatorKickParam[] memory operatorKickParams, - bytes32 salt, - uint256 expiry - ) public view returns (bytes32) { - // calculate the digest hash - return _hashTypedDataV4( - keccak256( - abi.encode( - OPERATOR_CHURN_APPROVAL_TYPEHASH, - registeringOperator, - registeringOperatorId, - operatorKickParams, - salt, - expiry - ) - ) - ); - } - - /** - * @notice Returns the message hash that an operator must sign to register their BLS public key. - * @param operator is the address of the operator registering their BLS public key - */ - function pubkeyRegistrationMessageHash( - address operator - ) public view returns (BN254.G1Point memory) { - return BN254.hashToG1( - _hashTypedDataV4(keccak256(abi.encode(PUBKEY_REGISTRATION_TYPEHASH, operator))) - ); - } - - /// @dev need to override function here since its defined in both these contracts - function owner() - public - view - override(OwnableUpgradeable, IRegistryCoordinator) - returns (address) - { - return OwnableUpgradeable.owner(); + /// @dev Returns a bitmap with all bits set up to `quorumCount`. Used for bit-masking quorum numbers + /// and differentiating between operator sets and M2 quorums + function _getQuorumBitmap( + uint256 quorumCount + ) internal pure returns (uint256) { + // This creates a number where all bits up to quorumCount are set to 1 + // For example: + // quorumCount = 3 -> 0111 (7 in decimal) + // quorumCount = 5 -> 011111 (31 in decimal) + // This is a safe operation since we limit MAX_QUORUM_COUNT to 192 + return (1 << quorumCount) - 1; } } diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index 4c5866c4..88d3e8bd 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -7,15 +7,18 @@ import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSD import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; -import {IAllocationManager, IAllocationManagerTypes} from - "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IPermissionController} from "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; +import { + IAllocationManager, + IAllocationManagerTypes +} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IPermissionController} from + "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; import {IPermissionController} from "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; import {ServiceManagerBaseStorage} from "./ServiceManagerBaseStorage.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; -import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; import {BitmapUtils} from "./libraries/BitmapUtils.sol"; @@ -47,7 +50,7 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { constructor( IAVSDirectory __avsDirectory, IRewardsCoordinator __rewardsCoordinator, - IRegistryCoordinator __registryCoordinator, + ISlashingRegistryCoordinator __registryCoordinator, IStakeRegistry __stakeRegistry, IPermissionController __permissionController, IAllocationManager __allocationManager @@ -73,11 +76,10 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { } /// @inheritdoc IServiceManager - function addPendingAdmin(address admin) external onlyOwner { - _permissionController.addPendingAdmin({ - account: address(this), - admin: admin - }); + function addPendingAdmin( + address admin + ) external onlyOwner { + _permissionController.addPendingAdmin({account: address(this), admin: admin}); } /// @inheritdoc IServiceManager @@ -181,7 +183,10 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { _avsDirectory.deregisterOperatorFromAVS(operator); } - function deregisterOperatorFromOperatorSets(address operator, uint32[] memory operatorSetIds) public virtual onlyRegistryCoordinator { + function deregisterOperatorFromOperatorSets( + address operator, + uint32[] memory operatorSetIds + ) public virtual onlyRegistryCoordinator { IAllocationManager.DeregisterParams memory params = IAllocationManagerTypes.DeregisterParams({ operator: operator, avs: address(this), diff --git a/src/ServiceManagerBaseStorage.sol b/src/ServiceManagerBaseStorage.sol index ca548ea2..e3e25f58 100644 --- a/src/ServiceManagerBaseStorage.sol +++ b/src/ServiceManagerBaseStorage.sol @@ -4,14 +4,18 @@ pragma solidity ^0.8.27; import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; -import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; -import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; -import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IPermissionController} from "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; +import {IAllocationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IRewardsCoordinator} from + "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import {IAllocationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IPermissionController} from + "eigenlayer-contracts/src/contracts/interfaces/IPermissionController.sol"; /** * @title Storage variables for the `ServiceManagerBase` contract. @@ -27,7 +31,7 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab IAVSDirectory internal immutable _avsDirectory; IAllocationManager internal immutable _allocationManager; IRewardsCoordinator internal immutable _rewardsCoordinator; - IRegistryCoordinator internal immutable _registryCoordinator; + ISlashingRegistryCoordinator internal immutable _registryCoordinator; IStakeRegistry internal immutable _stakeRegistry; IPermissionController internal immutable _permissionController; @@ -56,7 +60,7 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab constructor( IAVSDirectory __avsDirectory, IRewardsCoordinator __rewardsCoordinator, - IRegistryCoordinator __registryCoordinator, + ISlashingRegistryCoordinator __registryCoordinator, IStakeRegistry __stakeRegistry, IPermissionController __permissionController, IAllocationManager __allocationManager diff --git a/src/SlashingRegistryCoordinator.sol b/src/SlashingRegistryCoordinator.sol new file mode 100644 index 00000000..605c4285 --- /dev/null +++ b/src/SlashingRegistryCoordinator.sol @@ -0,0 +1,1122 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; +import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; +import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; +import { + IAllocationManager, + OperatorSet, + IAllocationManagerTypes +} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {ISocketUpdater} from "./interfaces/ISocketUpdater.sol"; +import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; +import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; +import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; + +import {BitmapUtils} from "./libraries/BitmapUtils.sol"; +import {BN254} from "./libraries/BN254.sol"; +import {SignatureCheckerLib} from "./libraries/SignatureCheckerLib.sol"; +import {QuorumBitmapHistoryLib} from "./libraries/QuorumBitmapHistoryLib.sol"; + +import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; +import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; +import {EIP712} from "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol"; + +import {Pausable} from "eigenlayer-contracts/src/contracts/permissions/Pausable.sol"; +import {SlashingRegistryCoordinatorStorage} from "./SlashingRegistryCoordinatorStorage.sol"; +import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; + +/** + * @title A `RegistryCoordinator` that has three registries: + * 1) a `StakeRegistry` that keeps track of operators' stakes + * 2) a `BLSApkRegistry` that keeps track of operators' BLS public keys and aggregate BLS public keys for each quorum + * 3) an `IndexRegistry` that keeps track of an ordered list of operators for each quorum + * + * @author Layr Labs, Inc. + */ +contract SlashingRegistryCoordinator is + EIP712, + Initializable, + Pausable, + OwnableUpgradeable, + SlashingRegistryCoordinatorStorage, + IAVSRegistrar, + ISocketUpdater, + ISignatureUtils +{ + using BitmapUtils for *; + using BN254 for BN254.G1Point; + + modifier onlyAllocationManager() { + _checkAllocationManager(); + _; + } + + modifier onlyEjector() { + _checkEjector(); + _; + } + + /// @dev Checks that `quorumNumber` corresponds to a quorum that has been created + /// via `initialize` or `createQuorum` + modifier quorumExists( + uint8 quorumNumber + ) { + _checkQuorumExists(quorumNumber); + _; + } + + constructor( + IStakeRegistry _stakeRegistry, + IBLSApkRegistry _blsApkRegistry, + IIndexRegistry _indexRegistry, + IAllocationManager _allocationManager, + IPauserRegistry _pauserRegistry + ) + SlashingRegistryCoordinatorStorage( + _stakeRegistry, + _blsApkRegistry, + _indexRegistry, + _allocationManager + ) + EIP712("AVSRegistryCoordinator", "v0.0.1") + Pausable(_pauserRegistry) + { + _disableInitializers(); + } + + /** + * + * EXTERNAL FUNCTIONS + * + */ + function initialize( + address _initialOwner, + address _churnApprover, + address _ejector, + uint256 _initialPausedStatus, + address _accountIdentifier + ) external initializer { + _transferOwnership(_initialOwner); + _setChurnApprover(_churnApprover); + _setPausedStatus(_initialPausedStatus); + _setEjector(_ejector); + _setAccountIdentifier(_accountIdentifier); + // Add registry contracts to the registries array + registries.push(address(stakeRegistry)); + registries.push(address(blsApkRegistry)); + registries.push(address(indexRegistry)); + + // Set the AVS to be OperatorSets compatible + operatorSetsEnabled = true; + + // Set the AVS to not accept M2 quorums + m2QuorumsDisabled = true; + } + + /** + * @notice Creates a quorum and initializes it in each registry contract + * @param operatorSetParams configures the quorum's max operator count and churn parameters + * @param minimumStake sets the minimum stake required for an operator to register or remain + * registered + * @param strategyParams a list of strategies and multipliers used by the StakeRegistry to + * calculate an operator's stake weight for the quorum + * @dev For m2 AVS this function has the same behavior as createQuorum before + * For migrated AVS that enable operator sets this will create a quorum that measures total delegated stake for operator set + * + */ + function createTotalDelegatedStakeQuorum( + OperatorSetParam memory operatorSetParams, + uint96 minimumStake, + IStakeRegistry.StrategyParams[] memory strategyParams + ) external virtual onlyOwner { + _createQuorum(operatorSetParams, minimumStake, strategyParams, StakeType.TOTAL_DELEGATED, 0); + } + + function createSlashableStakeQuorum( + OperatorSetParam memory operatorSetParams, + uint96 minimumStake, + IStakeRegistry.StrategyParams[] memory strategyParams, + uint32 lookAheadPeriod + ) external virtual onlyOwner { + require(operatorSetsEnabled, OperatorSetsNotEnabled()); + _createQuorum( + operatorSetParams, + minimumStake, + strategyParams, + StakeType.TOTAL_SLASHABLE, + lookAheadPeriod + ); + } + + function registerOperator( + address operator, + uint32[] memory operatorSetIds, + bytes calldata data + ) external override onlyAllocationManager onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { + require(operatorSetsEnabled, OperatorSetsNotEnabled()); + bytes memory quorumNumbers = _getQuorumNumbers(operatorSetIds); + + ( + RegistrationType registrationType, + string memory socket, + IBLSApkRegistry.PubkeyRegistrationParams memory params + ) = abi.decode(data, (RegistrationType, string, IBLSApkRegistry.PubkeyRegistrationParams)); + + /** + * If the operator has NEVER registered a pubkey before, use `params` to register + * their pubkey in blsApkRegistry + * + * If the operator HAS registered a pubkey, `params` is ignored and the pubkey hash + * (operatorId) is fetched instead + */ + bytes32 operatorId = _getOrCreateOperatorId(operator, params); + + if (registrationType == RegistrationType.NORMAL) { + uint32[] memory numOperatorsPerQuorum = _registerOperator({ + operator: operator, + operatorId: operatorId, + quorumNumbers: quorumNumbers, + socket: socket + }).numOperatorsPerQuorum; + + // For each quorum, validate that the new operator count does not exceed the maximum + // (If it does, an operator needs to be replaced -- see `registerOperatorWithChurn`) + for (uint256 i = 0; i < quorumNumbers.length; i++) { + uint8 quorumNumber = uint8(quorumNumbers[i]); + + require( + numOperatorsPerQuorum[i] <= _quorumParams[quorumNumber].maxOperatorCount, + MaxQuorumsReached() + ); + } + } else if (registrationType == RegistrationType.CHURN) { + // Decode registration data from bytes + ( + , + , + , + OperatorKickParam[] memory operatorKickParams, + SignatureWithSaltAndExpiry memory churnApproverSignature + ) = abi.decode( + data, + ( + RegistrationType, + string, + IBLSApkRegistry.PubkeyRegistrationParams, + OperatorKickParam[], + SignatureWithSaltAndExpiry + ) + ); + _registerOperatorWithChurn({ + operator: operator, + operatorId: operatorId, + quorumNumbers: quorumNumbers, + socket: socket, + operatorKickParams: operatorKickParams, + churnApproverSignature: churnApproverSignature + }); + } else { + revert InvalidRegistrationType(); + } + + // If the operator wasn't registered for any quorums, update their status + // and register them with this AVS in EigenLayer core (DelegationManager) + if (_operatorInfo[operator].status != OperatorStatus.REGISTERED) { + _operatorInfo[operator] = OperatorInfo(operatorId, OperatorStatus.REGISTERED); + emit OperatorRegistered(operator, operatorId); + } + } + + function deregisterOperator( + address operator, + uint32[] memory operatorSetIds + ) external override onlyAllocationManager onlyWhenNotPaused(PAUSED_DEREGISTER_OPERATOR) { + require(operatorSetsEnabled, OperatorSetsNotEnabled()); + bytes memory quorumNumbers = _getQuorumNumbers(operatorSetIds); + _deregisterOperator(operator, quorumNumbers); + } + + /** + * @notice Updates the StakeRegistry's view of one or more operators' stakes. If any operator + * is found to be below the minimum stake for the quorum, they are deregistered. + * @dev stakes are queried from the Eigenlayer core DelegationManager contract + * @param operators a list of operator addresses to update + */ + function updateOperators( + address[] memory operators + ) external onlyWhenNotPaused(PAUSED_UPDATE_OPERATOR) { + for (uint256 i = 0; i < operators.length; i++) { + address operator = operators[i]; + OperatorInfo memory operatorInfo = _operatorInfo[operator]; + bytes32 operatorId = operatorInfo.operatorId; + + // Update the operator's stake for their active quorums + uint192 currentBitmap = _currentOperatorBitmap(operatorId); + bytes memory quorumsToUpdate = BitmapUtils.bitmapToBytesArray(currentBitmap); + _updateOperator(operator, operatorInfo, quorumsToUpdate); + } + } + + /** + * @notice For each quorum in `quorumNumbers`, updates the StakeRegistry's view of ALL its registered operators' stakes. + * Each quorum's `quorumUpdateBlockNumber` is also updated, which tracks the most recent block number when ALL registered + * operators were updated. + * @dev stakes are queried from the Eigenlayer core DelegationManager contract + * @param operatorsPerQuorum for each quorum in `quorumNumbers`, this has a corresponding list of operators to update. + * @dev Each list of operator addresses MUST be sorted in ascending order + * @dev Each list of operator addresses MUST represent the entire list of registered operators for the corresponding quorum + * @param quorumNumbers is an ordered byte array containing the quorum numbers being updated + * @dev invariant: Each list of `operatorsPerQuorum` MUST be a sorted version of `IndexRegistry.getOperatorListAtBlockNumber` + * for the corresponding quorum. + * @dev note on race condition: if an operator registers/deregisters for any quorum in `quorumNumbers` after a txn to + * this method is broadcast (but before it is executed), the method will fail + */ + function updateOperatorsForQuorum( + address[][] memory operatorsPerQuorum, + bytes calldata quorumNumbers + ) external onlyWhenNotPaused(PAUSED_UPDATE_OPERATOR) { + // Input validation + // - all quorums should exist (checked against `quorumCount` in orderedBytesArrayToBitmap) + // - there should be no duplicates in `quorumNumbers` + // - there should be one list of operators per quorum + BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount); + require(operatorsPerQuorum.length == quorumNumbers.length, InputLengthMismatch()); + + // For each quorum, update ALL registered operators + for (uint256 i = 0; i < quorumNumbers.length; ++i) { + uint8 quorumNumber = uint8(quorumNumbers[i]); + + // Ensure we've passed in the correct number of operators for this quorum + address[] memory currQuorumOperators = operatorsPerQuorum[i]; + require( + currQuorumOperators.length == indexRegistry.totalOperatorsForQuorum(quorumNumber), + QuorumOperatorCountMismatch() + ); + + address prevOperatorAddress = address(0); + // For each operator: + // - check that they are registered for this quorum + // - check that their address is strictly greater than the last operator + // ... then, update their stakes + for (uint256 j = 0; j < currQuorumOperators.length; ++j) { + address operator = currQuorumOperators[j]; + + OperatorInfo memory operatorInfo = _operatorInfo[operator]; + bytes32 operatorId = operatorInfo.operatorId; + + { + uint192 currentBitmap = _currentOperatorBitmap(operatorId); + // Check that the operator is registered + require( + BitmapUtils.isSet(currentBitmap, quorumNumber), NotRegisteredForQuorum() + ); + // Prevent duplicate operators + require(operator > prevOperatorAddress, NotSorted()); + } + + // Update the operator + _updateOperator(operator, operatorInfo, quorumNumbers[i:i + 1]); + prevOperatorAddress = operator; + } + + // Update timestamp that all operators in quorum have been updated all at once + quorumUpdateBlockNumber[quorumNumber] = block.number; + emit QuorumBlockNumberUpdated(quorumNumber, block.number); + } + } + + /** + * @notice Updates the socket of the msg.sender given they are a registered operator + * @param socket is the new socket of the operator + */ + function updateSocket( + string memory socket + ) external { + require(_operatorInfo[msg.sender].status == OperatorStatus.REGISTERED, NotRegistered()); + emit OperatorSocketUpdate(_operatorInfo[msg.sender].operatorId, socket); + } + + /** + * + * EXTERNAL FUNCTIONS - EJECTOR + * + */ + + /** + * @notice Forcibly deregisters an operator from one or more quorums + * @param operator the operator to eject + * @param quorumNumbers the quorum numbers to eject the operator from + * @dev possible race condition if prior to being ejected for a set of quorums the operator self deregisters from a subset + */ + function ejectOperator(address operator, bytes memory quorumNumbers) external onlyEjector { + lastEjectionTimestamp[operator] = block.timestamp; + + OperatorInfo storage operatorInfo = _operatorInfo[operator]; + bytes32 operatorId = operatorInfo.operatorId; + uint192 quorumsToRemove = + uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); + uint192 currentBitmap = _currentOperatorBitmap(operatorId); + if ( + operatorInfo.status == OperatorStatus.REGISTERED && !quorumsToRemove.isEmpty() + && quorumsToRemove.isSubsetOf(currentBitmap) + ) { + _deregisterOperator({operator: operator, quorumNumbers: quorumNumbers}); + + if (operatorSetsEnabled) { + _forceDeregisterOperator(operator, quorumNumbers); + } + } + } + + /** + * + * EXTERNAL FUNCTIONS - OWNER + * + */ + + /** + * @notice Updates an existing quorum's configuration with a new max operator count + * and operator churn parameters + * @param quorumNumber the quorum number to update + * @param operatorSetParams the new config + * @dev only callable by the owner + */ + function setOperatorSetParams( + uint8 quorumNumber, + OperatorSetParam memory operatorSetParams + ) external onlyOwner quorumExists(quorumNumber) { + _setOperatorSetParams(quorumNumber, operatorSetParams); + } + + /** + * @notice Sets the churnApprover, which approves operator registration with churn + * (see `registerOperatorWithChurn`) + * @param _churnApprover the new churn approver + * @dev only callable by the owner + */ + function setChurnApprover( + address _churnApprover + ) external onlyOwner { + _setChurnApprover(_churnApprover); + } + + /** + * @notice Sets the ejector, which can force-deregister operators from quorums + * @param _ejector the new ejector + * @dev only callable by the owner + */ + function setEjector( + address _ejector + ) external onlyOwner { + _setEjector(_ejector); + } + + /** + * @notice Sets the account identifier for this AVS (used for UAM integration in EigenLayer) + * @param _accountIdentifier the new account identifier + * @dev only callable by the owner + */ + function setAccountIdentifier( + address _accountIdentifier + ) external onlyOwner { + _setAccountIdentifier(_accountIdentifier); + } + + /** + * @notice Sets the ejection cooldown, which is the time an operator must wait in + * seconds afer ejection before registering for any quorum + * @param _ejectionCooldown the new ejection cooldown in seconds + * @dev only callable by the owner + */ + function setEjectionCooldown( + uint256 _ejectionCooldown + ) external onlyOwner { + ejectionCooldown = _ejectionCooldown; + } + + /** + * + * INTERNAL FUNCTIONS + * + */ + + /** + * @notice Register the operator for one or more quorums. This method updates the + * operator's quorum bitmap, socket, and status, then registers them with each registry. + */ + function _registerOperator( + address operator, + bytes32 operatorId, + bytes memory quorumNumbers, + string memory socket + ) internal virtual returns (RegisterResults memory results) { + /** + * Get bitmap of quorums to register for and operator's current bitmap. Validate that: + * - we're trying to register for at least 1 quorum + * - the quorums we're registering for exist (checked against `quorumCount` in orderedBytesArrayToBitmap) + * - the operator is not currently registered for any quorums we're registering for + * Then, calculate the operator's new bitmap after registration + */ + uint192 quorumsToAdd = + uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); + uint192 currentBitmap = _currentOperatorBitmap(operatorId); + + // call hook to allow for any pre-register logic + _beforeRegisterOperator(operator, operatorId, quorumNumbers, currentBitmap); + + require(!quorumsToAdd.isEmpty(), BitmapEmpty()); + require(quorumsToAdd.noBitsInCommon(currentBitmap), AlreadyRegisteredForQuorums()); + uint192 newBitmap = uint192(currentBitmap.plus(quorumsToAdd)); + + // Check that the operator can reregister if ejected + require( + lastEjectionTimestamp[operator] + ejectionCooldown < block.timestamp, + CannotReregisterYet() + ); + + /** + * Update operator's bitmap, socket, and status. Only update operatorInfo if needed: + * if we're `REGISTERED`, the operatorId and status are already correct. + */ + _updateOperatorBitmap({operatorId: operatorId, newBitmap: newBitmap}); + + emit OperatorSocketUpdate(operatorId, socket); + + // Register the operator with the BLSApkRegistry, StakeRegistry, and IndexRegistry + blsApkRegistry.registerOperator(operator, quorumNumbers); + (results.operatorStakes, results.totalStakes) = + stakeRegistry.registerOperator(operator, operatorId, quorumNumbers); + results.numOperatorsPerQuorum = indexRegistry.registerOperator(operatorId, quorumNumbers); + + // call hook to allow for any post-register logic + _afterRegisterOperator(operator, operatorId, quorumNumbers, newBitmap); + + return results; + } + + function _registerOperatorWithChurn( + address operator, + bytes32 operatorId, + bytes memory quorumNumbers, + string memory socket, + OperatorKickParam[] memory operatorKickParams, + SignatureWithSaltAndExpiry memory churnApproverSignature + ) internal virtual { + require(operatorKickParams.length == quorumNumbers.length, InputLengthMismatch()); + + // Verify the churn approver's signature for the registering operator and kick params + _verifyChurnApproverSignature({ + registeringOperator: operator, + registeringOperatorId: operatorId, + operatorKickParams: operatorKickParams, + churnApproverSignature: churnApproverSignature + }); + + // Register the operator in each of the registry contracts and update the operator's + // quorum bitmap and registration status + RegisterResults memory results = + _registerOperator(operator, operatorId, quorumNumbers, socket); + + // Check that each quorum's operator count is below the configured maximum. If the max + // is exceeded, use `operatorKickParams` to deregister an existing operator to make space + for (uint256 i = 0; i < quorumNumbers.length; i++) { + OperatorSetParam memory operatorSetParams = _quorumParams[uint8(quorumNumbers[i])]; + + /** + * If the new operator count for any quorum exceeds the maximum, validate + * that churn can be performed, then deregister the specified operator + */ + if (results.numOperatorsPerQuorum[i] > operatorSetParams.maxOperatorCount) { + _validateChurn({ + quorumNumber: uint8(quorumNumbers[i]), + totalQuorumStake: results.totalStakes[i], + newOperator: operator, + newOperatorStake: results.operatorStakes[i], + kickParams: operatorKickParams[i], + setParams: operatorSetParams + }); + + bytes memory singleQuorumNumber = new bytes(1); + singleQuorumNumber[0] = quorumNumbers[i]; + _deregisterOperator(operatorKickParams[i].operator, singleQuorumNumber); + + if (operatorSetsEnabled) { + _forceDeregisterOperator(operatorKickParams[i].operator, singleQuorumNumber); + } + } + } + } + + /** + * @dev Deregister the operator from one or more quorums + * This method updates the operator's quorum bitmap and status, then deregisters + * the operator with the BLSApkRegistry, IndexRegistry, and StakeRegistry + */ + function _deregisterOperator(address operator, bytes memory quorumNumbers) internal virtual { + // Fetch the operator's info and ensure they are registered + OperatorInfo storage operatorInfo = _operatorInfo[operator]; + bytes32 operatorId = operatorInfo.operatorId; + uint192 currentBitmap = _currentOperatorBitmap(operatorId); + + // call hook to allow for any pre-deregister logic + _beforeDeregisterOperator(operator, operatorId, quorumNumbers, currentBitmap); + + require(operatorInfo.status == OperatorStatus.REGISTERED, NotRegistered()); + + /** + * Get bitmap of quorums to deregister from and operator's current bitmap. Validate that: + * - we're trying to deregister from at least 1 quorum + * - the quorums we're deregistering from exist (checked against `quorumCount` in orderedBytesArrayToBitmap) + * - the operator is currently registered for any quorums we're trying to deregister from + * Then, calculate the operator's new bitmap after deregistration + */ + uint192 quorumsToRemove = + uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); + require(!quorumsToRemove.isEmpty(), BitmapCannotBeZero()); + require(quorumsToRemove.isSubsetOf(currentBitmap), NotRegisteredForQuorum()); + uint192 newBitmap = uint192(currentBitmap.minus(quorumsToRemove)); + + // Update operator's bitmap and status + _updateOperatorBitmap({operatorId: operatorId, newBitmap: newBitmap}); + + // If the operator is no longer registered for any quorums, update their status and deregister + // them from the AVS via the EigenLayer core contracts + if (newBitmap.isEmpty()) { + _operatorInfo[operator].status = OperatorStatus.DEREGISTERED; + emit OperatorDeregistered(operator, operatorId); + } + + // Deregister operator with each of the registry contracts + blsApkRegistry.deregisterOperator(operator, quorumNumbers); + stakeRegistry.deregisterOperator(operatorId, quorumNumbers); + indexRegistry.deregisterOperator(operatorId, quorumNumbers); + + // call hook to allow for any post-deregister logic + _afterDeregisterOperator(operator, operatorId, quorumNumbers, newBitmap); + } + + /** + * @notice Helper function to handle operator set deregistration for OperatorSets quorums. This is used + * when an operator is force-deregistered from a set of quorums. For any of the quorums that are + * OperatorSets quorums, we need to deregister the operator in the AllocationManager. + * @param operator The operator to deregister + * @param quorumNumbers The quorum numbers the operator is force-deregistered from + */ + function _forceDeregisterOperator(address operator, bytes memory quorumNumbers) internal { + uint32[] memory operatorSetIds = new uint32[](quorumNumbers.length); + uint256 numOperatorSetQuorums; + + // Check each quorum's stake type + for (uint256 i = 0; i < quorumNumbers.length; i++) { + uint8 quorumNumber = uint8(quorumNumbers[i]); + if (_isM2Quorum(quorumNumber)) { + operatorSetIds[numOperatorSetQuorums++] = quorumNumber; + } + } + + // If any OperatorSet quorums found, deregister from AVS in the AllocationManager + if (numOperatorSetQuorums > 0) { + // Resize array to exact size needed + assembly { + mstore(operatorSetIds, numOperatorSetQuorums) + } + allocationManager.deregisterFromOperatorSets( + IAllocationManagerTypes.DeregisterParams({ + operator: operator, + avs: accountIdentifier, + operatorSetIds: operatorSetIds + }) + ); + } + } + + /** + * @notice Checks if the caller is the ejector + * @dev Reverts if the caller is not the ejector + */ + function _checkEjector() internal view { + require(msg.sender == ejector, OnlyEjector()); + } + + function _checkAllocationManager() internal view { + require(msg.sender == address(allocationManager), OnlyAllocationManager()); + } + + /** + * @notice Checks if a quorum exists + * @param quorumNumber The quorum number to check + * @dev Reverts if the quorum does not exist + */ + function _checkQuorumExists( + uint8 quorumNumber + ) internal view { + require(quorumNumber < quorumCount, QuorumDoesNotExist()); + } + + /** + * @notice Fetches an operator's pubkey hash from the BLSApkRegistry. If the + * operator has not registered a pubkey, attempts to register a pubkey using + * `params` + * @param operator the operator whose pubkey to query from the BLSApkRegistry + * @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership + * @dev `params` can be empty if the operator has already registered a pubkey in the BLSApkRegistry + */ + function _getOrCreateOperatorId( + address operator, + IBLSApkRegistry.PubkeyRegistrationParams memory params + ) internal returns (bytes32 operatorId) { + operatorId = blsApkRegistry.getOperatorId(operator); + if (operatorId == 0) { + operatorId = blsApkRegistry.registerBLSPublicKey( + operator, params, pubkeyRegistrationMessageHash(operator) + ); + } + return operatorId; + } + + /** + * @notice Validates that an incoming operator is eligible to replace an existing + * operator based on the stake of both + * @dev In order to churn, the incoming operator needs to have more stake than the + * existing operator by a proportion given by `kickBIPsOfOperatorStake` + * @dev In order to be churned out, the existing operator needs to have a proportion + * of the total quorum stake less than `kickBIPsOfTotalStake` + * @param quorumNumber `newOperator` is trying to replace an operator in this quorum + * @param totalQuorumStake the total stake of all operators in the quorum, after the + * `newOperator` registers + * @param newOperator the incoming operator + * @param newOperatorStake the incoming operator's stake + * @param kickParams the quorum number and existing operator to replace + * @dev the existing operator's registration to this quorum isn't checked here, but + * if we attempt to deregister them, this will be checked in `_deregisterOperator` + * @param setParams config for this quorum containing `kickBIPsX` stake proportions + * mentioned above + */ + function _validateChurn( + uint8 quorumNumber, + uint96 totalQuorumStake, + address newOperator, + uint96 newOperatorStake, + OperatorKickParam memory kickParams, + OperatorSetParam memory setParams + ) internal view { + address operatorToKick = kickParams.operator; + bytes32 idToKick = _operatorInfo[operatorToKick].operatorId; + require(newOperator != operatorToKick, CannotChurnSelf()); + require(kickParams.quorumNumber == quorumNumber, QuorumOperatorCountMismatch()); + + // Get the target operator's stake and check that it is below the kick thresholds + uint96 operatorToKickStake = stakeRegistry.getCurrentStake(idToKick, quorumNumber); + require( + newOperatorStake > _individualKickThreshold(operatorToKickStake, setParams), + InsufficientStakeForChurn() + ); + require( + operatorToKickStake < _totalKickThreshold(totalQuorumStake, setParams), + CannotKickOperatorAboveThreshold() + ); + } + + /** + * @notice Updates the StakeRegistry's view of the operator's stake in one or more quorums. + * For any quorums where the StakeRegistry finds the operator is under the configured minimum + * stake, `quorumsToRemove` is returned and used to deregister the operator from those quorums + * @dev does nothing if operator is not registered for any quorums. + */ + function _updateOperator( + address operator, + OperatorInfo memory operatorInfo, + bytes memory quorumsToUpdate + ) internal { + if (operatorInfo.status != OperatorStatus.REGISTERED) { + return; + } + bytes32 operatorId = operatorInfo.operatorId; + uint192 quorumsToRemove = + stakeRegistry.updateOperatorStake(operator, operatorId, quorumsToUpdate); + + if (!quorumsToRemove.isEmpty()) { + _deregisterOperator({ + operator: operator, + quorumNumbers: BitmapUtils.bitmapToBytesArray(quorumsToRemove) + }); + } + } + + /** + * @notice Returns the stake threshold required for an incoming operator to replace an existing operator + * The incoming operator must have more stake than the return value. + */ + function _individualKickThreshold( + uint96 operatorStake, + OperatorSetParam memory setParams + ) internal pure returns (uint96) { + return operatorStake * setParams.kickBIPsOfOperatorStake / BIPS_DENOMINATOR; + } + + /** + * @notice Returns the total stake threshold required for an operator to remain in a quorum. + * The operator must have at least the returned stake amount to keep their position. + */ + function _totalKickThreshold( + uint96 totalStake, + OperatorSetParam memory setParams + ) internal pure returns (uint96) { + return totalStake * setParams.kickBIPsOfTotalStake / BIPS_DENOMINATOR; + } + + /// @notice verifies churnApprover's signature on operator churn approval and increments the churnApprover nonce + function _verifyChurnApproverSignature( + address registeringOperator, + bytes32 registeringOperatorId, + OperatorKickParam[] memory operatorKickParams, + SignatureWithSaltAndExpiry memory churnApproverSignature + ) internal { + // make sure the salt hasn't been used already + require(!isChurnApproverSaltUsed[churnApproverSignature.salt], ChurnApproverSaltUsed()); + require(churnApproverSignature.expiry >= block.timestamp, SignatureExpired()); + + // set salt used to true + isChurnApproverSaltUsed[churnApproverSignature.salt] = true; + + // check the churnApprover's signature + SignatureCheckerLib.isValidSignature( + churnApprover, + calculateOperatorChurnApprovalDigestHash( + registeringOperator, + registeringOperatorId, + operatorKickParams, + churnApproverSignature.salt, + churnApproverSignature.expiry + ), + churnApproverSignature.signature + ); + } + + /** + * @notice Creates a quorum and initializes it in each registry contract + * @param operatorSetParams configures the quorum's max operator count and churn parameters + * @param minimumStake sets the minimum stake required for an operator to register or remain + * registered + * @param strategyParams a list of strategies and multipliers used by the StakeRegistry to + * calculate an operator's stake weight for the quorum + */ + function _createQuorum( + OperatorSetParam memory operatorSetParams, + uint96 minimumStake, + IStakeRegistry.StrategyParams[] memory strategyParams, + StakeType stakeType, + uint32 lookAheadPeriod + ) internal { + // Increment the total quorum count. Fails if we're already at the max + uint8 prevQuorumCount = quorumCount; + require(prevQuorumCount < MAX_QUORUM_COUNT, MaxQuorumsReached()); + quorumCount = prevQuorumCount + 1; + + // The previous count is the new quorum's number + uint8 quorumNumber = prevQuorumCount; + + // Initialize the quorum here and in each registry + _setOperatorSetParams(quorumNumber, operatorSetParams); + + /// Update the AllocationManager if operatorSetQuorum + if (operatorSetsEnabled && !_isM2Quorum(quorumNumber)) { + // Create array of CreateSetParams for the new quorum + IAllocationManagerTypes.CreateSetParams[] memory createSetParams = + new IAllocationManagerTypes.CreateSetParams[](1); + + // Extract strategies from strategyParams + IStrategy[] memory strategies = new IStrategy[](strategyParams.length); + for (uint256 i = 0; i < strategyParams.length; i++) { + strategies[i] = strategyParams[i].strategy; + } + + // Initialize CreateSetParams with quorumNumber as operatorSetId + createSetParams[0] = IAllocationManagerTypes.CreateSetParams({ + operatorSetId: quorumNumber, + strategies: strategies + }); + allocationManager.createOperatorSets({avs: accountIdentifier, params: createSetParams}); + } + // Initialize stake registry based on stake type + if (stakeType == StakeType.TOTAL_DELEGATED) { + stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); + } else if (stakeType == StakeType.TOTAL_SLASHABLE) { + stakeRegistry.initializeSlashableStakeQuorum( + quorumNumber, minimumStake, lookAheadPeriod, strategyParams + ); + } + + indexRegistry.initializeQuorum(quorumNumber); + blsApkRegistry.initializeQuorum(quorumNumber); + } + + /** + * @notice Record an update to an operator's quorum bitmap. + * @param newBitmap is the most up-to-date set of bitmaps the operator is registered for + */ + function _updateOperatorBitmap(bytes32 operatorId, uint192 newBitmap) internal { + QuorumBitmapHistoryLib.updateOperatorBitmap(_operatorBitmapHistory, operatorId, newBitmap); + } + + /// @notice Get the most recent bitmap for the operator, returning an empty bitmap if + /// the operator is not registered. + function _currentOperatorBitmap( + bytes32 operatorId + ) internal view returns (uint192) { + return QuorumBitmapHistoryLib.currentOperatorBitmap(_operatorBitmapHistory, operatorId); + } + + /** + * @notice Returns the index of the quorumBitmap for the provided `operatorId` at the given `blockNumber` + * @dev Reverts if the operator had not yet (ever) registered at `blockNumber` + * @dev This function is designed to find proper inputs to the `getQuorumBitmapAtBlockNumberByIndex` function + */ + function _getQuorumBitmapIndexAtBlockNumber( + uint32 blockNumber, + bytes32 operatorId + ) internal view returns (uint32 index) { + return QuorumBitmapHistoryLib.getQuorumBitmapIndexAtBlockNumber( + _operatorBitmapHistory, blockNumber, operatorId + ); + } + + /// @notice Returns the quorum numbers for the provided `OperatorSetIds` + /// OperatorSetIds are used in the AllocationManager to identify operator sets for a given AVS + function _getQuorumNumbers( + uint32[] memory operatorSetIds + ) internal pure returns (bytes memory) { + bytes memory quorumNumbers = new bytes(operatorSetIds.length); + for (uint256 i = 0; i < operatorSetIds.length; i++) { + quorumNumbers[i] = bytes1(uint8(operatorSetIds[i])); + } + return quorumNumbers; + } + + /// @notice Returns true if the quorum number is an M2 quorum + /// @dev We use bitwise and to check if the quorum number is an M2 quorum + function _isM2Quorum( + uint8 quorumNumber + ) internal view returns (bool) { + return M2quorumBitmap.isSet(quorumNumber); + } + + function _setOperatorSetParams( + uint8 quorumNumber, + OperatorSetParam memory operatorSetParams + ) internal { + _quorumParams[quorumNumber] = operatorSetParams; + emit OperatorSetParamsUpdated(quorumNumber, operatorSetParams); + } + + function _setChurnApprover( + address newChurnApprover + ) internal { + emit ChurnApproverUpdated(churnApprover, newChurnApprover); + churnApprover = newChurnApprover; + } + + function _setEjector( + address newEjector + ) internal { + emit EjectorUpdated(ejector, newEjector); + ejector = newEjector; + } + + function _setAccountIdentifier( + address _accountIdentifier + ) internal { + accountIdentifier = _accountIdentifier; + } + + /// @dev Hook to allow for any pre-register logic in `_registerOperator` + function _beforeRegisterOperator( + address operator, + bytes32 operatorId, + bytes memory quorumNumbers, + uint192 currentBitmap + ) internal virtual {} + + /// @dev Hook to allow for any post-register logic in `_registerOperator` + function _afterRegisterOperator( + address operator, + bytes32 operatorId, + bytes memory quorumNumbers, + uint192 newBitmap + ) internal virtual {} + + /// @dev Hook to allow for any pre-deregister logic in `_deregisterOperator` + function _beforeDeregisterOperator( + address operator, + bytes32 operatorId, + bytes memory quorumNumbers, + uint192 currentBitmap + ) internal virtual {} + + /// @dev Hook to allow for any post-deregister logic in `_deregisterOperator` + function _afterDeregisterOperator( + address operator, + bytes32 operatorId, + bytes memory quorumNumbers, + uint192 newBitmap + ) internal virtual {} + + /** + * + * VIEW FUNCTIONS + * + */ + + /// @notice Returns the operator set params for the given `quorumNumber` + function getOperatorSetParams( + uint8 quorumNumber + ) external view returns (OperatorSetParam memory) { + return _quorumParams[quorumNumber]; + } + + /// @notice Returns the operator struct for the given `operator` + function getOperator( + address operator + ) external view returns (OperatorInfo memory) { + return _operatorInfo[operator]; + } + + /// @notice Returns the operatorId for the given `operator` + function getOperatorId( + address operator + ) external view returns (bytes32) { + return _operatorInfo[operator].operatorId; + } + + /// @notice Returns the operator address for the given `operatorId` + function getOperatorFromId( + bytes32 operatorId + ) external view returns (address) { + return blsApkRegistry.getOperatorFromPubkeyHash(operatorId); + } + + /// @notice Returns the status for the given `operator` + function getOperatorStatus( + address operator + ) external view returns (ISlashingRegistryCoordinator.OperatorStatus) { + return _operatorInfo[operator].status; + } + + /// @notice Returns true if the quorum number is an M2 quorum + function isM2Quorum( + uint8 quorumNumber + ) external view returns (bool) { + return _isM2Quorum(quorumNumber); + } + + /** + * @notice Returns the indices of the quorumBitmaps for the provided `operatorIds` at the given `blockNumber` + * @dev Reverts if any of the `operatorIds` was not (yet) registered at `blockNumber` + * @dev This function is designed to find proper inputs to the `getQuorumBitmapAtBlockNumberByIndex` function + */ + function getQuorumBitmapIndicesAtBlockNumber( + uint32 blockNumber, + bytes32[] memory operatorIds + ) external view returns (uint32[] memory) { + return QuorumBitmapHistoryLib.getQuorumBitmapIndicesAtBlockNumber( + _operatorBitmapHistory, blockNumber, operatorIds + ); + } + + /** + * @notice Returns the quorum bitmap for the given `operatorId` at the given `blockNumber` via the `index`, + * reverting if `index` is incorrect + * @dev This function is meant to be used in concert with `getQuorumBitmapIndicesAtBlockNumber`, which + * helps off-chain processes to fetch the correct `index` input + */ + function getQuorumBitmapAtBlockNumberByIndex( + bytes32 operatorId, + uint32 blockNumber, + uint256 index + ) external view returns (uint192) { + return QuorumBitmapHistoryLib.getQuorumBitmapAtBlockNumberByIndex( + _operatorBitmapHistory, operatorId, blockNumber, index + ); + } + + /// @notice Returns the `index`th entry in the operator with `operatorId`'s bitmap history + function getQuorumBitmapUpdateByIndex( + bytes32 operatorId, + uint256 index + ) external view returns (QuorumBitmapUpdate memory) { + return _operatorBitmapHistory[operatorId][index]; + } + + /// @notice Returns the current quorum bitmap for the given `operatorId` or 0 if the operator is not registered for any quorum + function getCurrentQuorumBitmap( + bytes32 operatorId + ) external view returns (uint192) { + return _currentOperatorBitmap(operatorId); + } + + /// @notice Returns the length of the quorum bitmap history for the given `operatorId` + function getQuorumBitmapHistoryLength( + bytes32 operatorId + ) external view returns (uint256) { + return _operatorBitmapHistory[operatorId].length; + } + + /// @notice Returns the number of registries + function numRegistries() external view returns (uint256) { + return registries.length; + } + + /** + * @notice Public function for the the churnApprover signature hash calculation when operators are being kicked from quorums + * @param registeringOperatorId The id of the registering operator + * @param operatorKickParams The parameters needed to kick the operator from the quorums that have reached their caps + * @param salt The salt to use for the churnApprover's signature + * @param expiry The desired expiry time of the churnApprover's signature + */ + function calculateOperatorChurnApprovalDigestHash( + address registeringOperator, + bytes32 registeringOperatorId, + OperatorKickParam[] memory operatorKickParams, + bytes32 salt, + uint256 expiry + ) public view returns (bytes32) { + // calculate the digest hash + return _hashTypedDataV4( + keccak256( + abi.encode( + OPERATOR_CHURN_APPROVAL_TYPEHASH, + registeringOperator, + registeringOperatorId, + operatorKickParams, + salt, + expiry + ) + ) + ); + } + + /** + * @notice Returns the message hash that an operator must sign to register their BLS public key. + * @param operator is the address of the operator registering their BLS public key + */ + function pubkeyRegistrationMessageHash( + address operator + ) public view returns (BN254.G1Point memory) { + return BN254.hashToG1( + _hashTypedDataV4(keccak256(abi.encode(PUBKEY_REGISTRATION_TYPEHASH, operator))) + ); + } + + /// @dev need to override function here since its defined in both these contracts + function owner() + public + view + override(OwnableUpgradeable, ISlashingRegistryCoordinator) + returns (address) + { + return OwnableUpgradeable.owner(); + } +} diff --git a/src/RegistryCoordinatorStorage.sol b/src/SlashingRegistryCoordinatorStorage.sol similarity index 81% rename from src/RegistryCoordinatorStorage.sol rename to src/SlashingRegistryCoordinatorStorage.sol index 00a422ba..e8c9eb9b 100644 --- a/src/RegistryCoordinatorStorage.sol +++ b/src/SlashingRegistryCoordinatorStorage.sol @@ -11,9 +11,9 @@ import { OperatorSet, IAllocationManagerTypes } from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; -abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { +abstract contract SlashingRegistryCoordinatorStorage is ISlashingRegistryCoordinator { /** * * CONSTANTS AND IMMUTABLES @@ -40,8 +40,6 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { /// @notice The maximum number of quorums this contract supports uint8 internal constant MAX_QUORUM_COUNT = 192; - /// @notice the ServiceManager for this AVS, which forwards calls onto EigenLayer's core contracts - IServiceManager public immutable serviceManager; /// @notice the BLS Aggregate Pubkey Registry contract that will keep track of operators' aggregate BLS public keys per quorum IBLSApkRegistry public immutable blsApkRegistry; /// @notice the Stake Registry contract that will keep track of operators' stakes @@ -84,22 +82,29 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { /// @notice the delay in seconds before an operator can reregister after being ejected uint256 public ejectionCooldown; - /// @notice Whether this AVS uses operator sets for registration - /// @dev If true, operators must register to operator sets via the AllocationManager - bool public isOperatorSetAVS; + /// @notice Whether this AVS allows operator sets for registration + /// @dev If true, operators may register to operator sets via the AllocationManager + bool public operatorSetsEnabled; - /// @notice Mapping from quorum number to whether the quorum is an M2 quorum - /// @dev M2 quorums are pre-operator sets and track total delegated stake only - mapping(uint8 => bool) public isM2Quorum; + /// @notice Whether this AVS allows M2 quorums for registration + /// @dev If true, operators may **not** register to M2 quorums. Deregistration is still allowed. + bool public m2QuorumsDisabled; + + /// @notice The account identifier for this AVS (used for UAM integration in EigenLayer) + /// @dev NOTE: Updating this value will break existing OperatorSets and UAM integration. + /// This value should only be set once. + address public accountIdentifier; + + /// @notice The bitmap containing all M2 quorums. This is only used for existing AVS middlewares that have M2 quorums + /// and need to call `enableOperatorSets()` to enable operator sets mode. + uint256 internal M2quorumBitmap; constructor( - IServiceManager _serviceManager, IStakeRegistry _stakeRegistry, IBLSApkRegistry _blsApkRegistry, IIndexRegistry _indexRegistry, IAllocationManager _allocationManager ) { - serviceManager = _serviceManager; stakeRegistry = _stakeRegistry; blsApkRegistry = _blsApkRegistry; indexRegistry = _indexRegistry; diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index d93763c3..a75625a0 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -7,11 +7,10 @@ import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSD import {OperatorSet} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {StakeRegistryStorage, IStrategy} from "./StakeRegistryStorage.sol"; -import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; import {BitmapUtils} from "./libraries/BitmapUtils.sol"; @@ -28,13 +27,13 @@ import {BitmapUtils} from "./libraries/BitmapUtils.sol"; contract StakeRegistry is StakeRegistryStorage { using BitmapUtils for *; - modifier onlyRegistryCoordinator() { - _checkRegistryCoordinator(); + modifier onlySlashingRegistryCoordinator() { + _checkSlashingRegistryCoordinator(); _; } modifier onlyCoordinatorOwner() { - _checkRegistryCoordinatorOwner(); + _checkSlashingRegistryCoordinatorOwner(); _; } @@ -46,18 +45,16 @@ contract StakeRegistry is StakeRegistryStorage { } constructor( - IRegistryCoordinator _registryCoordinator, + ISlashingRegistryCoordinator _slashingRegistryCoordinator, IDelegationManager _delegationManager, IAVSDirectory _avsDirectory, - IAllocationManager _allocationManager, - IServiceManager _serviceManager + IAllocationManager _allocationManager ) StakeRegistryStorage( - _registryCoordinator, + _slashingRegistryCoordinator, _delegationManager, _avsDirectory, - _allocationManager, - _serviceManager + _allocationManager ) {} @@ -84,7 +81,7 @@ contract StakeRegistry is StakeRegistryStorage { address operator, bytes32 operatorId, bytes calldata quorumNumbers - ) public virtual onlyRegistryCoordinator returns (uint96[] memory, uint96[] memory) { + ) public virtual onlySlashingRegistryCoordinator returns (uint96[] memory, uint96[] memory) { uint96[] memory currentStakes = new uint96[](quorumNumbers.length); uint96[] memory totalStakes = new uint96[](quorumNumbers.length); for (uint256 i = 0; i < quorumNumbers.length; i++) { @@ -127,7 +124,7 @@ contract StakeRegistry is StakeRegistryStorage { function deregisterOperator( bytes32 operatorId, bytes calldata quorumNumbers - ) public virtual onlyRegistryCoordinator { + ) public virtual onlySlashingRegistryCoordinator { /** * For each quorum, remove the operator's stake for the quorum and update * the quorum's total stake to account for the removal @@ -161,7 +158,7 @@ contract StakeRegistry is StakeRegistryStorage { address operator, bytes32 operatorId, bytes calldata quorumNumbers - ) external onlyRegistryCoordinator returns (uint192) { + ) external onlySlashingRegistryCoordinator returns (uint192) { uint192 quorumsToRemove; /** @@ -207,7 +204,7 @@ contract StakeRegistry is StakeRegistryStorage { uint8 quorumNumber, uint96 minimumStake, StrategyParams[] memory _strategyParams - ) public virtual onlyRegistryCoordinator { + ) public virtual onlySlashingRegistryCoordinator { require(!_quorumExists(quorumNumber), QuorumAlreadyExists()); _addStrategyParams(quorumNumber, _strategyParams); _setMinimumStakeForQuorum(quorumNumber, minimumStake); @@ -228,7 +225,7 @@ contract StakeRegistry is StakeRegistryStorage { uint96 minimumStake, uint32 lookAheadPeriod, StrategyParams[] memory _strategyParams - ) public virtual onlyRegistryCoordinator { + ) public virtual onlySlashingRegistryCoordinator { require(!_quorumExists(quorumNumber), QuorumAlreadyExists()); _addStrategyParams(quorumNumber, _strategyParams); _setMinimumStakeForQuorum(quorumNumber, minimumStake); @@ -283,7 +280,7 @@ contract StakeRegistry is StakeRegistryStorage { strategiesToAdd[i] = _strategyParams[i].strategy; } allocationManager.addStrategiesToOperatorSet({ - avs: address(serviceManager), + avs: ISlashingRegistryCoordinator(registryCoordinator).accountIdentifier(), operatorSetId: quorumNumber, strategies: strategiesToAdd }); @@ -325,7 +322,7 @@ contract StakeRegistry is StakeRegistryStorage { if (isOperatorSetQuorum(quorumNumber)) { allocationManager.removeStrategiesFromOperatorSet({ - avs: address(serviceManager), + avs: ISlashingRegistryCoordinator(registryCoordinator).accountIdentifier(), operatorSetId: quorumNumber, strategies: _strategiesToRemove }); @@ -562,7 +559,9 @@ contract StakeRegistry is StakeRegistryStorage { uint32(block.number + slashableStakeLookAheadPerQuorum[quorumNumber]); uint256[][] memory slashableShares = allocationManager.getMinimumSlashableStake( - OperatorSet(address(serviceManager), quorumNumber), + OperatorSet( + ISlashingRegistryCoordinator(registryCoordinator).accountIdentifier(), quorumNumber + ), operators, strategiesPerQuorum[quorumNumber], beforeTimestamp @@ -641,8 +640,8 @@ contract StakeRegistry is StakeRegistryStorage { function isOperatorSetQuorum( uint8 quorumNumber ) public view returns (bool) { - bool isM2 = IRegistryCoordinator(registryCoordinator).isM2Quorum(quorumNumber); - bool isOperatorSet = IRegistryCoordinator(registryCoordinator).isOperatorSetAVS(); + bool isM2 = ISlashingRegistryCoordinator(registryCoordinator).isM2Quorum(quorumNumber); + bool isOperatorSet = ISlashingRegistryCoordinator(registryCoordinator).operatorSetsEnabled(); return isOperatorSet && !isM2; } @@ -896,14 +895,14 @@ contract StakeRegistry is StakeRegistryStorage { emit LookAheadPeriodChanged(oldLookAheadDays, _lookAheadBlocks); } - function _checkRegistryCoordinator() internal view { - require(msg.sender == address(registryCoordinator), OnlyRegistryCoordinator()); + function _checkSlashingRegistryCoordinator() internal view { + require(msg.sender == registryCoordinator, OnlySlashingRegistryCoordinator()); } - function _checkRegistryCoordinatorOwner() internal view { + function _checkSlashingRegistryCoordinatorOwner() internal view { require( - msg.sender == IRegistryCoordinator(registryCoordinator).owner(), - OnlyRegistryCoordinatorOwner() + msg.sender == ISlashingRegistryCoordinator(registryCoordinator).owner(), + OnlySlashingRegistryCoordinatorOwner() ); } diff --git a/src/StakeRegistryStorage.sol b/src/StakeRegistryStorage.sol index c0d7b933..e13835f3 100644 --- a/src/StakeRegistryStorage.sol +++ b/src/StakeRegistryStorage.sol @@ -6,13 +6,12 @@ import {IDelegationManager} from import {IAVSDirectory} from "eigenlayer-contracts/src/contracts/interfaces/IAVSDirectory.sol"; import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IServiceManager} from "./interfaces/IServiceManager.sol"; import { IStrategyManager, IStrategy } from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; -import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; /** @@ -37,9 +36,6 @@ abstract contract StakeRegistryStorage is IStakeRegistry { /// @notice the address of the AllocationManager for EigenLayer. IAllocationManager public immutable allocationManager; - /// @notice the address of the ServiceManager associtated with the stake registries - IServiceManager public immutable serviceManager; - /// @notice the coordinator contract that this registry is associated with address public immutable registryCoordinator; @@ -69,16 +65,14 @@ abstract contract StakeRegistryStorage is IStakeRegistry { mapping(uint8 quorumNumber => uint32) public slashableStakeLookAheadPerQuorum; constructor( - IRegistryCoordinator _registryCoordinator, + ISlashingRegistryCoordinator _slashingRegistryCoordinator, IDelegationManager _delegationManager, IAVSDirectory _avsDirectory, - IAllocationManager _allocationManager, - IServiceManager _serviceManager + IAllocationManager _allocationManager ) { - registryCoordinator = address(_registryCoordinator); + registryCoordinator = address(_slashingRegistryCoordinator); delegation = _delegationManager; avsDirectory = _avsDirectory; - serviceManager = _serviceManager; allocationManager = _allocationManager; } diff --git a/src/interfaces/IBLSSignatureChecker.sol b/src/interfaces/IBLSSignatureChecker.sol index 6a7df2c5..87feab40 100644 --- a/src/interfaces/IBLSSignatureChecker.sol +++ b/src/interfaces/IBLSSignatureChecker.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IRegistryCoordinator} from "./IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "./ISlashingRegistryCoordinator.sol"; import {IBLSApkRegistry} from "./IBLSApkRegistry.sol"; import {IStakeRegistry, IDelegationManager} from "./IStakeRegistry.sol"; @@ -68,7 +68,7 @@ interface IBLSSignatureChecker is IBLSSignatureCheckerErrors { // CONSTANTS & IMMUTABLES - function registryCoordinator() external view returns (IRegistryCoordinator); + function registryCoordinator() external view returns (ISlashingRegistryCoordinator); function stakeRegistry() external view returns (IStakeRegistry); function blsApkRegistry() external view returns (IBLSApkRegistry); function delegation() external view returns (IDelegationManager); diff --git a/src/interfaces/IRegistryCoordinator.sol b/src/interfaces/IRegistryCoordinator.sol index 3a7fcfd7..2f6fe5fe 100644 --- a/src/interfaces/IRegistryCoordinator.sol +++ b/src/interfaces/IRegistryCoordinator.sol @@ -1,218 +1,73 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IServiceManager} from "./IServiceManager.sol"; +import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; import {IBLSApkRegistry} from "./IBLSApkRegistry.sol"; -import {IStakeRegistry} from "./IStakeRegistry.sol"; -import {IIndexRegistry} from "./IIndexRegistry.sol"; -import {BN254} from "../libraries/BN254.sol"; +import {ISlashingRegistryCoordinator} from "./ISlashingRegistryCoordinator.sol"; -interface IRegistryCoordinatorErrors { - error InputLengthMismatch(); - error OperatorSetsEnabled(); - error OperatorSetsNotEnabled(); - error OperatorSetsNotSupported(); - error OnlyAllocationManager(); - error OnlyEjector(); - error QuorumDoesNotExist(); - error BitmapEmpty(); - error AlreadyRegisteredForQuorums(); - error CannotReregisterYet(); - error NotRegistered(); - error CannotChurnSelf(); - error QuorumOperatorCountMismatch(); - error InsufficientStakeForChurn(); - error CannotKickOperatorAboveThreshold(); - error BitmapCannotBeZero(); - error NotRegisteredForQuorum(); - error MaxQuorumsReached(); - error SaltAlreadyUsed(); - error RegistryCoordinatorSignatureExpired(); - error ChurnApproverSaltUsed(); - error NotSorted(); -} -/** - * @title Interface for a contract that coordinates between various registries for an AVS. - * @author Layr Labs, Inc. - */ - -interface IRegistryCoordinator is IRegistryCoordinatorErrors { - // EVENTS - - /// Emits when an operator is registered - event OperatorRegistered(address indexed operator, bytes32 indexed operatorId); - - /// Emits when an operator is deregistered - event OperatorDeregistered(address indexed operator, bytes32 indexed operatorId); - - event OperatorSetParamsUpdated(uint8 indexed quorumNumber, OperatorSetParam operatorSetParams); - - event ChurnApproverUpdated(address prevChurnApprover, address newChurnApprover); - - event EjectorUpdated(address prevEjector, address newEjector); - - /// @notice emitted when all the operators for a quorum are updated at once - event QuorumBlockNumberUpdated(uint8 indexed quorumNumber, uint256 blocknumber); - - // DATA STRUCTURES - enum OperatorStatus { - // default is NEVER_REGISTERED - NEVER_REGISTERED, - REGISTERED, - DEREGISTERED - } - - // STRUCTS +interface IRegistryCoordinator { + /// Emits when operator sets mode is enabled + event OperatorSetsEnabled(); + /// Emits when M2 quorums are disabled + event M2QuorumsDisabled(); /** - * @notice Data structure for storing info on operators + * @notice Registers msg.sender as an operator for one or more quorums. If any quorum exceeds its maximum + * operator capacity after the operator is registered, this method will fail. + * @param quorumNumbers is an ordered byte array containing the quorum numbers being registered for + * @param socket is the socket of the operator (typically an IP address) + * @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership + * @param operatorSignature is the signature of the operator used by the AVS to register the operator in the delegation manager + * @dev `params` is ignored if the caller has previously registered a public key + * @dev `operatorSignature` is ignored if the operator's status is already REGISTERED */ - struct OperatorInfo { - // the id of the operator, which is likely the keccak256 hash of the operator's public key if using BLSRegistry - bytes32 operatorId; - // indicates whether the operator is actively registered for serving the middleware or not - OperatorStatus status; - } + function registerOperator( + bytes memory quorumNumbers, + string memory socket, + IBLSApkRegistry.PubkeyRegistrationParams memory params, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external; /** - * @notice Data structure for storing info on quorum bitmap updates where the `quorumBitmap` is the bitmap of the - * quorums the operator is registered for starting at (inclusive)`updateBlockNumber` and ending at (exclusive) `nextUpdateBlockNumber` - * @dev nextUpdateBlockNumber is initialized to 0 for the latest update + * @notice Registers msg.sender as an operator for one or more quorums. If any quorum reaches its maximum operator + * capacity, `operatorKickParams` is used to replace an old operator with the new one. + * @param quorumNumbers is an ordered byte array containing the quorum numbers being registered for + * @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership + * @param operatorKickParams used to determine which operator is removed to maintain quorum capacity as the + * operator registers for quorums + * @param churnApproverSignature is the signature of the churnApprover over the `operatorKickParams` + * @param operatorSignature is the signature of the operator used by the AVS to register the operator in the delegation manager + * @dev `params` is ignored if the caller has previously registered a public key + * @dev `operatorSignature` is ignored if the operator's status is already REGISTERED */ - struct QuorumBitmapUpdate { - uint32 updateBlockNumber; - uint32 nextUpdateBlockNumber; - uint192 quorumBitmap; - } + function registerOperatorWithChurn( + bytes calldata quorumNumbers, + string memory socket, + IBLSApkRegistry.PubkeyRegistrationParams memory params, + ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams, + ISignatureUtils.SignatureWithSaltAndExpiry memory churnApproverSignature, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external; /** - * @notice Data structure for storing operator set params for a given quorum. Specifically the - * `maxOperatorCount` is the maximum number of operators that can be registered for the quorum, - * `kickBIPsOfOperatorStake` is the basis points of a new operator needs to have of an operator they are trying to kick from the quorum, - * and `kickBIPsOfTotalStake` is the basis points of the total stake of the quorum that an operator needs to be below to be kicked. + * @notice Deregisters the caller from one or more quorums + * @param quorumNumbers is an ordered byte array containing the quorum numbers being deregistered from */ - struct OperatorSetParam { - uint32 maxOperatorCount; - uint16 kickBIPsOfOperatorStake; - uint16 kickBIPsOfTotalStake; - } + function deregisterOperator( + bytes memory quorumNumbers + ) external; /** - * @notice Data structure for the parameters needed to kick an operator from a quorum with number `quorumNumber`, used during registration churn. - * `operator` is the address of the operator to kick + * @notice Enables operator sets mode. This is by default initialized to set `operatorSetsEnabled` to True. + * So this is only meant to be called for existing AVSs that have a existing quorums and a previously deployed + * version of middleware contracts. + * @dev This is only callable by the owner of the RegistryCoordinator */ - struct OperatorKickParam { - uint8 quorumNumber; - address operator; - } - - /// @notice Returns the operator set params for the given `quorumNumber` - function getOperatorSetParams( - uint8 quorumNumber - ) external view returns (OperatorSetParam memory); - /// @notice the Stake registry contract that will keep track of operators' stakes - function stakeRegistry() external view returns (IStakeRegistry); - /// @notice the BLS Aggregate Pubkey Registry contract that will keep track of operators' BLS aggregate pubkeys per quorum - function blsApkRegistry() external view returns (IBLSApkRegistry); - /// @notice the index Registry contract that will keep track of operators' indexes - function indexRegistry() external view returns (IIndexRegistry); + function enableOperatorSets() external; /** - * @notice Ejects the provided operator from the provided quorums from the AVS - * @param operator is the operator to eject - * @param quorumNumbers are the quorum numbers to eject the operator from + * @notice Disables registration to M2 quorums. This is only callable by the owner of the RegistryCoordinator. + * @dev This is only callable if `operatorSetsEnabled` is True. */ - function ejectOperator(address operator, bytes calldata quorumNumbers) external; - - /// @notice Returns the number of quorums the registry coordinator has created - function quorumCount() external view returns (uint8); - - /// @notice Returns the operator struct for the given `operator` - function getOperator( - address operator - ) external view returns (OperatorInfo memory); - - /// @notice Returns the operatorId for the given `operator` - function getOperatorId( - address operator - ) external view returns (bytes32); - - /// @notice Returns the operator address for the given `operatorId` - function getOperatorFromId( - bytes32 operatorId - ) external view returns (address operator); - - /// @notice Returns the status for the given `operator` - function getOperatorStatus( - address operator - ) external view returns (IRegistryCoordinator.OperatorStatus); - - /// @notice Returns the indices of the quorumBitmaps for the provided `operatorIds` at the given `blockNumber` - function getQuorumBitmapIndicesAtBlockNumber( - uint32 blockNumber, - bytes32[] memory operatorIds - ) external view returns (uint32[] memory); - - /** - * @notice Returns the quorum bitmap for the given `operatorId` at the given `blockNumber` via the `index` - * @dev reverts if `index` is incorrect - */ - function getQuorumBitmapAtBlockNumberByIndex( - bytes32 operatorId, - uint32 blockNumber, - uint256 index - ) external view returns (uint192); - - /// @notice Returns the `index`th entry in the operator with `operatorId`'s bitmap history - function getQuorumBitmapUpdateByIndex( - bytes32 operatorId, - uint256 index - ) external view returns (QuorumBitmapUpdate memory); - - /// @notice Returns the current quorum bitmap for the given `operatorId` - function getCurrentQuorumBitmap( - bytes32 operatorId - ) external view returns (uint192); - - /// @notice Returns the length of the quorum bitmap history for the given `operatorId` - function getQuorumBitmapHistoryLength( - bytes32 operatorId - ) external view returns (uint256); - - /// @notice Returns the registry at the desired index - function registries( - uint256 - ) external view returns (address); - - /// @notice Returns the number of registries - function numRegistries() external view returns (uint256); - - /// @notice Returns whether a quorum is an M2 quorum - /// @param quorumNumber The quorum number to check - /// @return True if the quorum is an M2 quorum - function isM2Quorum( - uint8 quorumNumber - ) external view returns (bool); - - /// @notice Returns whether the AVS is an operator set AVS - /// @return True if the AVS is an operator set AVS - function isOperatorSetAVS() external view returns (bool); - - /** - * @notice Returns the message hash that an operator must sign to register their BLS public key. - * @param operator is the address of the operator registering their BLS public key - */ - function pubkeyRegistrationMessageHash( - address operator - ) external view returns (BN254.G1Point memory); - - /// @notice returns the blocknumber the quorum was last updated all at once for all operators - function quorumUpdateBlockNumber( - uint8 quorumNumber - ) external view returns (uint256); - - /// @notice The owner of the registry coordinator - function owner() external view returns (address); - - function serviceManager() external view returns (IServiceManager); + function disableM2QuorumRegistration() external; } diff --git a/src/interfaces/IServiceManager.sol b/src/interfaces/IServiceManager.sol index 6d3cbaa8..bfb522af 100644 --- a/src/interfaces/IServiceManager.sol +++ b/src/interfaces/IServiceManager.sol @@ -101,11 +101,7 @@ interface IServiceManager is IServiceManagerUI, IServiceManagerErrors { * @param selector The function selector to remove the appointee for * @dev Only callable by the owner of the contract */ - function removeAppointee( - address appointee, - address target, - bytes4 selector - ) external; + function removeAppointee(address appointee, address target, bytes4 selector) external; /** * @notice Deregisters an operator from specified operator sets @@ -113,5 +109,8 @@ interface IServiceManager is IServiceManagerUI, IServiceManagerErrors { * @param operatorSetIds The IDs of the operator sets to deregister from * @dev Only callable by the RegistryCoordinator */ - function deregisterOperatorFromOperatorSets(address operator, uint32[] memory operatorSetIds) external; + function deregisterOperatorFromOperatorSets( + address operator, + uint32[] memory operatorSetIds + ) external; } diff --git a/src/interfaces/ISlashingRegistryCoordinator.sol b/src/interfaces/ISlashingRegistryCoordinator.sol new file mode 100644 index 00000000..2a8dd58d --- /dev/null +++ b/src/interfaces/ISlashingRegistryCoordinator.sol @@ -0,0 +1,239 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import {IServiceManager} from "./IServiceManager.sol"; +import {IBLSApkRegistry} from "./IBLSApkRegistry.sol"; +import {IStakeRegistry} from "./IStakeRegistry.sol"; +import {IIndexRegistry} from "./IIndexRegistry.sol"; +import {BN254} from "../libraries/BN254.sol"; + +interface IRegistryCoordinatorErrors { + error InputLengthMismatch(); + error OperatorSetsAlreadyEnabled(); + error OperatorSetsNotEnabled(); + error M2QuorumsAlreadyDisabled(); + error OnlyAllocationManager(); + error OnlyEjector(); + error QuorumDoesNotExist(); + error BitmapEmpty(); + error AlreadyRegisteredForQuorums(); + error CannotReregisterYet(); + error NotRegistered(); + error CannotChurnSelf(); + error QuorumOperatorCountMismatch(); + error InsufficientStakeForChurn(); + error CannotKickOperatorAboveThreshold(); + error BitmapCannotBeZero(); + error NotRegisteredForQuorum(); + error MaxQuorumsReached(); + error SaltAlreadyUsed(); + error RegistryCoordinatorSignatureExpired(); + error ChurnApproverSaltUsed(); + error NotSorted(); + error InvalidRegistrationType(); +} +/** + * @title Interface for a contract that coordinates between various registries for an AVS. + * @author Layr Labs, Inc. + */ + +interface ISlashingRegistryCoordinator is IRegistryCoordinatorErrors { + // EVENTS + + /// Emits when an operator is registered + event OperatorRegistered(address indexed operator, bytes32 indexed operatorId); + /// Emits when an operator is deregistered + event OperatorDeregistered(address indexed operator, bytes32 indexed operatorId); + + event OperatorSetParamsUpdated(uint8 indexed quorumNumber, OperatorSetParam operatorSetParams); + + event ChurnApproverUpdated(address prevChurnApprover, address newChurnApprover); + + event EjectorUpdated(address prevEjector, address newEjector); + + /// @notice emitted when all the operators for a quorum are updated at once + event QuorumBlockNumberUpdated(uint8 indexed quorumNumber, uint256 blocknumber); + + // DATA STRUCTURES + enum OperatorStatus { + // default is NEVER_REGISTERED + NEVER_REGISTERED, + REGISTERED, + DEREGISTERED + } + + enum RegistrationType { + NORMAL, + CHURN + } + + // STRUCTS + + /** + * @notice Data structure for storing info on operators + */ + struct OperatorInfo { + // the id of the operator, which is likely the keccak256 hash of the operator's public key if using BLSRegistry + bytes32 operatorId; + // indicates whether the operator is actively registered for serving the middleware or not + OperatorStatus status; + } + + /** + * @notice Data structure for storing info on quorum bitmap updates where the `quorumBitmap` is the bitmap of the + * quorums the operator is registered for starting at (inclusive)`updateBlockNumber` and ending at (exclusive) `nextUpdateBlockNumber` + * @dev nextUpdateBlockNumber is initialized to 0 for the latest update + */ + struct QuorumBitmapUpdate { + uint32 updateBlockNumber; + uint32 nextUpdateBlockNumber; + uint192 quorumBitmap; + } + + /** + * @notice Data structure for storing the results of a registerOperator call + * @dev For each quorum the operator registered for, numOperatorsPerQuorum is the number of operators registered + * @dev For each quorum the operator registered for, operatorStakes is the stake of the operator in the quorum + * @dev For each quorum the operator registered for, totalStakes is the total stake of the quorum + */ + struct RegisterResults { + uint32[] numOperatorsPerQuorum; + uint96[] operatorStakes; + uint96[] totalStakes; + } + + /** + * @notice Data structure for storing operator set params for a given quorum. Specifically the + * `maxOperatorCount` is the maximum number of operators that can be registered for the quorum, + * `kickBIPsOfOperatorStake` is the basis points of a new operator needs to have of an operator they are trying to kick from the quorum, + * and `kickBIPsOfTotalStake` is the basis points of the total stake of the quorum that an operator needs to be below to be kicked. + */ + struct OperatorSetParam { + uint32 maxOperatorCount; + uint16 kickBIPsOfOperatorStake; + uint16 kickBIPsOfTotalStake; + } + + /** + * @notice Data structure for the parameters needed to kick an operator from a quorum with number `quorumNumber`, used during registration churn. + * `operator` is the address of the operator to kick + */ + struct OperatorKickParam { + uint8 quorumNumber; + address operator; + } + + /// @notice Returns the operator set params for the given `quorumNumber` + function getOperatorSetParams( + uint8 quorumNumber + ) external view returns (OperatorSetParam memory); + /// @notice the Stake registry contract that will keep track of operators' stakes + function stakeRegistry() external view returns (IStakeRegistry); + /// @notice the BLS Aggregate Pubkey Registry contract that will keep track of operators' BLS aggregate pubkeys per quorum + function blsApkRegistry() external view returns (IBLSApkRegistry); + /// @notice the index Registry contract that will keep track of operators' indexes + function indexRegistry() external view returns (IIndexRegistry); + + /** + * @notice Ejects the provided operator from the provided quorums from the AVS + * @param operator is the operator to eject + * @param quorumNumbers are the quorum numbers to eject the operator from + */ + function ejectOperator(address operator, bytes calldata quorumNumbers) external; + + /// @notice Returns the number of quorums the registry coordinator has created + function quorumCount() external view returns (uint8); + + /// @notice Returns the operator struct for the given `operator` + function getOperator( + address operator + ) external view returns (OperatorInfo memory); + + /// @notice Returns the operatorId for the given `operator` + function getOperatorId( + address operator + ) external view returns (bytes32); + + /// @notice Returns the operator address for the given `operatorId` + function getOperatorFromId( + bytes32 operatorId + ) external view returns (address operator); + + /// @notice Returns the status for the given `operator` + function getOperatorStatus( + address operator + ) external view returns (OperatorStatus); + + /// @notice Returns the indices of the quorumBitmaps for the provided `operatorIds` at the given `blockNumber` + function getQuorumBitmapIndicesAtBlockNumber( + uint32 blockNumber, + bytes32[] memory operatorIds + ) external view returns (uint32[] memory); + + /** + * @notice Returns the quorum bitmap for the given `operatorId` at the given `blockNumber` via the `index` + * @dev reverts if `index` is incorrect + */ + function getQuorumBitmapAtBlockNumberByIndex( + bytes32 operatorId, + uint32 blockNumber, + uint256 index + ) external view returns (uint192); + + /// @notice Returns the `index`th entry in the operator with `operatorId`'s bitmap history + function getQuorumBitmapUpdateByIndex( + bytes32 operatorId, + uint256 index + ) external view returns (QuorumBitmapUpdate memory); + + /// @notice Returns the current quorum bitmap for the given `operatorId` + function getCurrentQuorumBitmap( + bytes32 operatorId + ) external view returns (uint192); + + /// @notice Returns the length of the quorum bitmap history for the given `operatorId` + function getQuorumBitmapHistoryLength( + bytes32 operatorId + ) external view returns (uint256); + + /// @notice Returns the registry at the desired index + function registries( + uint256 + ) external view returns (address); + + /// @notice Returns the number of registries + function numRegistries() external view returns (uint256); + + /// @notice Returns whether a quorum is an M2 quorum + /// @param quorumNumber The quorum number to check + /// @return True if the quorum is an M2 quorum + function isM2Quorum( + uint8 quorumNumber + ) external view returns (bool); + + /// @notice Returns whether operator sets mode is enabled + function operatorSetsEnabled() external view returns (bool); + + /** + * @notice Returns the message hash that an operator must sign to register their BLS public key. + * @param operator is the address of the operator registering their BLS public key + */ + function pubkeyRegistrationMessageHash( + address operator + ) external view returns (BN254.G1Point memory); + + /// @notice returns the blocknumber the quorum was last updated all at once for all operators + function quorumUpdateBlockNumber( + uint8 quorumNumber + ) external view returns (uint256); + + /// @notice The owner of the registry coordinator + function owner() external view returns (address); + + /** + * @notice The account identifier for this AVS (used for UAM integration in EigenLayer) + * @dev NOTE: Updating this value will break existing OperatorSets and UAM integration. + * This value should only be set once. + */ + function accountIdentifier() external view returns (address); +} diff --git a/src/interfaces/IStakeRegistry.sol b/src/interfaces/IStakeRegistry.sol index a9d3d5a3..66108a75 100644 --- a/src/interfaces/IStakeRegistry.sol +++ b/src/interfaces/IStakeRegistry.sol @@ -14,9 +14,9 @@ enum StakeType { interface IStakeRegistryErrors { /// @dev Thrown when the caller is not the registry coordinator - error OnlyRegistryCoordinator(); + error OnlySlashingRegistryCoordinator(); /// @dev Thrown when the caller is not the owner of the registry coordinator - error OnlyRegistryCoordinatorOwner(); + error OnlySlashingRegistryCoordinatorOwner(); /// @dev Thrown when the stake is below the minimum required for a quorum error BelowMinimumStakeRequirement(); /// @dev Thrown when a quorum being created already exists. diff --git a/src/libraries/QuorumBitmapHistoryLib.sol b/src/libraries/QuorumBitmapHistoryLib.sol index 92848aba..677c8678 100644 --- a/src/libraries/QuorumBitmapHistoryLib.sol +++ b/src/libraries/QuorumBitmapHistoryLib.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IRegistryCoordinator} from "../interfaces/IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "../interfaces/ISlashingRegistryCoordinator.sol"; /// @title QuorumBitmapHistoryLib /// @notice This library operates on the _operatorBitmapHistory in the RegistryCoordinator @@ -19,7 +19,7 @@ library QuorumBitmapHistoryLib { /// @param operatorId The ID of the operator /// @return index The index of the quorum bitmap update function getQuorumBitmapIndexAtBlockNumber( - mapping(bytes32 => IRegistryCoordinator.QuorumBitmapUpdate[]) storage self, + mapping(bytes32 => ISlashingRegistryCoordinator.QuorumBitmapUpdate[]) storage self, uint32 blockNumber, bytes32 operatorId ) internal view returns (uint32 index) { @@ -45,7 +45,7 @@ library QuorumBitmapHistoryLib { /// @param operatorId The ID of the operator /// @return The current quorum bitmap function currentOperatorBitmap( - mapping(bytes32 => IRegistryCoordinator.QuorumBitmapUpdate[]) storage self, + mapping(bytes32 => ISlashingRegistryCoordinator.QuorumBitmapUpdate[]) storage self, bytes32 operatorId ) internal view returns (uint192) { uint256 historyLength = self[operatorId].length; @@ -62,7 +62,7 @@ library QuorumBitmapHistoryLib { /// @param operatorIds The array of operator IDs /// @return An array of indices corresponding to the quorum bitmap updates function getQuorumBitmapIndicesAtBlockNumber( - mapping(bytes32 => IRegistryCoordinator.QuorumBitmapUpdate[]) storage self, + mapping(bytes32 => ISlashingRegistryCoordinator.QuorumBitmapUpdate[]) storage self, uint32 blockNumber, bytes32[] memory operatorIds ) internal view returns (uint32[] memory) { @@ -80,12 +80,13 @@ library QuorumBitmapHistoryLib { /// @param index The index of the quorum bitmap update /// @return The quorum bitmap at the specified index function getQuorumBitmapAtBlockNumberByIndex( - mapping(bytes32 => IRegistryCoordinator.QuorumBitmapUpdate[]) storage self, + mapping(bytes32 => ISlashingRegistryCoordinator.QuorumBitmapUpdate[]) storage self, bytes32 operatorId, uint32 blockNumber, uint256 index ) internal view returns (uint192) { - IRegistryCoordinator.QuorumBitmapUpdate memory quorumBitmapUpdate = self[operatorId][index]; + ISlashingRegistryCoordinator.QuorumBitmapUpdate memory quorumBitmapUpdate = + self[operatorId][index]; /** * Validate that the update is valid for the given blockNumber: @@ -109,7 +110,7 @@ library QuorumBitmapHistoryLib { /// @param operatorId The ID of the operator /// @param newBitmap The new quorum bitmap to set function updateOperatorBitmap( - mapping(bytes32 => IRegistryCoordinator.QuorumBitmapUpdate[]) storage self, + mapping(bytes32 => ISlashingRegistryCoordinator.QuorumBitmapUpdate[]) storage self, bytes32 operatorId, uint192 newBitmap ) internal { @@ -118,7 +119,7 @@ library QuorumBitmapHistoryLib { if (historyLength == 0) { // No prior bitmap history - push our first entry self[operatorId].push( - IRegistryCoordinator.QuorumBitmapUpdate({ + ISlashingRegistryCoordinator.QuorumBitmapUpdate({ updateBlockNumber: uint32(block.number), nextUpdateBlockNumber: 0, quorumBitmap: newBitmap @@ -126,7 +127,7 @@ library QuorumBitmapHistoryLib { ); } else { // We have prior history - fetch our last-recorded update - IRegistryCoordinator.QuorumBitmapUpdate storage lastUpdate = + ISlashingRegistryCoordinator.QuorumBitmapUpdate storage lastUpdate = self[operatorId][historyLength - 1]; /** @@ -138,7 +139,7 @@ library QuorumBitmapHistoryLib { } else { lastUpdate.nextUpdateBlockNumber = uint32(block.number); self[operatorId].push( - IRegistryCoordinator.QuorumBitmapUpdate({ + ISlashingRegistryCoordinator.QuorumBitmapUpdate({ updateBlockNumber: uint32(block.number), nextUpdateBlockNumber: 0, quorumBitmap: newBitmap diff --git a/src/slashers/InstantSlasher.sol b/src/slashers/InstantSlasher.sol index 5575525a..10276bff 100644 --- a/src/slashers/InstantSlasher.sol +++ b/src/slashers/InstantSlasher.sol @@ -4,15 +4,15 @@ pragma solidity ^0.8.27; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IServiceManager} from "../interfaces/IServiceManager.sol"; +import {ISlashingRegistryCoordinator} from "../interfaces/ISlashingRegistryCoordinator.sol"; import {SlasherBase} from "./base/SlasherBase.sol"; contract InstantSlasher is SlasherBase { constructor( IAllocationManager _allocationManager, - IServiceManager _serviceManager, + ISlashingRegistryCoordinator _slashingRegistryCoordinator, address _slasher - ) SlasherBase(_allocationManager, _serviceManager) {} + ) SlasherBase(_allocationManager, _slashingRegistryCoordinator) {} function initialize( address _slasher diff --git a/src/slashers/VetoableSlasher.sol b/src/slashers/VetoableSlasher.sol index 87112d21..949c46c2 100644 --- a/src/slashers/VetoableSlasher.sol +++ b/src/slashers/VetoableSlasher.sol @@ -5,7 +5,7 @@ import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {SlasherBase} from "./base/SlasherBase.sol"; -import {IServiceManager} from "../interfaces/IServiceManager.sol"; +import {ISlashingRegistryCoordinator} from "../interfaces/ISlashingRegistryCoordinator.sol"; contract VetoableSlasher is SlasherBase { uint256 public constant VETO_PERIOD = 3 days; @@ -20,9 +20,9 @@ contract VetoableSlasher is SlasherBase { constructor( IAllocationManager _allocationManager, - IServiceManager _serviceManager, + ISlashingRegistryCoordinator _slashingRegistryCoordinator, address _slasher - ) SlasherBase(_allocationManager, _serviceManager) {} + ) SlasherBase(_allocationManager, _slashingRegistryCoordinator) {} function initialize(address _vetoCommittee, address _slasher) external virtual initializer { __SlasherBase_init(_slasher); diff --git a/src/slashers/base/SlasherBase.sol b/src/slashers/base/SlasherBase.sol index 370e60b1..a6917d39 100644 --- a/src/slashers/base/SlasherBase.sol +++ b/src/slashers/base/SlasherBase.sol @@ -2,8 +2,7 @@ pragma solidity ^0.8.27; import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; -import {IServiceManager} from "../../interfaces/IServiceManager.sol"; -import {SlasherStorage} from "./SlasherStorage.sol"; +import {SlasherStorage, ISlashingRegistryCoordinator} from "./SlasherStorage.sol"; import { IAllocationManagerTypes, IAllocationManager @@ -18,8 +17,8 @@ abstract contract SlasherBase is Initializable, SlasherStorage { constructor( IAllocationManager _allocationManager, - IServiceManager _serviceManager - ) SlasherStorage(_allocationManager, _serviceManager) { + ISlashingRegistryCoordinator _registryCoordinator + ) SlasherStorage(_allocationManager, _registryCoordinator) { _disableInitializers(); } @@ -33,7 +32,10 @@ abstract contract SlasherBase is Initializable, SlasherStorage { uint256 _requestId, IAllocationManager.SlashingParams memory _params ) internal virtual { - allocationManager.slashOperator({avs: address(serviceManager), params: _params}); + allocationManager.slashOperator({ + avs: slashingRegistryCoordinator.accountIdentifier(), + params: _params + }); emit OperatorSlashed( _requestId, _params.operator, diff --git a/src/slashers/base/SlasherStorage.sol b/src/slashers/base/SlasherStorage.sol index 1b8d0b1b..54627326 100644 --- a/src/slashers/base/SlasherStorage.sol +++ b/src/slashers/base/SlasherStorage.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.27; import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; import {ISlasher} from "../../interfaces/ISlasher.sol"; -import {IServiceManager} from "../../interfaces/IServiceManager.sol"; +import {ISlashingRegistryCoordinator} from "../../interfaces/ISlashingRegistryCoordinator.sol"; contract SlasherStorage is ISlasher { /** @@ -15,9 +15,8 @@ contract SlasherStorage is ISlasher { /// @notice the AllocationManager that tracks OperatorSets and Slashing in EigenLayer IAllocationManager public immutable allocationManager; - /// @notice the ServiceManager for this AVS, which forwards calls onto EigenLayer's core contracts - IServiceManager public immutable serviceManager; - + /// @notice the SlashingRegistryCoordinator for this AVS + ISlashingRegistryCoordinator public immutable slashingRegistryCoordinator; /** * * STATE @@ -27,9 +26,12 @@ contract SlasherStorage is ISlasher { uint256 public nextRequestId; - constructor(IAllocationManager _allocationManager, IServiceManager _serviceManager) { + constructor( + IAllocationManager _allocationManager, + ISlashingRegistryCoordinator _slashingRegistryCoordinator + ) { allocationManager = _allocationManager; - serviceManager = _serviceManager; + slashingRegistryCoordinator = _slashingRegistryCoordinator; } uint256[48] private __gap; diff --git a/test/ffi/BLSPubKeyCompendiumFFI.t.sol b/test/ffi/BLSPubKeyCompendiumFFI.t.sol index b2c078b2..78d3ca72 100644 --- a/test/ffi/BLSPubKeyCompendiumFFI.t.sol +++ b/test/ffi/BLSPubKeyCompendiumFFI.t.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.27; import "../../src/BLSApkRegistry.sol"; import "../ffi/util/G2Operations.sol"; import {IBLSApkRegistry} from "../../src/interfaces/IBLSApkRegistry.sol"; +import {ISlashingRegistryCoordinator} from "../../src/interfaces/ISlashingRegistryCoordinator.sol"; contract BLSApkRegistryFFITests is G2Operations { using BN254 for BN254.G1Point; @@ -12,7 +13,7 @@ contract BLSApkRegistryFFITests is G2Operations { Vm cheats = Vm(VM_ADDRESS); BLSApkRegistry blsApkRegistry; - IRegistryCoordinator registryCoordinator; + ISlashingRegistryCoordinator registryCoordinator; uint256 privKey; IBLSApkRegistry.PubkeyRegistrationParams pubkeyRegistrationParams; diff --git a/test/harnesses/BLSApkRegistryHarness.sol b/test/harnesses/BLSApkRegistryHarness.sol index 1ee7df30..b97ba955 100644 --- a/test/harnesses/BLSApkRegistryHarness.sol +++ b/test/harnesses/BLSApkRegistryHarness.sol @@ -6,8 +6,8 @@ import "../../src/BLSApkRegistry.sol"; // wrapper around the BLSApkRegistry contract that exposes internal functionality, for unit testing _other functionality_. contract BLSApkRegistryHarness is BLSApkRegistry { constructor( - IRegistryCoordinator _registryCoordinator - ) BLSApkRegistry(_registryCoordinator) {} + ISlashingRegistryCoordinator _slashingRegistryCoordinator + ) BLSApkRegistry(_slashingRegistryCoordinator) {} function setBLSPublicKey(address account, BN254.G1Point memory pk) external { bytes32 pubkeyHash = BN254.hashG1Point(pk); diff --git a/test/harnesses/RegistryCoordinatorHarness.t.sol b/test/harnesses/RegistryCoordinatorHarness.t.sol index c6b6cb3b..8d6e6bc4 100644 --- a/test/harnesses/RegistryCoordinatorHarness.t.sol +++ b/test/harnesses/RegistryCoordinatorHarness.t.sol @@ -45,7 +45,7 @@ contract RegistryCoordinatorHarness is RegistryCoordinator, Test { string memory socket, SignatureWithSaltAndExpiry memory operatorSignature ) external returns (RegisterResults memory results) { - return _registerOperator(operator, operatorId, quorumNumbers, socket, operatorSignature); + return _registerOperator(operator, operatorId, quorumNumbers, socket); } // @notice exposes the internal `_deregisterOperator` function, overriding all access controls @@ -66,4 +66,12 @@ contract RegistryCoordinatorHarness is RegistryCoordinator, Test { function _updateOperatorBitmapExternal(bytes32 operatorId, uint192 quorumBitmap) external { _updateOperatorBitmap(operatorId, quorumBitmap); } + + function setOperatorSetsEnabled(bool enabled) external { + operatorSetsEnabled = enabled; + } + + function setM2QuorumsDisabled(bool disabled) external { + m2QuorumsDisabled = disabled; + } } diff --git a/test/harnesses/StakeRegistryHarness.sol b/test/harnesses/StakeRegistryHarness.sol index 4e156aac..3fe3a187 100644 --- a/test/harnesses/StakeRegistryHarness.sol +++ b/test/harnesses/StakeRegistryHarness.sol @@ -6,20 +6,12 @@ import "../../src/StakeRegistry.sol"; // wrapper around the StakeRegistry contract that exposes the internal functions for unit testing. contract StakeRegistryHarness is StakeRegistry { constructor( - IRegistryCoordinator _registryCoordinator, + ISlashingRegistryCoordinator _registryCoordinator, IDelegationManager _delegationManager, IAVSDirectory _avsDirectory, - IAllocationManager _allocationManager, - IServiceManager _serviceManager - ) - StakeRegistry( - _registryCoordinator, - _delegationManager, - _avsDirectory, - _allocationManager, - _serviceManager - ) - {} + IAllocationManager _allocationManager + ) StakeRegistry(_registryCoordinator, _delegationManager, _avsDirectory, _allocationManager) { + } function recordOperatorStakeUpdate( bytes32 operatorId, diff --git a/test/integration/IntegrationBase.t.sol b/test/integration/IntegrationBase.t.sol index 15371667..388535c6 100644 --- a/test/integration/IntegrationBase.t.sol +++ b/test/integration/IntegrationBase.t.sol @@ -29,24 +29,22 @@ abstract contract IntegrationBase is IntegrationConfig { /// @dev Also checks that the user has NEVER_REGISTERED status function assert_HasNoOperatorInfo(User user, string memory err) internal { - IRegistryCoordinator.OperatorInfo memory info = _getOperatorInfo(user); + ISlashingRegistryCoordinator.OperatorInfo memory info = _getOperatorInfo(user); assertEq(info.operatorId, bytes32(0), err); - assertTrue(info.status == IRegistryCoordinator.OperatorStatus.NEVER_REGISTERED, err); + assertTrue(info.status == ISlashingRegistryCoordinator.OperatorStatus.NEVER_REGISTERED, err); } function assert_HasRegisteredStatus(User user, string memory err) internal { - IRegistryCoordinator.OperatorStatus status = - registryCoordinator.getOperatorStatus(address(user)); + ISlashingRegistryCoordinator.OperatorStatus status = registryCoordinator.getOperatorStatus(address(user)); - assertTrue(status == IRegistryCoordinator.OperatorStatus.REGISTERED, err); + assertTrue(status == ISlashingRegistryCoordinator.OperatorStatus.REGISTERED, err); } function assert_HasDeregisteredStatus(User user, string memory err) internal { - IRegistryCoordinator.OperatorStatus status = - registryCoordinator.getOperatorStatus(address(user)); + ISlashingRegistryCoordinator.OperatorStatus status = registryCoordinator.getOperatorStatus(address(user)); - assertTrue(status == IRegistryCoordinator.OperatorStatus.DEREGISTERED, err); + assertTrue(status == ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED, err); } function assert_EmptyQuorumBitmap(User user, string memory err) internal { @@ -243,8 +241,8 @@ abstract contract IntegrationBase is IntegrationConfig { } function assert_Snap_Unchanged_OperatorInfo(User user, string memory err) internal { - IRegistryCoordinator.OperatorInfo memory curInfo = _getOperatorInfo(user); - IRegistryCoordinator.OperatorInfo memory prevInfo = _getPrevOperatorInfo(user); + ISlashingRegistryCoordinator.OperatorInfo memory curInfo = _getOperatorInfo(user); + ISlashingRegistryCoordinator.OperatorInfo memory prevInfo = _getPrevOperatorInfo(user); assertEq(prevInfo.operatorId, curInfo.operatorId, err); assertTrue(prevInfo.status == curInfo.status, err); @@ -864,15 +862,11 @@ abstract contract IntegrationBase is IntegrationConfig { /// RegistryCoordinator: - function _getOperatorInfo( - User user - ) internal view returns (IRegistryCoordinator.OperatorInfo memory) { + function _getOperatorInfo(User user) internal view returns (ISlashingRegistryCoordinator.OperatorInfo memory) { return registryCoordinator.getOperator(address(user)); } - function _getPrevOperatorInfo( - User user - ) internal timewarp returns (IRegistryCoordinator.OperatorInfo memory) { + function _getPrevOperatorInfo(User user) internal timewarp() returns (ISlashingRegistryCoordinator.OperatorInfo memory) { return _getOperatorInfo(user); } diff --git a/test/integration/IntegrationConfig.t.sol b/test/integration/IntegrationConfig.t.sol index e04a7204..4581372f 100644 --- a/test/integration/IntegrationConfig.t.sol +++ b/test/integration/IntegrationConfig.t.sol @@ -158,8 +158,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { emit log_named_uint("_configRand: number of quorums being initialized", quorumCount); // Default OperatorSetParams for all quorums - IRegistryCoordinator.OperatorSetParam memory operatorSet = IRegistryCoordinator - .OperatorSetParam({ + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSet = ISlashingRegistryCoordinator.OperatorSetParam({ maxOperatorCount: MAX_OPERATOR_COUNT, kickBIPsOfOperatorStake: KICK_BIPS_OPERATOR_STAKE, kickBIPsOfTotalStake: KICK_BIPS_TOTAL_STAKE @@ -318,8 +317,8 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { for (uint256 i = 0; i < churnQuorums.length; i++) { uint8 quorum = uint8(churnQuorums[i]); - IRegistryCoordinator.OperatorSetParam memory params = - registryCoordinator.getOperatorSetParams(quorum); + ISlashingRegistryCoordinator.OperatorSetParam memory params + = registryCoordinator.getOperatorSetParams(quorum); // Sanity check - make sure we're at the operator cap uint32 curNumOperators = indexRegistry.totalOperatorsForQuorum(quorum); @@ -365,7 +364,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// From RegistryCoordinator._individualKickThreshold function _individualKickThreshold( uint96 operatorStake, - IRegistryCoordinator.OperatorSetParam memory setParams + ISlashingRegistryCoordinator.OperatorSetParam memory setParams ) internal pure returns (uint96) { return operatorStake * setParams.kickBIPsOfOperatorStake / BIPS_DENOMINATOR; } @@ -373,7 +372,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// From RegistryCoordinator._totalKickThreshold function _totalKickThreshold( uint96 totalStake, - IRegistryCoordinator.OperatorSetParam memory setParams + ISlashingRegistryCoordinator.OperatorSetParam memory setParams ) internal pure returns (uint96) { return totalStake * setParams.kickBIPsOfTotalStake / BIPS_DENOMINATOR; } @@ -565,10 +564,8 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { * @dev Uses _randFillType to determine how many operators to register for a quorum initially * @return The number of operators to register */ - function _randInitialOperators( - IRegistryCoordinator.OperatorSetParam memory operatorSet - ) private returns (uint256) { - uint256 fillTypeFlag = _randValue(fillTypeFlags); + function _randInitialOperators(ISlashingRegistryCoordinator.OperatorSetParam memory operatorSet) private returns (uint) { + uint fillTypeFlag = _randValue(fillTypeFlags); if (fillTypeFlag == EMPTY) { return 0; diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index f1899fe7..323c1cc8 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -195,7 +195,6 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { new StrategyManager(delegationManager, pauserRegistry); EigenPodManager eigenPodManagerImplementation = new EigenPodManager(ethPOSDeposit, eigenPodBeacon, delegationManager, pauserRegistry); - console.log("HERE Impl"); AVSDirectory avsDirectoryImplementation = new AVSDirectory(delegationManager, pauserRegistry); @@ -340,20 +339,16 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { cheats.stopPrank(); StakeRegistry stakeRegistryImplementation = new StakeRegistry( - IRegistryCoordinator(registryCoordinator), - IDelegationManager(delegationManager), - IAVSDirectory(avsDirectory), - allocationManager, - IServiceManager(serviceManager) + ISlashingRegistryCoordinator(registryCoordinator), IDelegationManager(delegationManager), IAVSDirectory(avsDirectory), allocationManager ); BLSApkRegistry blsApkRegistryImplementation = - new BLSApkRegistry(IRegistryCoordinator(registryCoordinator)); + new BLSApkRegistry(ISlashingRegistryCoordinator(registryCoordinator)); IndexRegistry indexRegistryImplementation = - new IndexRegistry(IRegistryCoordinator(registryCoordinator)); + new IndexRegistry(ISlashingRegistryCoordinator(registryCoordinator)); ServiceManagerMock serviceManagerImplementation = new ServiceManagerMock( IAVSDirectory(avsDirectory), rewardsCoordinator, - IRegistryCoordinator(registryCoordinator), + ISlashingRegistryCoordinator(registryCoordinator), stakeRegistry, permissionController, allocationManager @@ -399,20 +394,80 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { TransparentUpgradeableProxy(payable(address(registryCoordinator))), address(registryCoordinatorImplementation), abi.encodeWithSelector( - RegistryCoordinator.initialize.selector, + SlashingRegistryCoordinator.initialize.selector, registryCoordinatorOwner, churnApprover, ejector, 0, /*initialPausedStatus*/ - new IRegistryCoordinator.OperatorSetParam[](0), - new uint96[](0), - new IStakeRegistry.StrategyParams[][](0), - quorumStakeTypes, - slashableStakeQuorumLookAheadPeriods + address(serviceManager) // _accountIdentifier ) ); operatorStateRetriever = new OperatorStateRetriever(); + + // Setup UAM Permissions + cheats.startPrank(serviceManager.owner()); + // 1. set AVS registrar + serviceManager.setAppointee({ + appointee: serviceManager.owner(), + target: address(allocationManager), + selector: IAllocationManager.setAVSRegistrar.selector + }); + // 2. create operator sets + serviceManager.setAppointee({ + appointee: address(registryCoordinator), + target: address(allocationManager), + selector: IAllocationManager.createOperatorSets.selector + }); + // 3. deregister operator from operator sets + serviceManager.setAppointee({ + appointee: address(registryCoordinator), + target: address(allocationManager), + selector: IAllocationManager.deregisterFromOperatorSets.selector + }); + // 4. add strategies to operator sets + serviceManager.setAppointee({ + appointee: address(registryCoordinator), + target: address(stakeRegistry), + selector: IAllocationManager.addStrategiesToOperatorSet.selector + }); + // 5. remove strategies from operator sets + serviceManager.setAppointee({ + appointee: address(registryCoordinator), + target: address(stakeRegistry), + selector: IAllocationManager.removeStrategiesFromOperatorSet.selector + }); + cheats.stopPrank(); + + _setOperatorSetsEnabled(false); + _setM2QuorumsDisabled(false); + } + + /// @notice Overwrite RegistryCoordinator.operatorSetsEnabled to the specified value. + /// This is to enable testing of RegistryCoordinator in non-operator set mode. + function _setOperatorSetsEnabled(bool operatorSetsEnabled) internal { + // 1. First read the current value of the entire slot + // which holds operatorSetsEnabled, m2QuorumsDisabled, and accountIdentifier + bytes32 currentSlot = cheats.load(address(registryCoordinator), bytes32(uint256(161))); + + // 2. Clear only the first byte (operatorSetsEnabled) while keeping the rest + bytes32 newSlot = (currentSlot & ~bytes32(uint256(0xff))) | bytes32(uint256(operatorSetsEnabled ? 0x01 : 0x00)); + + // 3. Store the modified slot + cheats.store(address(registryCoordinator), bytes32(uint256(161)), newSlot); + } + + /// @notice Overwrite RegistryCoordinator.m2QuorumsDisabled to the specified value. + function _setM2QuorumsDisabled(bool m2QuorumsDisabled) internal { + // 1. First read the current value of the entire slot + // which holds operatorSetsEnabled, m2QuorumsDisabled, and accountIdentifier + bytes32 currentSlot = cheats.load(address(registryCoordinator), bytes32(uint256(161))); + + // 2. Clear only the second byte (m2QuorumsDisabled) while keeping the rest + bytes32 newSlot = (currentSlot & ~bytes32(uint256(0xff) << 8)) | bytes32(uint256(m2QuorumsDisabled ? 0x01 : 0x00) << 8); + + // 3. Store the modified slot + cheats.store(address(registryCoordinator), bytes32(uint256(161)), newSlot); } /// @dev Deploy a strategy and its underlying token, push to global lists of tokens/strategies, and whitelist diff --git a/test/integration/User.t.sol b/test/integration/User.t.sol index fbc491f5..42e8740e 100644 --- a/test/integration/User.t.sol +++ b/test/integration/User.t.sol @@ -160,8 +160,8 @@ contract User is Test { bytes memory allQuorums = churnBitmap.plus(standardBitmap).bitmapToBytesArray(); - IRegistryCoordinator.OperatorKickParam[] memory kickParams = - new IRegistryCoordinator.OperatorKickParam[](allQuorums.length); + ISlashingRegistryCoordinator.OperatorKickParam[] memory kickParams + = new ISlashingRegistryCoordinator.OperatorKickParam[](allQuorums.length); // this constructs OperatorKickParam[] in ascending quorum order // (yikes) @@ -169,20 +169,22 @@ contract User is Test { uint256 stdIdx; while (churnIdx + stdIdx < allQuorums.length) { if (churnIdx == churnQuorums.length) { - kickParams[churnIdx + stdIdx] = - IRegistryCoordinator.OperatorKickParam({quorumNumber: 0, operator: address(0)}); + kickParams[churnIdx + stdIdx] = ISlashingRegistryCoordinator.OperatorKickParam({ + quorumNumber: 0, + operator: address(0) + }); stdIdx++; - } else if ( - stdIdx == standardQuorums.length || churnQuorums[churnIdx] < standardQuorums[stdIdx] - ) { - kickParams[churnIdx + stdIdx] = IRegistryCoordinator.OperatorKickParam({ + } else if (stdIdx == standardQuorums.length || churnQuorums[churnIdx] < standardQuorums[stdIdx]) { + kickParams[churnIdx + stdIdx] = ISlashingRegistryCoordinator.OperatorKickParam({ quorumNumber: uint8(churnQuorums[churnIdx]), operator: address(churnTargets[churnIdx]) }); churnIdx++; } else if (standardQuorums[stdIdx] < churnQuorums[churnIdx]) { - kickParams[churnIdx + stdIdx] = - IRegistryCoordinator.OperatorKickParam({quorumNumber: 0, operator: address(0)}); + kickParams[churnIdx + stdIdx] = ISlashingRegistryCoordinator.OperatorKickParam({ + quorumNumber: 0, + operator: address(0) + }); stdIdx++; } else { revert("User.registerOperatorWithChurn: malformed input"); diff --git a/test/mocks/AVSDirectoryMock.sol b/test/mocks/AVSDirectoryMock.sol index 0271add0..d76f1abf 100644 --- a/test/mocks/AVSDirectoryMock.sol +++ b/test/mocks/AVSDirectoryMock.sol @@ -68,7 +68,7 @@ contract AVSDirectoryMock is IAVSDirectory { function operatorSaltIsSpent(address operator, bytes32 salt) external view returns (bool) {} - function isOperatorSetAVS( + function operatorSetsEnabled( address avs ) external view returns (bool) {} diff --git a/test/mocks/AVSRegistrarMock.sol b/test/mocks/AVSRegistrarMock.sol index ce4ce2bc..2684275c 100644 --- a/test/mocks/AVSRegistrarMock.sol +++ b/test/mocks/AVSRegistrarMock.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {AVSRegistrar} from "../../src/AVSRegistrar.sol"; +import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; -contract AVSRegistrarMock is AVSRegistrar { + +contract AVSRegistrarMock is IAVSRegistrar { function registerOperator( address operator, uint32[] calldata operatorSetIds, diff --git a/test/mocks/RegistryCoordinatorMock.sol b/test/mocks/RegistryCoordinatorMock.sol index d0464db2..533e14ef 100644 --- a/test/mocks/RegistryCoordinatorMock.sol +++ b/test/mocks/RegistryCoordinatorMock.sol @@ -2,8 +2,10 @@ pragma solidity ^0.8.27; import "../../src/interfaces/IRegistryCoordinator.sol"; +import "../../src/interfaces/ISlashingRegistryCoordinator.sol"; -contract RegistryCoordinatorMock is IRegistryCoordinator { + +contract RegistryCoordinatorMock is ISlashingRegistryCoordinator, IRegistryCoordinator { function blsApkRegistry() external view returns (IBLSApkRegistry) {} function ejectOperator(address operator, bytes calldata quorumNumbers) external {} @@ -37,9 +39,7 @@ contract RegistryCoordinatorMock is IRegistryCoordinator { ) external view returns (address) {} /// @notice Returns the status for the given `operator` - function getOperatorStatus( - address operator - ) external view returns (IRegistryCoordinator.OperatorStatus) {} + function getOperatorStatus(address operator) external view returns (OperatorStatus){} /// @notice Returns task number from when `operator` has been registered. function getFromTaskNumberForOperator( @@ -104,7 +104,29 @@ contract RegistryCoordinatorMock is IRegistryCoordinator { return false; } - function isOperatorSetAVS() external view returns (bool) { - return false; - } + function accountIdentifier() external view returns (address) {} + + function deregisterOperator(bytes memory quorumNumbers) external {} + + function enableOperatorSets() external {} + + function registerOperator( + bytes memory quorumNumbers, + string memory socket, + IBLSApkRegistry.PubkeyRegistrationParams memory params, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external {} + + function registerOperatorWithChurn( + bytes calldata quorumNumbers, + string memory socket, + IBLSApkRegistry.PubkeyRegistrationParams memory params, + ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams, + ISignatureUtils.SignatureWithSaltAndExpiry memory churnApproverSignature, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external {} + + function disableM2QuorumRegistration() external {} + + function operatorSetsEnabled() external view returns (bool) {} } diff --git a/test/mocks/ServiceManagerMock.sol b/test/mocks/ServiceManagerMock.sol index 68fbdf4c..b33df503 100644 --- a/test/mocks/ServiceManagerMock.sol +++ b/test/mocks/ServiceManagerMock.sol @@ -7,7 +7,7 @@ contract ServiceManagerMock is ServiceManagerBase { constructor( IAVSDirectory _avsDirectory, IRewardsCoordinator _rewardsCoordinator, - IRegistryCoordinator _registryCoordinator, + ISlashingRegistryCoordinator _slashingRegistryCoordinator, IStakeRegistry _stakeRegistry, IPermissionController _permissionController, IAllocationManager _allocationManager @@ -15,7 +15,7 @@ contract ServiceManagerMock is ServiceManagerBase { ServiceManagerBase( _avsDirectory, _rewardsCoordinator, - _registryCoordinator, + _slashingRegistryCoordinator, _stakeRegistry, _permissionController, _allocationManager diff --git a/test/unit/EjectionManagerUnit.t.sol b/test/unit/EjectionManagerUnit.t.sol index 2cfa859e..886a94f5 100644 --- a/test/unit/EjectionManagerUnit.t.sol +++ b/test/unit/EjectionManagerUnit.t.sol @@ -80,10 +80,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } - assertEq( - uint8(registryCoordinator.getOperatorStatus(defaultOperator)), - uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) - ); + assertEq(uint8(registryCoordinator.getOperatorStatus(defaultOperator)), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); for (uint8 i = 0; i < numQuorums; i++) { for (uint8 j = 0; j < operatorsToEject; j++) { @@ -95,10 +92,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - assertEq( - uint8(registryCoordinator.getOperatorStatus(defaultOperator)), - uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) - ); + assertEq(uint8(registryCoordinator.getOperatorStatus(defaultOperator)), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); } function testEjectOperators_MultipleOperatorInsideRatelimit() public { @@ -116,11 +110,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } - for (uint8 i = 0; i < operatorsToEject; i++) { - assertEq( - uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), - uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) - ); + for(uint8 i = 0; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); } for (uint8 i = 0; i < numQuorums; i++) { @@ -133,11 +124,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for (uint8 i = 0; i < operatorsToEject; i++) { - assertEq( - uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), - uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) - ); + for(uint8 i = 0; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); } } @@ -157,11 +145,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } - for (uint8 i = 0; i < operatorsToEject; i++) { - assertEq( - uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), - uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) - ); + for(uint8 i = 0; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); } for (uint8 i = 0; i < numQuorums; i++) { @@ -174,18 +159,12 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for (uint8 i = 0; i < operatorsCanEject; i++) { - assertEq( - uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), - uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) - ); + for(uint8 i = 0; i < operatorsCanEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); } - for (uint8 i = operatorsCanEject; i < operatorsToEject; i++) { - assertEq( - uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), - uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) - ); + for(uint8 i = operatorsCanEject; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); } } @@ -204,11 +183,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } - for (uint8 i = 0; i < operatorsToEject; i++) { - assertEq( - uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), - uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) - ); + for(uint8 i = 0; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); } for (uint8 i = 0; i < numQuorums; i++) { @@ -221,11 +197,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for (uint8 i = 0; i < operatorsToEject; i++) { - assertEq( - uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), - uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) - ); + for(uint8 i = 0; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); } cheats.warp(block.timestamp + (ratelimitWindow / 2)); @@ -240,15 +213,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } - for (uint8 i = 0; i < operatorsToEject; i++) { - assertEq( - uint8( - registryCoordinator.getOperatorStatus( - _incrementAddress(defaultOperator, operatorsToEject + i) - ) - ), - uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) - ); + for(uint8 i = 0; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, operatorsToEject + i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); } for (uint8 i = 0; i < numQuorums; i++) { @@ -261,15 +227,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for (uint8 i = 0; i < operatorsToEject; i++) { - assertEq( - uint8( - registryCoordinator.getOperatorStatus( - _incrementAddress(defaultOperator, operatorsToEject + i) - ) - ), - uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) - ); + for(uint8 i = 0; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, operatorsToEject + i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); } } @@ -295,11 +254,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } - for (uint8 i = 0; i < operatorsToEject; i++) { - assertEq( - uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), - uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) - ); + for(uint8 i = 0; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); } for (uint8 i = 0; i < numQuorums; i++) { @@ -312,11 +268,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for (uint8 i = 0; i < operatorsToEject; i++) { - assertEq( - uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), - uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) - ); + for(uint8 i = 0; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); } } @@ -335,11 +288,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } - for (uint8 i = 0; i < operatorsToEject; i++) { - assertEq( - uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), - uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) - ); + for(uint8 i = 0; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); } for (uint8 i = 0; i < numQuorums; i++) { @@ -352,11 +302,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(registryCoordinatorOwner); ejectionManager.ejectOperators(operatorIds); - for (uint8 i = 0; i < operatorsToEject; i++) { - assertEq( - uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), - uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) - ); + for(uint8 i = 0; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); } } @@ -378,11 +325,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(defaultOperator); registryCoordinator.deregisterOperator(BitmapUtils.bitmapToBytesArray(MAX_QUORUM_BITMAP)); - for (uint8 i = 1; i < operatorsToEject; i++) { - assertEq( - uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), - uint8(IRegistryCoordinator.OperatorStatus.REGISTERED) - ); + for(uint8 i = 1; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); } for (uint8 i = 0; i < numQuorums; i++) { @@ -395,11 +339,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for (uint8 i = 0; i < operatorsToEject; i++) { - assertEq( - uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), - uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED) - ); + for(uint8 i = 0; i < operatorsToEject; i++) { + assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); } } diff --git a/test/unit/OperatorStateRetrieverUnit.t.sol b/test/unit/OperatorStateRetrieverUnit.t.sol index e16621fc..cc40349c 100644 --- a/test/unit/OperatorStateRetrieverUnit.t.sol +++ b/test/unit/OperatorStateRetrieverUnit.t.sol @@ -81,7 +81,7 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { function test_getOperatorState_revert_quorumNotCreatedAtReferenceBlockNumber() public { cheats.roll(registrationBlockNumber); - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator .OperatorSetParam({ maxOperatorCount: defaultMaxOperatorCount, kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, @@ -223,7 +223,7 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { bytes32[] memory nonSignerOperatorIds = new bytes32[](1); nonSignerOperatorIds[0] = defaultOperatorId; - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator .OperatorSetParam({ maxOperatorCount: defaultMaxOperatorCount, kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, @@ -254,6 +254,11 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { uint256 quorumBitmapTwo = 2; uint256 quorumBitmapThree = 3; + assertFalse( + registryCoordinator.operatorSetsEnabled(), + "operatorSetsEnabled should be false" + ); + cheats.roll(registrationBlockNumber); _registerOperatorWithCoordinator(defaultOperator, quorumBitmapOne, defaultPubKey); diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index 4afc62bf..06a19576 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -2,13 +2,14 @@ pragma solidity ^0.8.27; import "../utils/MockAVSDeployer.sol"; -import {IRegistryCoordinatorErrors} from "../../src/interfaces/IRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator, IRegistryCoordinatorErrors} from "../../src/interfaces/ISlashingRegistryCoordinator.sol"; import {QuorumBitmapHistoryLib} from "../../src/libraries/QuorumBitmapHistoryLib.sol"; import {BitmapUtils} from "../../src/libraries/BitmapUtils.sol"; import {console} from "forge-std/console.sol"; contract RegistryCoordinatorUnitTests is MockAVSDeployer { using BN254 for BN254.G1Point; + using stdStorage for StdStorage; uint8 internal constant PAUSED_REGISTER_OPERATOR = 0; uint8 internal constant PAUSED_DEREGISTER_OPERATOR = 1; @@ -34,9 +35,7 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { // emitted when an operator's index in the orderd operator list for the quorum with number `quorumNumber` is updated event QuorumIndexUpdate(bytes32 indexed operatorId, uint8 quorumNumber, uint32 newIndex); - event OperatorSetParamsUpdated( - uint8 indexed quorumNumber, IRegistryCoordinator.OperatorSetParam operatorSetParams - ); + event OperatorSetParamsUpdated(uint8 indexed quorumNumber, ISlashingRegistryCoordinator.OperatorSetParam operatorSetParams); event ChurnApproverUpdated(address prevChurnApprover, address newChurnApprover); @@ -52,14 +51,11 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { uint256 pseudoRandomNumber, bytes memory quorumNumbers, uint96 operatorToKickStake - ) - internal - returns ( - address operatorToRegister, - BN254.G1Point memory operatorToRegisterPubKey, - IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams - ) - { + ) internal returns( + address operatorToRegister, + BN254.G1Point memory operatorToRegisterPubKey, + ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams + ) { uint32 kickRegistrationBlockNumber = 100; uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); @@ -82,7 +78,7 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { address operatorToKick; // register last operator before kick - operatorKickParams = new IRegistryCoordinator.OperatorKickParam[](1); + operatorKickParams = new ISlashingRegistryCoordinator.OperatorKickParam[](1); { BN254.G1Point memory pubKey = BN254.hashToG1( keccak256(abi.encodePacked(pseudoRandomNumber, defaultMaxOperatorCount - 1)) @@ -99,7 +95,7 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { // operatorIdsToSwap[0] = operatorToRegisterId operatorIdsToSwap[0] = operatorToRegisterId; - operatorKickParams[0] = IRegistryCoordinator.OperatorKickParam({ + operatorKickParams[0] = ISlashingRegistryCoordinator.OperatorKickParam({ quorumNumber: uint8(quorumNumbers[0]), operator: operatorToKick }); @@ -129,12 +125,8 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina registryCoordinatorOwner, churnApprover, ejector, - 0, /*initialPausedStatus*/ - operatorSetParams, - new uint96[](0), - new IStakeRegistry.StrategyParams[][](0), - new StakeType[](0), - new uint32[](0) + 0/*initialPausedStatus*/, + address(serviceManager) // _accountIdentifier ); } @@ -208,7 +200,7 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina } function test_createQuorum_revert_notOwner() public { - IRegistryCoordinator.OperatorSetParam memory operatorSetParams; + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams; uint96 minimumStake; IStakeRegistry.StrategyParams[] memory strategyParams; @@ -224,12 +216,12 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina // this is necessary since the default setup already configures the max number of quorums, preventing adding more _deployMockEigenLayerAndAVS(0); - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator - .OperatorSetParam({ - maxOperatorCount: defaultMaxOperatorCount, - kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, - kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake - }); + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = + ISlashingRegistryCoordinator.OperatorSetParam({ + maxOperatorCount: defaultMaxOperatorCount, + kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, + kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake + }); uint96 minimumStake = 1; IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); @@ -340,29 +332,19 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }) - ) - ) + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED + }))) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256( - abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }))) ); } @@ -383,21 +365,18 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni cheats.expectEmit(true, true, true, true, address(registryCoordinator)); emit OperatorSocketUpdate(defaultOperatorId, defaultSocket); - cheats.expectEmit(true, true, true, true, address(registryCoordinator)); - emit OperatorRegistered(defaultOperator, defaultOperatorId); - cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); emit OperatorAddedToQuorums(defaultOperator, defaultOperatorId, quorumNumbers); - for (uint256 i = 0; i < quorumNumbers.length; i++) { cheats.expectEmit(true, true, true, true, address(stakeRegistry)); emit OperatorStakeUpdate(defaultOperatorId, uint8(quorumNumbers[i]), actualStake); } - for (uint256 i = 0; i < quorumNumbers.length; i++) { cheats.expectEmit(true, true, true, true, address(indexRegistry)); emit QuorumIndexUpdate(defaultOperatorId, uint8(quorumNumbers[i]), 0); } + cheats.expectEmit(true, true, true, true, address(registryCoordinator)); + emit OperatorRegistered(defaultOperator, defaultOperatorId); uint256 gasBefore = gasleft(); cheats.prank(defaultOperator); @@ -411,29 +390,19 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }) - ) - ) + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED + }))) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256( - abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }))) ); } @@ -478,43 +447,27 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }) - ) - ) + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED + }))) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256( - abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers)), - updateBlockNumber: uint32(registrationBlockNumber), - nextUpdateBlockNumber: uint32(nextRegistrationBlockNumber) - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers)), + updateBlockNumber: uint32(registrationBlockNumber), + nextUpdateBlockNumber: uint32(nextRegistrationBlockNumber) + }))) ); assertEq( - keccak256( - abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1)) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(nextRegistrationBlockNumber), - nextUpdateBlockNumber: 0 - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(nextRegistrationBlockNumber), + nextUpdateBlockNumber: 0 + }))) ); } @@ -640,32 +593,14 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); - assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); - assertEq( - keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }) - ) - ) - ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256( - abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }))) ); } } @@ -691,6 +626,10 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is } function test_deregisterOperator_revert_notRegistered() public { + // enable operatorSets + cheats.prank(registryCoordinator.owner()); + registryCoordinator.enableOperatorSets(); + bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); @@ -700,17 +639,24 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is } function test_deregisterOperator_revert_incorrectQuorums() public { + // enable operatorSets + cheats.prank(registryCoordinator.owner()); + registryCoordinator.enableOperatorSets(); + + assertTrue( + registryCoordinator.isM2Quorum(uint8(defaultQuorumNumber)), + "defaultQuorumNumber should be a M2 quorum" + ); + bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); - _registerOperatorWithCoordinator(defaultOperator, quorumBitmap, defaultPubKey); - quorumNumbers = new bytes(2); - quorumNumbers[0] = bytes1(defaultQuorumNumber + 1); - quorumNumbers[1] = bytes1(defaultQuorumNumber + 2); + quorumNumbers = new bytes(1); + quorumNumbers[0] = bytes1(defaultQuorumNumber); - cheats.expectRevert(bytes4(keccak256("NotRegisteredForQuorum()"))); + cheats.expectRevert(bytes4(keccak256("NotRegistered()"))); cheats.prank(defaultOperator); registryCoordinator.deregisterOperator(quorumNumbers); } @@ -750,29 +696,19 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.DEREGISTERED - }) - ) - ) + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED + }))) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); assertEq( - keccak256( - abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }))) ); } @@ -819,29 +755,19 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.DEREGISTERED - }) - ) - ) + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED + }))) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); assertEq( - keccak256( - abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }))) ); } // @notice verifies that an operator who was registered for a fuzzed set of quorums can be deregistered from a subset of those quorums @@ -900,26 +826,18 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is if (deregistrationQuorumBitmap == registrationQuorumBitmap) { assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.DEREGISTERED - }) - ) - ) + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED + }))) ); } else { assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }) - ) - ) + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED + }))) ); } // ensure that the operator's current quorum bitmap matches the expectation @@ -930,36 +848,22 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is ); // check that the quorum bitmap history is as expected assertEq( - keccak256( - abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(registrationQuorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(registrationQuorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }))) ); // note: there will be no second entry in the operator's bitmap history in the event that the operator has totally deregistered if (deregistrationQuorumBitmap != registrationQuorumBitmap) { assertEq( - keccak256( - abi.encode( - registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1) - ) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(expectedQuorumBitmap), - updateBlockNumber: deregistrationBlockNumber, - nextUpdateBlockNumber: 0 - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(expectedQuorumBitmap), + updateBlockNumber: deregistrationBlockNumber, + nextUpdateBlockNumber: 0 + }))) ); } } @@ -1036,31 +940,19 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is assertEq( keccak256(abi.encode(registryCoordinator.getOperator(operatorToDeregister))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: operatorToDeregisterId, - status: IRegistryCoordinator.OperatorStatus.DEREGISTERED - }) - ) - ) + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: operatorToDeregisterId, + status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED + }))) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); assertEq( - keccak256( - abi.encode( - registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToDeregisterId, 0) - ) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(operatorToDeregisterQuorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToDeregisterId, 0))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(operatorToDeregisterQuorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }))) ); } @@ -1079,7 +971,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is cheats.roll(reregistrationBlockNumber); // store data before registering, to check against later - IRegistryCoordinator.QuorumBitmapUpdate memory previousQuorumBitmapUpdate = + ISlashingRegistryCoordinator.QuorumBitmapUpdate memory previousQuorumBitmapUpdate = registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0); // re-register the operator @@ -1091,14 +983,10 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId, "1"); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }) - ) - ), + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED + }))), "2" ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap, "3"); @@ -1113,22 +1001,12 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is // check that new entry in bitmap history is as expected uint256 historyLength = registryCoordinator.getQuorumBitmapHistoryLength(defaultOperatorId); assertEq( - keccak256( - abi.encode( - registryCoordinator.getQuorumBitmapUpdateByIndex( - defaultOperatorId, historyLength - 1 - ) - ) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(reregistrationBlockNumber), - nextUpdateBlockNumber: 0 - }) - ) - ), + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, historyLength - 1))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(reregistrationBlockNumber), + nextUpdateBlockNumber: 0 + }))), "5" ); } @@ -1303,26 +1181,18 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is if (deregistrationQuorumBitmap == registrationQuorumBitmap) { assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.DEREGISTERED - }) - ) - ) + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED + }))) ); } else { assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }) - ) - ) + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED + }))) ); } // ensure that the operator's current quorum bitmap matches the expectation @@ -1333,36 +1203,22 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is ); // check that the quorum bitmap history is as expected assertEq( - keccak256( - abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(registrationQuorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(registrationQuorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }))) ); // note: there will be no second entry in the operator's bitmap history in the event that the operator has totally deregistered if (deregistrationQuorumBitmap != registrationQuorumBitmap) { assertEq( - keccak256( - abi.encode( - registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1) - ) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(expectedQuorumBitmap), - updateBlockNumber: deregistrationBlockNumber, - nextUpdateBlockNumber: 0 - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(expectedQuorumBitmap), + updateBlockNumber: deregistrationBlockNumber, + nextUpdateBlockNumber: 0 + }))) ); } } @@ -1393,14 +1249,10 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is // make sure the operator is deregistered assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.DEREGISTERED - }) - ) - ) + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED + }))) ); // make sure the operator is not in any quorums assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); @@ -1438,14 +1290,10 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is // make sure the operator is registered assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }) - ) - ) + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED + }))) ); // make sure the operator is properly removed from the quorums assertEq( @@ -1676,8 +1524,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord address operatorToKick; // register last operator before kick - IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = - new IRegistryCoordinator.OperatorKickParam[](1); + ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = new ISlashingRegistryCoordinator.OperatorKickParam[](1); { BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, numOperators - 1))); @@ -1690,7 +1537,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord // operatorIdsToSwap[0] = operatorToRegisterId operatorIdsToSwap[0] = operatorToRegisterId; - operatorKickParams[0] = IRegistryCoordinator.OperatorKickParam({ + operatorKickParams[0] = ISlashingRegistryCoordinator.OperatorKickParam({ quorumNumber: defaultQuorumNumber, operator: operatorToKick }); @@ -1704,26 +1551,25 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord cheats.roll(registrationBlockNumber); cheats.expectEmit(true, true, true, true, address(registryCoordinator)); emit OperatorSocketUpdate(operatorToRegisterId, defaultSocket); - cheats.expectEmit(true, true, true, true, address(registryCoordinator)); - emit OperatorRegistered(operatorToRegister, operatorToRegisterId); cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); emit OperatorAddedToQuorums(operatorToRegister, operatorToRegisterId, quorumNumbers); cheats.expectEmit(true, true, true, false, address(stakeRegistry)); - emit OperatorStakeUpdate(operatorToRegisterId, defaultQuorumNumber, registeringStake - 1); + emit OperatorStakeUpdate(operatorToRegisterId, defaultQuorumNumber, registeringStake); cheats.expectEmit(true, true, true, true, address(indexRegistry)); emit QuorumIndexUpdate(operatorToRegisterId, defaultQuorumNumber, numOperators); + // Then expect the deregistration events cheats.expectEmit(true, true, true, true, address(registryCoordinator)); emit OperatorDeregistered(operatorKickParams[0].operator, operatorToKickId); cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); - emit OperatorRemovedFromQuorums( - operatorKickParams[0].operator, operatorToKickId, quorumNumbers - ); + emit OperatorRemovedFromQuorums(operatorKickParams[0].operator, operatorToKickId, quorumNumbers); cheats.expectEmit(true, true, true, true, address(stakeRegistry)); emit OperatorStakeUpdate(operatorToKickId, defaultQuorumNumber, 0); cheats.expectEmit(true, true, true, true, address(indexRegistry)); emit QuorumIndexUpdate(operatorToRegisterId, defaultQuorumNumber, numOperators - 1); + cheats.expectEmit(true, true, true, true, address(registryCoordinator)); + emit OperatorRegistered(operatorToRegister, operatorToRegisterId); { ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; @@ -1751,39 +1597,25 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord assertEq( keccak256(abi.encode(registryCoordinator.getOperator(operatorToRegister))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: operatorToRegisterId, - status: IRegistryCoordinator.OperatorStatus.REGISTERED - }) - ) - ) + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: operatorToRegisterId, + status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED + }))) ); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(operatorToKick))), - keccak256( - abi.encode( - IRegistryCoordinator.OperatorInfo({ - operatorId: operatorToKickId, - status: IRegistryCoordinator.OperatorStatus.DEREGISTERED - }) - ) - ) + keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ + operatorId: operatorToKickId, + status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED + }))) ); assertEq( - keccak256( - abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToKickId, 0)) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: kickRegistrationBlockNumber, - nextUpdateBlockNumber: registrationBlockNumber - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToKickId, 0))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: kickRegistrationBlockNumber, + nextUpdateBlockNumber: registrationBlockNumber + }))) ); } @@ -1797,7 +1629,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ( address operatorToRegister, BN254.G1Point memory operatorToRegisterPubKey, - IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams + ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, defaultStake); bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); @@ -1835,10 +1667,8 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ( address operatorToRegister, BN254.G1Point memory operatorToRegisterPubKey, - IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams - ) = _test_registerOperatorWithChurn_SetUp( - pseudoRandomNumber, quorumNumbers, operatorToKickStake - ); + ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams + ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, operatorToKickStake); bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); // set the stake of the operator to register to the defaultKickBIPsOfOperatorStake multiple of the operatorToKickStake @@ -1879,7 +1709,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ( address operatorToRegister, , - IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams + ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, defaultStake); uint96 registeringStake = defaultKickBIPsOfOperatorStake * defaultStake; @@ -1913,7 +1743,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ( address operatorToRegister, BN254.G1Point memory operatorToRegisterPubKey, - IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams + ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, defaultStake); bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); @@ -2243,7 +2073,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit ), keccak256( abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ + ISlashingRegistryCoordinator.QuorumBitmapUpdate({ quorumBitmap: uint192(newBitmap), updateBlockNumber: uint32(block.number), nextUpdateBlockNumber: 0 @@ -2262,18 +2092,12 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); assertEq( - keccak256( - abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(newBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(newBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }))) ); } @@ -2290,32 +2114,20 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); assertEq( - keccak256( - abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(pastBitmap), - updateBlockNumber: uint32(previousBlockNumber), - nextUpdateBlockNumber: uint32(block.number) - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(pastBitmap), + updateBlockNumber: uint32(previousBlockNumber), + nextUpdateBlockNumber: uint32(block.number) + }))) ); assertEq( - keccak256( - abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1)) - ), - keccak256( - abi.encode( - IRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(newBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }) - ) - ) + keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), + keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + quorumBitmap: uint192(newBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }))) ); } } @@ -2340,8 +2152,7 @@ contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnit function test_CreateTotalDelegatedStakeQuorum() public { _deployMockEigenLayerAndAVS(0); // Set up test params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator - .OperatorSetParam({ + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 0, kickBIPsOfTotalStake: 0 @@ -2365,8 +2176,7 @@ contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnit assertEq(registryCoordinator.quorumCount(), initialQuorumCount + 1); // Verify quorum params were set correctly - IRegistryCoordinator.OperatorSetParam memory storedParams = - registryCoordinator.getOperatorSetParams(initialQuorumCount); + ISlashingRegistryCoordinator.OperatorSetParam memory storedParams = registryCoordinator.getOperatorSetParams(initialQuorumCount); assertEq(storedParams.maxOperatorCount, operatorSetParams.maxOperatorCount); assertEq(storedParams.kickBIPsOfOperatorStake, operatorSetParams.kickBIPsOfOperatorStake); assertEq(storedParams.kickBIPsOfTotalStake, operatorSetParams.kickBIPsOfTotalStake); @@ -2374,8 +2184,7 @@ contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnit function test_CreateSlashableStakeQuorum_Reverts() public { _deployMockEigenLayerAndAVS(0); - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator - .OperatorSetParam({ + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 0, kickBIPsOfTotalStake: 0 @@ -2399,15 +2208,16 @@ contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnit _deployMockEigenLayerAndAVS(0); cheats.prank(registryCoordinatorOwner); registryCoordinator.enableOperatorSets(); - assertTrue(registryCoordinator.isUsingOperatorSets()); + assertTrue(registryCoordinator.operatorSetsEnabled()); } } contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitTests { + function test_MigrateToOperatorSets() public { cheats.prank(registryCoordinatorOwner); registryCoordinator.enableOperatorSets(); - assertTrue(registryCoordinator.isUsingOperatorSets()); + assertTrue(registryCoordinator.operatorSetsEnabled()); } function test_M2_Deregister() public { @@ -2451,13 +2261,8 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT assertEq(bitmap, 0, "Operator bitmap should be empty after deregistration"); // Verify operator status is NEVER_REGISTERED - IRegistryCoordinator.OperatorStatus status = - registryCoordinator.getOperatorStatus(operatorToRegister); - assertEq( - uint8(status), - uint8(IRegistryCoordinator.OperatorStatus.NEVER_REGISTERED), - "Operator status should be NEVER_REGISTERED" - ); + ISlashingRegistryCoordinator.OperatorStatus status = registryCoordinator.getOperatorStatus(operatorToRegister); + assertEq(uint8(status), uint8(ISlashingRegistryCoordinator.OperatorStatus.NEVER_REGISTERED), "Operator status should be NEVER_REGISTERED"); } function test_M2_Register_Reverts() public { @@ -2484,8 +2289,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT registryCoordinator.enableOperatorSets(); // Create quorum params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator - .OperatorSetParam({ + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 @@ -2513,8 +2317,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT registryCoordinator.enableOperatorSets(); // Create quorum params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator - .OperatorSetParam({ + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 @@ -2536,13 +2339,13 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT vm.skip(true); _deployMockEigenLayerAndAVS(0); + // Enable operator sets first cheats.prank(registryCoordinatorOwner); registryCoordinator.enableOperatorSets(); // Create quorum params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator - .OperatorSetParam({ + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 @@ -2576,7 +2379,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT // Encode with RegistrationType.NORMAL bytes memory data = abi.encode( - RegistryCoordinator.RegistrationType.NORMAL, + ISlashingRegistryCoordinator.RegistrationType.NORMAL, socket, params ); @@ -2586,14 +2389,14 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT } function test_registerHook_WithChurn() public { + vm.skip(true); _deployMockEigenLayerAndAVS(0); // Enable operator sets first cheats.prank(registryCoordinatorOwner); registryCoordinator.enableOperatorSets(); // Create quorum params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator - .OperatorSetParam({ + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 @@ -2621,16 +2424,17 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT // pubkeySignature: defaultPubKeySignature // }); - IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = - new IRegistryCoordinator.OperatorKickParam[](1); - operatorKickParams[0] = - IRegistryCoordinator.OperatorKickParam({operator: address(0x1), quorumNumber: 0}); + ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = new ISlashingRegistryCoordinator.OperatorKickParam[](1); + operatorKickParams[0] = ISlashingRegistryCoordinator.OperatorKickParam({ + operator: address(0x1), + quorumNumber: 0 + }); ISignatureUtils.SignatureWithSaltAndExpiry memory churnApproverSignature; // Encode with RegistrationType.CHURN bytes memory data = abi.encode( - RegistryCoordinator.RegistrationType.CHURN, + ISlashingRegistryCoordinator.RegistrationType.CHURN, socket, params, operatorKickParams, @@ -2646,8 +2450,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT vm.skip(true); _deployMockEigenLayerAndAVS(0); - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator - .OperatorSetParam({ + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ maxOperatorCount: defaultMaxOperatorCount, kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake @@ -2676,8 +2479,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT registryCoordinator.enableOperatorSets(); // Create quorum params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator - .OperatorSetParam({ + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 @@ -2708,7 +2510,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT // Encode with RegistrationType.NORMAL bytes memory data = abi.encode( - RegistryCoordinator.RegistrationType.NORMAL, + ISlashingRegistryCoordinator.RegistrationType.NORMAL, socket, params ); @@ -2723,13 +2525,13 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT function test_registerHook_Reverts_WhenNotALM() public { _deployMockEigenLayerAndAVS(0); + // Enable operator sets first cheats.prank(registryCoordinatorOwner); registryCoordinator.enableOperatorSets(); // Create quorum params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator - .OperatorSetParam({ + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 @@ -2763,7 +2565,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT // Encode with RegistrationType.NORMAL bytes memory data = abi.encode( - RegistryCoordinator.RegistrationType.NORMAL, + ISlashingRegistryCoordinator.RegistrationType.NORMAL, socket, params ); @@ -2774,13 +2576,18 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT function test_deregisterHook_Reverts_WhenNotALM() public { _deployMockEigenLayerAndAVS(0); + // Enable operator sets first cheats.prank(registryCoordinatorOwner); registryCoordinator.enableOperatorSets(); + assertTrue( + registryCoordinator.operatorSetsEnabled(), + "operatorSetsEnabled should be true" + ); + // Create quorum params - IRegistryCoordinator.OperatorSetParam memory operatorSetParams = IRegistryCoordinator - .OperatorSetParam({ + ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 @@ -2809,16 +2616,14 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT // pubkeySignature: defaultPubKeySignature // }); - // Encode with RegistrationType.NORMAL bytes memory data = abi.encode( - RegistryCoordinator.RegistrationType.NORMAL, + ISlashingRegistryCoordinator.RegistrationType.NORMAL, socket, params ); cheats.prank(address(registryCoordinator.allocationManager())); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); - cheats.stopPrank(); cheats.expectRevert(); registryCoordinator.deregisterOperator(defaultOperator, operatorSetIds); diff --git a/test/unit/SlashingRegistryCoordinatorUnit.t.sol b/test/unit/SlashingRegistryCoordinatorUnit.t.sol new file mode 100644 index 00000000..52d12ed8 --- /dev/null +++ b/test/unit/SlashingRegistryCoordinatorUnit.t.sol @@ -0,0 +1,2421 @@ +// // SPDX-License-Identifier: BUSL-1.1 +// pragma solidity ^0.8.27; + +// import "../utils/MockAVSDeployer.sol"; +// import {ISlashingRegistryCoordinator, IRegistryCoordinatorErrors} from "../../src/interfaces/ISlashingRegistryCoordinator.sol"; +// import {QuorumBitmapHistoryLib} from "../../src/libraries/QuorumBitmapHistoryLib.sol"; +// import {BitmapUtils} from "../../src/libraries/BitmapUtils.sol"; +// import {console} from "forge-std/console.sol"; + + +// contract RegistryCoordinatorUnitTests is MockAVSDeployer { +// using BN254 for BN254.G1Point; + +// uint8 internal constant PAUSED_REGISTER_OPERATOR = 0; +// uint8 internal constant PAUSED_DEREGISTER_OPERATOR = 1; +// uint8 internal constant PAUSED_UPDATE_OPERATOR = 2; +// uint8 internal constant MAX_QUORUM_COUNT = 192; + +// /// Emits when an operator is registered +// event OperatorRegistered(address indexed operator, bytes32 indexed operatorId); +// /// Emits when an operator is deregistered +// event OperatorDeregistered(address indexed operator, bytes32 indexed operatorId); + +// event OperatorSocketUpdate(bytes32 indexed operatorId, string socket); + +// /// @notice emitted whenever the stake of `operator` is updated +// event OperatorStakeUpdate( +// bytes32 indexed operatorId, +// uint8 quorumNumber, +// uint96 stake +// ); + +// // Emitted when a new operator pubkey is registered for a set of quorums +// event OperatorAddedToQuorums( +// address operator, +// bytes32 operatorId, +// bytes quorumNumbers +// ); + +// // Emitted when an operator pubkey is removed from a set of quorums +// event OperatorRemovedFromQuorums( +// address operator, +// bytes32 operatorId, +// bytes quorumNumbers +// ); + +// // emitted when an operator's index in the orderd operator list for the quorum with number `quorumNumber` is updated +// event QuorumIndexUpdate(bytes32 indexed operatorId, uint8 quorumNumber, uint32 newIndex); + +// event OperatorSetParamsUpdated(uint8 indexed quorumNumber, ISlashingRegistryCoordinator.OperatorSetParam operatorSetParams); + +// event ChurnApproverUpdated(address prevChurnApprover, address newChurnApprover); + +// event EjectorUpdated(address prevEjector, address newEjector); + +// event QuorumBlockNumberUpdated(uint8 indexed quorumNumber, uint256 blocknumber); + +// function setUp() virtual public { +// _deployMockEigenLayerAndAVS(numQuorums); +// } + +// function _test_registerOperatorWithChurn_SetUp( +// uint256 pseudoRandomNumber, +// bytes memory quorumNumbers, +// uint96 operatorToKickStake +// ) internal returns( +// address operatorToRegister, +// BN254.G1Point memory operatorToRegisterPubKey, +// ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams +// ) { +// uint32 kickRegistrationBlockNumber = 100; + +// uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); + +// cheats.roll(kickRegistrationBlockNumber); + +// for (uint i = 0; i < defaultMaxOperatorCount - 1; i++) { +// BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); +// address operator = _incrementAddress(defaultOperator, i); + +// _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); +// } + +// operatorToRegister = _incrementAddress(defaultOperator, defaultMaxOperatorCount); +// operatorToRegisterPubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, defaultMaxOperatorCount))); +// bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); +// bytes32 operatorToKickId; +// address operatorToKick; + +// // register last operator before kick +// operatorKickParams = new ISlashingRegistryCoordinator.OperatorKickParam[](1); +// { +// BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, defaultMaxOperatorCount - 1))); +// operatorToKickId = BN254.hashG1Point(pubKey); +// operatorToKick = _incrementAddress(defaultOperator, defaultMaxOperatorCount - 1); + +// // register last operator with much more than the kickBIPsOfTotalStake stake +// _registerOperatorWithCoordinator(operatorToKick, quorumBitmap, pubKey, operatorToKickStake); + +// bytes32[] memory operatorIdsToSwap = new bytes32[](1); +// // operatorIdsToSwap[0] = operatorToRegisterId +// operatorIdsToSwap[0] = operatorToRegisterId; + +// operatorKickParams[0] = ISlashingRegistryCoordinator.OperatorKickParam({ +// quorumNumber: uint8(quorumNumbers[0]), +// operator: operatorToKick +// }); +// } + +// blsApkRegistry.setBLSPublicKey(operatorToRegister, operatorToRegisterPubKey); +// } +// } + +// contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordinatorUnitTests { +// function test_initialization() public { +// assertEq(address(registryCoordinator.stakeRegistry()), address(stakeRegistry)); +// assertEq(address(registryCoordinator.blsApkRegistry()), address(blsApkRegistry)); +// assertEq(address(registryCoordinator.indexRegistry()), address(indexRegistry)); +// assertEq(address(registryCoordinator.serviceManager()), address(serviceManager)); + +// for (uint i = 0; i < numQuorums; i++) { +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperatorSetParams(uint8(i)))), +// keccak256(abi.encode(operatorSetParams[i])) +// ); +// } + +// // make sure the contract initializers are disabled +// cheats.expectRevert(bytes("Initializable: contract is already initialized")); +// registryCoordinator.initialize( +// registryCoordinatorOwner, +// churnApprover, +// ejector, +// 0/*initialPausedStatus*/, +// address(serviceManager) // _accountIdentifier +// ); +// } + +// function test_setOperatorSetParams() public { +// cheats.prank(registryCoordinatorOwner); +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit OperatorSetParamsUpdated(0, operatorSetParams[1]); +// registryCoordinator.setOperatorSetParams(0, operatorSetParams[1]); +// assertEq(keccak256(abi.encode(registryCoordinator.getOperatorSetParams(0))),keccak256(abi.encode(operatorSetParams[1])), +// "operator set params not updated correctly"); +// } + +// function test_setOperatorSetParams_revert_notOwner() public { +// cheats.expectRevert("Ownable: caller is not the owner"); +// cheats.prank(defaultOperator); +// registryCoordinator.setOperatorSetParams(0, operatorSetParams[0]); +// } + +// function test_setChurnApprover() public { +// address newChurnApprover = address(uint160(uint256(keccak256("newChurnApprover")))); +// cheats.prank(registryCoordinatorOwner); +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit ChurnApproverUpdated(churnApprover, newChurnApprover); +// registryCoordinator.setChurnApprover(newChurnApprover); +// assertEq(registryCoordinator.churnApprover(), newChurnApprover); +// } + +// function test_setChurnApprover_revert_notOwner() public { +// address newChurnApprover = address(uint160(uint256(keccak256("newChurnApprover")))); +// cheats.expectRevert("Ownable: caller is not the owner"); +// cheats.prank(defaultOperator); +// registryCoordinator.setChurnApprover(newChurnApprover); +// } + +// function test_setEjector() public { +// address newEjector = address(uint160(uint256(keccak256("newEjector")))); +// cheats.prank(registryCoordinatorOwner); +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit EjectorUpdated(ejector, newEjector); +// registryCoordinator.setEjector(newEjector); +// assertEq(registryCoordinator.ejector(), newEjector); +// } + +// function test_setEjector_revert_notOwner() public { +// address newEjector = address(uint160(uint256(keccak256("newEjector")))); +// cheats.expectRevert("Ownable: caller is not the owner"); +// cheats.prank(defaultOperator); +// registryCoordinator.setEjector(newEjector); +// } + +// function test_updateSocket() public { +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); +// _registerOperatorWithCoordinator(defaultOperator, quorumBitmap, defaultPubKey); + +// cheats.prank(defaultOperator); +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit OperatorSocketUpdate(defaultOperatorId, "localhost:32004"); +// registryCoordinator.updateSocket("localhost:32004"); + +// } + +// function test_updateSocket_revert_notRegistered() public { +// cheats.prank(defaultOperator); +// cheats.expectRevert(bytes4(keccak256("NotRegistered()"))); +// registryCoordinator.updateSocket("localhost:32004"); +// } + +// function test_createQuorum_revert_notOwner() public { +// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams; +// uint96 minimumStake; +// IStakeRegistry.StrategyParams[] memory strategyParams; + +// cheats.expectRevert("Ownable: caller is not the owner"); +// cheats.prank(defaultOperator); +// registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, minimumStake, strategyParams); +// } + +// function test_createQuorum() public { +// // re-run setup, but setting up zero quorums +// // this is necessary since the default setup already configures the max number of quorums, preventing adding more +// _deployMockEigenLayerAndAVS(0); + +// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = +// ISlashingRegistryCoordinator.OperatorSetParam({ +// maxOperatorCount: defaultMaxOperatorCount, +// kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, +// kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake +// }); +// uint96 minimumStake = 1; +// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); +// strategyParams[0] = +// IStakeRegistry.StrategyParams({ +// strategy: IStrategy(address(1000)), +// multiplier: 1e16 +// }); + +// uint8 quorumCountBefore = registryCoordinator.quorumCount(); + +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit OperatorSetParamsUpdated(quorumCountBefore, operatorSetParams); +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, minimumStake, strategyParams); + +// uint8 quorumCountAfter = registryCoordinator.quorumCount(); +// assertEq(quorumCountAfter, quorumCountBefore + 1, "quorum count did not increase properly"); +// assertLe(quorumCountAfter, MAX_QUORUM_COUNT, "quorum count exceeded max"); + +// assertEq( +// keccak256(abi.encode(operatorSetParams)), +// keccak256(abi.encode(registryCoordinator.getOperatorSetParams(quorumCountBefore))), +// "OperatorSetParams not stored properly" +// ); +// } +// } + +// contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUnitTests { + +// function test_registerOperator_revert_paused() public { +// bytes memory emptyQuorumNumbers = new bytes(0); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; + +// // pause registerOperator +// cheats.prank(pauser); +// registryCoordinator.pause(2 ** PAUSED_REGISTER_OPERATOR); + +// cheats.startPrank(defaultOperator); +// cheats.expectRevert(bytes4(keccak256("CurrentlyPaused()"))); +// registryCoordinator.registerOperator(emptyQuorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); +// } + +// function test_registerOperator_revert_emptyQuorumNumbers() public { +// bytes memory emptyQuorumNumbers = new bytes(0); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; + +// cheats.expectRevert(bytes4(keccak256("BitmapEmpty()"))); +// cheats.prank(defaultOperator); +// registryCoordinator.registerOperator(emptyQuorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); +// } + +// function test_registerOperator_revert_invalidQuorum() public { +// bytes memory quorumNumbersTooLarge = new bytes(1); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; + +// quorumNumbersTooLarge[0] = 0xC0; + +// cheats.expectRevert(BitmapUtils.BitmapValueTooLarge.selector); +// cheats.prank(defaultOperator); +// registryCoordinator.registerOperator(quorumNumbersTooLarge, defaultSocket, pubkeyRegistrationParams, emptySig); +// } + +// function test_registerOperator_revert_nonexistentQuorum() public { +// _deployMockEigenLayerAndAVS(10); +// bytes memory quorumNumbersNotCreated = new bytes(1); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; + +// quorumNumbersNotCreated[0] = 0x0B; + +// cheats.prank(defaultOperator); +// cheats.expectRevert(BitmapUtils.BitmapValueTooLarge.selector); +// registryCoordinator.registerOperator(quorumNumbersNotCreated, defaultSocket, pubkeyRegistrationParams, emptySig); +// } + +// function test_registerOperator_singleQuorum() public { +// bytes memory quorumNumbers = new bytes(1); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// uint96 actualStake = _setOperatorWeight(defaultOperator, defaultQuorumNumber, defaultStake); + +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit OperatorSocketUpdate(defaultOperatorId, defaultSocket); +// cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); +// emit OperatorAddedToQuorums(defaultOperator, defaultOperatorId, quorumNumbers); +// cheats.expectEmit(true, true, true, true, address(stakeRegistry)); +// emit OperatorStakeUpdate(defaultOperatorId, defaultQuorumNumber, actualStake); +// cheats.expectEmit(true, true, true, true, address(indexRegistry)); +// emit QuorumIndexUpdate(defaultOperatorId, defaultQuorumNumber, 0); + +// uint256 gasBefore = gasleft(); +// cheats.prank(defaultOperator); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); +// uint256 gasAfter = gasleft(); +// emit log_named_uint("gasUsed, register for single quorum", gasBefore - gasAfter); + +// uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); + +// assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: defaultOperatorId, +// status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED +// }))) +// ); +// assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(quorumBitmap), +// updateBlockNumber: uint32(block.number), +// nextUpdateBlockNumber: 0 +// }))) +// ); +// } + +// // @notice tests registering an operator for a fuzzed assortment of quorums +// function testFuzz_registerOperator(uint256 quorumBitmap) public { +// // filter the fuzzed input down to only valid quorums +// quorumBitmap = quorumBitmap & MAX_QUORUM_BITMAP; +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// cheats.assume(quorumBitmap != 0); +// bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); + +// uint96 actualStake; +// for (uint i = 0; i < quorumNumbers.length; i++) { +// actualStake = _setOperatorWeight(defaultOperator, uint8(quorumNumbers[i]), defaultStake); +// } + +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit OperatorSocketUpdate(defaultOperatorId, defaultSocket); +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit OperatorRegistered(defaultOperator, defaultOperatorId); + +// cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); +// emit OperatorAddedToQuorums(defaultOperator, defaultOperatorId, quorumNumbers); + +// for (uint i = 0; i < quorumNumbers.length; i++) { +// cheats.expectEmit(true, true, true, true, address(stakeRegistry)); +// emit OperatorStakeUpdate(defaultOperatorId, uint8(quorumNumbers[i]), actualStake); +// } + +// for (uint i = 0; i < quorumNumbers.length; i++) { +// cheats.expectEmit(true, true, true, true, address(indexRegistry)); +// emit QuorumIndexUpdate(defaultOperatorId, uint8(quorumNumbers[i]), 0); +// } + +// uint256 gasBefore = gasleft(); +// cheats.prank(defaultOperator); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); +// uint256 gasAfter = gasleft(); +// emit log_named_uint("gasUsed", gasBefore - gasAfter); +// emit log_named_uint("numQuorums", quorumNumbers.length); + +// assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: defaultOperatorId, +// status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED +// }))) +// ); +// assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(quorumBitmap), +// updateBlockNumber: uint32(block.number), +// nextUpdateBlockNumber: 0 +// }))) +// ); +// } + +// // @notice tests registering an operator for a single quorum and later registering them for an additional quorum +// function test_registerOperator_addingQuorumsAfterInitialRegistration() public { +// uint256 registrationBlockNumber = block.number + 100; +// uint256 nextRegistrationBlockNumber = registrationBlockNumber + 100; +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; + +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); +// cheats.prank(defaultOperator); +// cheats.roll(registrationBlockNumber); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// bytes memory newQuorumNumbers = new bytes(1); +// newQuorumNumbers[0] = bytes1(defaultQuorumNumber+1); + +// uint96 actualStake = _setOperatorWeight(defaultOperator, uint8(newQuorumNumbers[0]), defaultStake); +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit OperatorSocketUpdate(defaultOperatorId, defaultSocket); +// cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); +// emit OperatorAddedToQuorums(defaultOperator, defaultOperatorId, newQuorumNumbers); +// cheats.expectEmit(true, true, true, true, address(stakeRegistry)); +// emit OperatorStakeUpdate(defaultOperatorId, uint8(newQuorumNumbers[0]), actualStake); +// cheats.expectEmit(true, true, true, true, address(indexRegistry)); +// emit QuorumIndexUpdate(defaultOperatorId, uint8(newQuorumNumbers[0]), 0); +// cheats.roll(nextRegistrationBlockNumber); +// cheats.prank(defaultOperator); +// registryCoordinator.registerOperator(newQuorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers) | BitmapUtils.orderedBytesArrayToBitmap(newQuorumNumbers); + +// assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: defaultOperatorId, +// status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED +// }))) +// ); +// assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers)), +// updateBlockNumber: uint32(registrationBlockNumber), +// nextUpdateBlockNumber: uint32(nextRegistrationBlockNumber) +// }))) +// ); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(quorumBitmap), +// updateBlockNumber: uint32(nextRegistrationBlockNumber), +// nextUpdateBlockNumber: 0 +// }))) +// ); +// } + +// function test_registerOperator_revert_overFilledQuorum(uint256 pseudoRandomNumber) public { +// uint32 numOperators = defaultMaxOperatorCount; +// uint32 registrationBlockNumber = 200; +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; + +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); + +// cheats.roll(registrationBlockNumber); + +// for (uint i = 0; i < numOperators; i++) { +// BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); +// address operator = _incrementAddress(defaultOperator, i); + +// _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); +// } + +// address operatorToRegister = _incrementAddress(defaultOperator, numOperators); +// BN254.G1Point memory operatorToRegisterPubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, numOperators))); + +// blsApkRegistry.setBLSPublicKey(operatorToRegister, operatorToRegisterPubKey); + +// _setOperatorWeight(operatorToRegister, defaultQuorumNumber, defaultStake); + +// cheats.prank(operatorToRegister); +// cheats.expectRevert(bytes4(keccak256("MaxQuorumsReached()"))); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); +// } + +// function test_registerOperator_revert_operatorAlreadyRegisteredForQuorum() public { +// uint256 registrationBlockNumber = block.number + 100; +// uint256 nextRegistrationBlockNumber = registrationBlockNumber + 100; +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; + +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); +// cheats.prank(defaultOperator); +// cheats.roll(registrationBlockNumber); + +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// cheats.prank(defaultOperator); +// cheats.roll(nextRegistrationBlockNumber); +// cheats.expectRevert(bytes4(keccak256("AlreadyRegisteredForQuorums()"))); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); +// } + +// // tests for the internal `_registerOperator` function: +// function test_registerOperatorInternal_revert_noQuorums() public { +// bytes memory emptyQuorumNumbers = new bytes(0); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; + +// cheats.expectRevert(bytes4(keccak256("BitmapEmpty()"))); +// registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, emptyQuorumNumbers, defaultSocket, emptySig); +// } + +// function test_registerOperatorInternal_revert_nonexistentQuorum() public { +// bytes memory quorumNumbersTooLarge = new bytes(1); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; + +// quorumNumbersTooLarge[0] = 0xC0; + +// cheats.expectRevert(BitmapUtils.BitmapValueTooLarge.selector); +// registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, quorumNumbersTooLarge, defaultSocket, emptySig); +// } + +// function test_registerOperatorInternal_revert_operatorAlreadyRegisteredForQuorum() public { +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); +// registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, quorumNumbers, defaultSocket, emptySig); + +// cheats.expectRevert(bytes4(keccak256("AlreadyRegisteredForQuorums()"))); +// registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, quorumNumbers, defaultSocket, emptySig); +// } + +// function test_registerOperatorInternal() public { +// bytes memory quorumNumbers = new bytes(1); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// defaultStake = _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); + +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit OperatorSocketUpdate(defaultOperatorId, defaultSocket); +// cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); +// emit OperatorAddedToQuorums(defaultOperator, defaultOperatorId, quorumNumbers); +// cheats.expectEmit(true, true, true, true, address(stakeRegistry)); +// emit OperatorStakeUpdate(defaultOperatorId, defaultQuorumNumber, defaultStake); +// cheats.expectEmit(true, true, true, true, address(indexRegistry)); +// emit QuorumIndexUpdate(defaultOperatorId, defaultQuorumNumber, 0); + +// registryCoordinator._registerOperatorExternal(defaultOperator, defaultOperatorId, quorumNumbers, defaultSocket, emptySig); + +// uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); + +// assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: defaultOperatorId, +// status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED +// }))) +// ); +// assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(quorumBitmap), +// updateBlockNumber: uint32(block.number), +// nextUpdateBlockNumber: 0 +// }))) +// ); +// } +// } + +// // @dev note that this contract also contains tests for the `getQuorumBitmapIndicesAtBlockNumber` and `getQuorumBitmapAtBlockNumberByIndex` view fncs +// contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is RegistryCoordinatorUnitTests { +// function test_deregisterOperator_revert_paused() public { +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); + +// _registerOperatorWithCoordinator(defaultOperator, quorumBitmap, defaultPubKey); + +// // pause deregisterOperator +// cheats.prank(pauser); +// registryCoordinator.pause(2 ** PAUSED_DEREGISTER_OPERATOR); + +// cheats.expectRevert(bytes4(keccak256("CurrentlyPaused()"))); +// cheats.prank(defaultOperator); +// registryCoordinator.deregisterOperator(quorumNumbers); +// } + +// function test_deregisterOperator_revert_notRegistered() public { +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// cheats.expectRevert(bytes4(keccak256("NotRegistered()"))); +// cheats.prank(defaultOperator); +// registryCoordinator.deregisterOperator(quorumNumbers); +// } + +// function test_deregisterOperator_revert_incorrectQuorums() public { +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); + +// _registerOperatorWithCoordinator(defaultOperator, quorumBitmap, defaultPubKey); + +// quorumNumbers = new bytes(2); +// quorumNumbers[0] = bytes1(defaultQuorumNumber + 1); +// quorumNumbers[1] = bytes1(defaultQuorumNumber + 2); + +// cheats.expectRevert(bytes4(keccak256("NotRegisteredForQuorum()"))); +// cheats.prank(defaultOperator); +// registryCoordinator.deregisterOperator(quorumNumbers); +// } + +// // @notice verifies that an operator who was registered for a single quorum can be deregistered +// function test_deregisterOperator_singleQuorumAndSingleOperator() public { +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// uint32 registrationBlockNumber = 100; +// uint32 deregistrationBlockNumber = 200; + +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); + +// cheats.startPrank(defaultOperator); + +// cheats.roll(registrationBlockNumber); + +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); + +// cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); +// emit OperatorRemovedFromQuorums(defaultOperator, defaultOperatorId, quorumNumbers); +// cheats.expectEmit(true, true, true, true, address(stakeRegistry)); +// emit OperatorStakeUpdate(defaultOperatorId, defaultQuorumNumber, 0); + +// cheats.roll(deregistrationBlockNumber); + +// uint256 gasBefore = gasleft(); +// registryCoordinator.deregisterOperator(quorumNumbers); +// uint256 gasAfter = gasleft(); +// emit log_named_uint("gasUsed", gasBefore - gasAfter); + +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: defaultOperatorId, +// status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED +// }))) +// ); +// assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(quorumBitmap), +// updateBlockNumber: registrationBlockNumber, +// nextUpdateBlockNumber: deregistrationBlockNumber +// }))) +// ); +// } + +// // @notice verifies that an operator who was registered for a fuzzed set of quorums can be deregistered +// // @dev deregisters the operator from *all* quorums for which they we registered. +// function testFuzz_deregisterOperator_fuzzedQuorumAndSingleOperator(uint256 quorumBitmap) public { +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// uint32 registrationBlockNumber = 100; +// uint32 deregistrationBlockNumber = 200; + +// // filter down fuzzed input to only valid quorums +// quorumBitmap = quorumBitmap & MAX_QUORUM_BITMAP; +// cheats.assume(quorumBitmap != 0); +// bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); + +// for (uint i = 0; i < quorumNumbers.length; i++) { +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[i]), defaultStake); +// } + +// cheats.startPrank(defaultOperator); + +// cheats.roll(registrationBlockNumber); + +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); +// emit OperatorRemovedFromQuorums(defaultOperator, defaultOperatorId, quorumNumbers); +// for (uint i = 0; i < quorumNumbers.length; i++) { +// cheats.expectEmit(true, true, true, true, address(stakeRegistry)); +// emit OperatorStakeUpdate(defaultOperatorId, uint8(quorumNumbers[i]), 0); +// } + +// cheats.roll(deregistrationBlockNumber); + +// uint256 gasBefore = gasleft(); +// registryCoordinator.deregisterOperator(quorumNumbers); +// uint256 gasAfter = gasleft(); +// emit log_named_uint("gasUsed", gasBefore - gasAfter); +// emit log_named_uint("numQuorums", quorumNumbers.length); + +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: defaultOperatorId, +// status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED +// }))) +// ); +// assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(quorumBitmap), +// updateBlockNumber: registrationBlockNumber, +// nextUpdateBlockNumber: deregistrationBlockNumber +// }))) +// ); +// } +// // @notice verifies that an operator who was registered for a fuzzed set of quorums can be deregistered from a subset of those quorums +// // @dev deregisters the operator from a fuzzed subset of the quorums for which they we registered. +// function testFuzz_deregisterOperator_singleOperator_partialDeregistration( +// uint256 registrationQuorumBitmap, +// uint256 deregistrationQuorumBitmap +// ) public { +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// uint32 registrationBlockNumber = 100; +// uint32 deregistrationBlockNumber = 200; + +// // filter down fuzzed input to only valid quorums +// registrationQuorumBitmap = registrationQuorumBitmap & MAX_QUORUM_BITMAP; +// cheats.assume(registrationQuorumBitmap != 0); +// // filter the other fuzzed input to a subset of the first fuzzed input +// deregistrationQuorumBitmap = deregistrationQuorumBitmap & registrationQuorumBitmap; +// cheats.assume(deregistrationQuorumBitmap != 0); +// bytes memory registrationquorumNumbers = BitmapUtils.bitmapToBytesArray(registrationQuorumBitmap); + +// for (uint i = 0; i < registrationquorumNumbers.length; i++) { +// _setOperatorWeight(defaultOperator, uint8(registrationquorumNumbers[i]), defaultStake); +// } + +// cheats.startPrank(defaultOperator); + +// cheats.roll(registrationBlockNumber); + +// registryCoordinator.registerOperator(registrationquorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// bytes memory deregistrationquorumNumbers = BitmapUtils.bitmapToBytesArray(deregistrationQuorumBitmap); + +// cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); +// emit OperatorRemovedFromQuorums(defaultOperator, defaultOperatorId, deregistrationquorumNumbers); +// for (uint i = 0; i < deregistrationquorumNumbers.length; i++) { +// cheats.expectEmit(true, true, true, true, address(stakeRegistry)); +// emit OperatorStakeUpdate(defaultOperatorId, uint8(deregistrationquorumNumbers[i]), 0); +// } + +// cheats.roll(deregistrationBlockNumber); + +// uint256 gasBefore = gasleft(); +// registryCoordinator.deregisterOperator(deregistrationquorumNumbers); +// uint256 gasAfter = gasleft(); +// emit log_named_uint("gasUsed", gasBefore - gasAfter); +// emit log_named_uint("numQuorums", deregistrationquorumNumbers.length); + +// // check that the operator is marked as 'degregistered' only if deregistered from *all* quorums +// if (deregistrationQuorumBitmap == registrationQuorumBitmap) { +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: defaultOperatorId, +// status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED +// }))) +// ); +// } else { +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: defaultOperatorId, +// status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED +// }))) +// ); +// } +// // ensure that the operator's current quorum bitmap matches the expectation +// uint256 expectedQuorumBitmap = BitmapUtils.minus(registrationQuorumBitmap, deregistrationQuorumBitmap); +// assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), expectedQuorumBitmap); +// // check that the quorum bitmap history is as expected +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(registrationQuorumBitmap), +// updateBlockNumber: registrationBlockNumber, +// nextUpdateBlockNumber: deregistrationBlockNumber +// }))) +// ); +// // note: there will be no second entry in the operator's bitmap history in the event that the operator has totally deregistered +// if (deregistrationQuorumBitmap != registrationQuorumBitmap) { +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(expectedQuorumBitmap), +// updateBlockNumber: deregistrationBlockNumber, +// nextUpdateBlockNumber: 0 +// }))) +// ); +// } +// } + +// // @notice registers the max number of operators with fuzzed bitmaps and then deregisters a pseudorandom operator (from all of their quorums) +// function testFuzz_deregisterOperator_manyOperators(uint256 pseudoRandomNumber) public { +// uint32 numOperators = defaultMaxOperatorCount; + +// uint32 registrationBlockNumber = 100; +// uint32 deregistrationBlockNumber = 200; + +// // pad quorumBitmap with 1 until it has numOperators elements +// uint256[] memory quorumBitmaps = new uint256[](numOperators); +// for (uint i = 0; i < numOperators; i++) { +// // limit to maxQuorumsToRegisterFor quorums via mask so we don't run out of gas, make them all register for quorum 0 as well +// quorumBitmaps[i] = uint256(keccak256(abi.encodePacked("quorumBitmap", pseudoRandomNumber, i))) & (1 << maxQuorumsToRegisterFor - 1) | 1; +// } + +// cheats.roll(registrationBlockNumber); + +// bytes32[] memory lastOperatorInQuorum = new bytes32[](numQuorums); +// for (uint i = 0; i < numOperators; i++) { +// emit log_named_uint("i", i); +// BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); +// bytes32 operatorId = BN254.hashG1Point(pubKey); +// address operator = _incrementAddress(defaultOperator, i); + +// _registerOperatorWithCoordinator(operator, quorumBitmaps[i], pubKey); + +// // for each quorum the operator is in, save the operatorId +// bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmaps[i]); +// for (uint j = 0; j < quorumNumbers.length; j++) { +// lastOperatorInQuorum[uint8(quorumNumbers[j])] = operatorId; +// } +// } + +// uint256 indexOfOperatorToDeregister = pseudoRandomNumber % numOperators; +// address operatorToDeregister = _incrementAddress(defaultOperator, indexOfOperatorToDeregister); +// BN254.G1Point memory operatorToDeregisterPubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, indexOfOperatorToDeregister))); +// bytes32 operatorToDeregisterId = BN254.hashG1Point(operatorToDeregisterPubKey); +// uint256 operatorToDeregisterQuorumBitmap = quorumBitmaps[indexOfOperatorToDeregister]; +// bytes memory operatorToDeregisterQuorumNumbers = BitmapUtils.bitmapToBytesArray(operatorToDeregisterQuorumBitmap); + +// bytes32[] memory operatorIdsToSwap = new bytes32[](operatorToDeregisterQuorumNumbers.length); +// for (uint i = 0; i < operatorToDeregisterQuorumNumbers.length; i++) { +// operatorIdsToSwap[i] = lastOperatorInQuorum[uint8(operatorToDeregisterQuorumNumbers[i])]; +// } + +// cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); +// emit OperatorRemovedFromQuorums(operatorToDeregister, operatorToDeregisterId, operatorToDeregisterQuorumNumbers); + +// for (uint i = 0; i < operatorToDeregisterQuorumNumbers.length; i++) { +// cheats.expectEmit(true, true, true, true, address(stakeRegistry)); +// emit OperatorStakeUpdate(operatorToDeregisterId, uint8(operatorToDeregisterQuorumNumbers[i]), 0); +// } + +// cheats.roll(deregistrationBlockNumber); + +// cheats.prank(operatorToDeregister); +// registryCoordinator.deregisterOperator(operatorToDeregisterQuorumNumbers); + +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(operatorToDeregister))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: operatorToDeregisterId, +// status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED +// }))) +// ); +// assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToDeregisterId, 0))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(operatorToDeregisterQuorumBitmap), +// updateBlockNumber: registrationBlockNumber, +// nextUpdateBlockNumber: deregistrationBlockNumber +// }))) +// ); +// } + +// // @notice verify that it is possible for an operator to register, deregister, and then register again! +// function test_reregisterOperator() public { +// test_deregisterOperator_singleQuorumAndSingleOperator(); + +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// uint32 reregistrationBlockNumber = 201; + +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// cheats.startPrank(defaultOperator); + +// cheats.roll(reregistrationBlockNumber); + +// // store data before registering, to check against later +// ISlashingRegistryCoordinator.QuorumBitmapUpdate memory previousQuorumBitmapUpdate = +// registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0); + +// // re-register the operator +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); +// // check success of registration +// uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); +// assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId, "1"); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: defaultOperatorId, +// status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED +// }))), +// "2" +// ); +// assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap, "3"); +// // check that previous entry in bitmap history was not changed +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), +// keccak256(abi.encode(previousQuorumBitmapUpdate)), +// "4" +// ); +// // check that new entry in bitmap history is as expected +// uint historyLength = registryCoordinator.getQuorumBitmapHistoryLength(defaultOperatorId); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, historyLength - 1))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(quorumBitmap), +// updateBlockNumber: uint32(reregistrationBlockNumber), +// nextUpdateBlockNumber: 0 +// }))), +// "5" +// ); +// } + +// // tests for the internal `_deregisterOperator` function: +// function test_deregisterOperatorExternal_revert_noQuorums() public { +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// uint32 registrationBlockNumber = 100; +// uint32 deregistrationBlockNumber = 200; + +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); + +// cheats.roll(registrationBlockNumber); +// cheats.startPrank(defaultOperator); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// bytes memory emptyQuorumNumbers = new bytes(0); + +// cheats.roll(deregistrationBlockNumber); +// cheats.expectRevert(bytes4(keccak256("BitmapCannotBeZero()"))); +// registryCoordinator._deregisterOperatorExternal(defaultOperator, emptyQuorumNumbers); +// } + +// function test_deregisterOperatorExternal_revert_notRegistered() public { +// bytes memory emptyQuorumNumbers = new bytes(0); +// cheats.expectRevert(bytes4(keccak256("NotRegistered()"))); +// registryCoordinator._deregisterOperatorExternal(defaultOperator, emptyQuorumNumbers); +// } + +// function test_deregisterOperatorExternal_revert_incorrectQuorums() public { +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// uint32 registrationBlockNumber = 100; +// uint32 deregistrationBlockNumber = 200; + +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); + +// cheats.roll(registrationBlockNumber); +// cheats.startPrank(defaultOperator); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// bytes memory incorrectQuorum = new bytes(1); +// incorrectQuorum[0] = bytes1(defaultQuorumNumber + 1); + +// cheats.roll(deregistrationBlockNumber); +// cheats.expectRevert(bytes4(keccak256("NotRegisteredForQuorum()"))); +// registryCoordinator._deregisterOperatorExternal(defaultOperator, incorrectQuorum); +// } + +// function test_reregisterOperator_revert_reregistrationDelay() public { +// uint256 reregistrationDelay = 1 days; +// cheats.warp(block.timestamp + reregistrationDelay); +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.setEjectionCooldown(reregistrationDelay); + +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// uint32 registrationBlockNumber = 100; +// uint32 reregistrationBlockNumber = 200; + +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); + +// cheats.prank(defaultOperator); +// cheats.roll(registrationBlockNumber); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// cheats.prank(ejector); +// registryCoordinator.ejectOperator(defaultOperator, quorumNumbers); + +// cheats.prank(defaultOperator); +// cheats.roll(reregistrationBlockNumber); +// cheats.expectRevert(bytes4(keccak256("CannotReregisterYet()"))); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); +// } + +// function test_reregisterOperator_reregistrationDelay() public { +// uint256 reregistrationDelay = 1 days; +// cheats.warp(block.timestamp + reregistrationDelay); +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.setEjectionCooldown(reregistrationDelay); + +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// uint32 registrationBlockNumber = 100; +// uint32 reregistrationBlockNumber = 200; + +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); + +// cheats.prank(defaultOperator); +// cheats.roll(registrationBlockNumber); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// cheats.prank(ejector); +// registryCoordinator.ejectOperator(defaultOperator, quorumNumbers); + +// cheats.prank(defaultOperator); +// cheats.roll(reregistrationBlockNumber); +// cheats.warp(block.timestamp + reregistrationDelay + 1); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); +// } + +// // note: this is not possible to test, because there is no route to getting the operator registered for nonexistent quorums +// // function test_deregisterOperatorExternal_revert_nonexistentQuorums() public { + +// function testFuzz_deregisterOperatorInternal_partialDeregistration( +// uint256 registrationQuorumBitmap, +// uint256 deregistrationQuorumBitmap +// ) public { +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// uint32 registrationBlockNumber = 100; +// uint32 deregistrationBlockNumber = 200; + +// // filter down fuzzed input to only valid quorums +// registrationQuorumBitmap = registrationQuorumBitmap & MAX_QUORUM_BITMAP; +// cheats.assume(registrationQuorumBitmap != 0); +// // filter the other fuzzed input to a subset of the first fuzzed input +// deregistrationQuorumBitmap = deregistrationQuorumBitmap & registrationQuorumBitmap; +// cheats.assume(deregistrationQuorumBitmap != 0); +// bytes memory registrationquorumNumbers = BitmapUtils.bitmapToBytesArray(registrationQuorumBitmap); + +// for (uint i = 0; i < registrationquorumNumbers.length; i++) { +// _setOperatorWeight(defaultOperator, uint8(registrationquorumNumbers[i]), defaultStake); +// } + +// cheats.roll(registrationBlockNumber); +// cheats.startPrank(defaultOperator); +// registryCoordinator.registerOperator(registrationquorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// bytes memory deregistrationquorumNumbers = BitmapUtils.bitmapToBytesArray(deregistrationQuorumBitmap); + +// cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); +// emit OperatorRemovedFromQuorums(defaultOperator, defaultOperatorId, deregistrationquorumNumbers); +// for (uint i = 0; i < deregistrationquorumNumbers.length; i++) { +// cheats.expectEmit(true, true, true, true, address(stakeRegistry)); +// emit OperatorStakeUpdate(defaultOperatorId, uint8(deregistrationquorumNumbers[i]), 0); +// } + +// cheats.roll(deregistrationBlockNumber); + +// registryCoordinator._deregisterOperatorExternal(defaultOperator, deregistrationquorumNumbers); + +// // check that the operator is marked as 'degregistered' only if deregistered from *all* quorums +// if (deregistrationQuorumBitmap == registrationQuorumBitmap) { +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: defaultOperatorId, +// status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED +// }))) +// ); +// } else { +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: defaultOperatorId, +// status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED +// }))) +// ); +// } +// // ensure that the operator's current quorum bitmap matches the expectation +// uint256 expectedQuorumBitmap = BitmapUtils.minus(registrationQuorumBitmap, deregistrationQuorumBitmap); +// assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), expectedQuorumBitmap); +// // check that the quorum bitmap history is as expected +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(registrationQuorumBitmap), +// updateBlockNumber: registrationBlockNumber, +// nextUpdateBlockNumber: deregistrationBlockNumber +// }))) +// ); +// // note: there will be no second entry in the operator's bitmap history in the event that the operator has totally deregistered +// if (deregistrationQuorumBitmap != registrationQuorumBitmap) { +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(expectedQuorumBitmap), +// updateBlockNumber: deregistrationBlockNumber, +// nextUpdateBlockNumber: 0 +// }))) +// ); +// } +// } + +// function test_ejectOperator_allQuorums() public { +// // register operator with default stake with default quorum number +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; + +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); + +// cheats.prank(defaultOperator); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); +// emit OperatorRemovedFromQuorums(defaultOperator, defaultOperatorId, quorumNumbers); + +// cheats.expectEmit(true, true, true, true, address(stakeRegistry)); +// emit OperatorStakeUpdate(defaultOperatorId, uint8(quorumNumbers[0]), 0); + +// // eject +// cheats.prank(ejector); +// registryCoordinator.ejectOperator(defaultOperator, quorumNumbers); + +// // make sure the operator is deregistered +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: defaultOperatorId, +// status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED +// }))) +// ); +// // make sure the operator is not in any quorums +// assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); +// } + +// function test_ejectOperator_subsetOfQuorums() public { +// // register operator with default stake with 2 quorums +// bytes memory quorumNumbers = new bytes(2); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// quorumNumbers[1] = bytes1(defaultQuorumNumber + 1); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; + +// for (uint i = 0; i < quorumNumbers.length; i++) { +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[i]), defaultStake); +// } + +// cheats.prank(defaultOperator); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// // eject from only first quorum +// bytes memory quorumNumbersToEject = new bytes(1); +// quorumNumbersToEject[0] = quorumNumbers[0]; + +// cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); +// emit OperatorRemovedFromQuorums(defaultOperator, defaultOperatorId, quorumNumbersToEject); + +// cheats.expectEmit(true, true, true, true, address(stakeRegistry)); +// emit OperatorStakeUpdate(defaultOperatorId, uint8(quorumNumbersToEject[0]), 0); + +// cheats.prank(ejector); +// registryCoordinator.ejectOperator(defaultOperator, quorumNumbersToEject); + +// // make sure the operator is registered +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: defaultOperatorId, +// status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED +// }))) +// ); +// // make sure the operator is properly removed from the quorums +// assertEq( +// registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), +// // quorumsRegisteredFor & ~quorumsEjectedFrom +// BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers) & ~BitmapUtils.orderedBytesArrayToBitmap(quorumNumbersToEject) +// ); +// } + +// function test_ejectOperator_revert_notEjector() public { +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; + +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); + +// cheats.prank(defaultOperator); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// cheats.expectRevert(bytes4(keccak256("OnlyEjector()"))); +// cheats.prank(defaultOperator); +// registryCoordinator.ejectOperator(defaultOperator, quorumNumbers); +// } + +// function test_getQuorumBitmapIndicesAtBlockNumber_revert_notRegistered() public { +// uint32 blockNumber; +// bytes32[] memory operatorIds = new bytes32[](1); +// cheats.expectRevert("RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId"); +// registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); +// } + +// // @notice tests for correct reversion and return values in the event that an operator registers +// function test_getQuorumBitmapIndicesAtBlockNumber_operatorRegistered() public { +// // register the operator +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// uint32 registrationBlockNumber = 100; +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); +// cheats.roll(registrationBlockNumber); +// cheats.startPrank(defaultOperator); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// uint32 blockNumber = 0; +// bytes32[] memory operatorIds = new bytes32[](1); +// operatorIds[0] = defaultOperatorId; + +// uint32[] memory returnArray; +// cheats.expectRevert("RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId"); +// registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); + +// blockNumber = registrationBlockNumber; +// returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); +// assertEq(returnArray[0], 0, "defaultOperator bitmap index at blockNumber registrationBlockNumber was not 0"); + +// blockNumber = registrationBlockNumber + 1; +// returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); +// assertEq(returnArray[0], 0, "defaultOperator bitmap index at blockNumber registrationBlockNumber + 1 was not 0"); +// } + +// // @notice tests for correct reversion and return values in the event that an operator registers and later deregisters +// function test_getQuorumBitmapIndicesAtBlockNumber_operatorDeregistered() public { +// test_deregisterOperator_singleQuorumAndSingleOperator(); +// uint32 registrationBlockNumber = 100; +// uint32 deregistrationBlockNumber = 200; +// uint32 blockNumber = 0; +// bytes32[] memory operatorIds = new bytes32[](1); +// operatorIds[0] = defaultOperatorId; + +// uint32[] memory returnArray; +// cheats.expectRevert("RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId"); +// registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); + +// blockNumber = registrationBlockNumber; +// returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); +// assertEq(returnArray[0], 0, "defaultOperator bitmap index at blockNumber registrationBlockNumber was not 0"); + +// blockNumber = registrationBlockNumber + 1; +// returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); +// assertEq(returnArray[0], 0, "defaultOperator bitmap index at blockNumber registrationBlockNumber + 1 was not 0"); + +// blockNumber = deregistrationBlockNumber; +// returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); +// assertEq(returnArray[0], 1, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber was not 1"); + +// blockNumber = deregistrationBlockNumber + 1; +// returnArray = registryCoordinator.getQuorumBitmapIndicesAtBlockNumber(blockNumber, operatorIds); +// assertEq(returnArray[0], 1, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber + 1 was not 1"); +// } + +// // @notice tests for correct reversion and return values in the event that an operator registers and later deregisters +// function test_getQuorumBitmapAtBlockNumberByIndex_operatorDeregistered() public { +// test_deregisterOperator_singleQuorumAndSingleOperator(); +// uint32 registrationBlockNumber = 100; +// uint32 deregistrationBlockNumber = 200; +// uint32 blockNumber = 0; +// bytes32 operatorId = defaultOperatorId; +// uint256 index = 0; + +// uint192 defaultQuorumBitmap = 1; +// uint192 emptyBitmap = 0; + +// // try an incorrect blockNumber input and confirm reversion +// cheats.expectRevert(QuorumBitmapHistoryLib.BitmapUpdateIsAfterBlockNumber.selector); +// uint192 returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); + +// blockNumber = registrationBlockNumber; +// returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); +// assertEq(returnVal, defaultQuorumBitmap, "defaultOperator bitmap index at blockNumber registrationBlockNumber was not defaultQuorumBitmap"); + +// blockNumber = registrationBlockNumber + 1; +// returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); +// assertEq(returnVal, defaultQuorumBitmap, "defaultOperator bitmap index at blockNumber registrationBlockNumber + 1 was not defaultQuorumBitmap"); + +// // try an incorrect index input and confirm reversion +// index = 1; +// cheats.expectRevert(QuorumBitmapHistoryLib.BitmapUpdateIsAfterBlockNumber.selector); +// returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); + +// blockNumber = deregistrationBlockNumber; +// returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); +// assertEq(returnVal, emptyBitmap, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber was not emptyBitmap"); + +// blockNumber = deregistrationBlockNumber + 1; +// returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); +// assertEq(returnVal, emptyBitmap, "defaultOperator bitmap index at blockNumber deregistrationBlockNumber + 1 was not emptyBitmap"); + +// // try an incorrect index input and confirm reversion +// index = 0; +// cheats.expectRevert(QuorumBitmapHistoryLib.NextBitmapUpdateIsBeforeBlockNumber.selector); +// returnVal = registryCoordinator.getQuorumBitmapAtBlockNumberByIndex(operatorId, blockNumber, index); +// } +// } + +// contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoordinatorUnitTests { +// // @notice registers an operator for a single quorum, with a fuzzed pubkey, churning out another operator from the quorum +// function testFuzz_registerOperatorWithChurn(uint256 pseudoRandomNumber) public { +// uint32 numOperators = defaultMaxOperatorCount; +// uint32 kickRegistrationBlockNumber = 100; +// uint32 registrationBlockNumber = 200; + +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); + +// cheats.roll(kickRegistrationBlockNumber); + +// for (uint i = 0; i < numOperators - 1; i++) { +// BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); +// address operator = _incrementAddress(defaultOperator, i); + +// _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); +// } + +// address operatorToRegister = _incrementAddress(defaultOperator, numOperators); +// BN254.G1Point memory operatorToRegisterPubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, numOperators))); +// bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); +// bytes32 operatorToKickId; +// address operatorToKick; + +// // register last operator before kick +// ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = new ISlashingRegistryCoordinator.OperatorKickParam[](1); +// { +// BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, numOperators - 1))); +// operatorToKickId = BN254.hashG1Point(pubKey); +// operatorToKick = _incrementAddress(defaultOperator, numOperators - 1); + +// _registerOperatorWithCoordinator(operatorToKick, quorumBitmap, pubKey); + +// bytes32[] memory operatorIdsToSwap = new bytes32[](1); +// // operatorIdsToSwap[0] = operatorToRegisterId +// operatorIdsToSwap[0] = operatorToRegisterId; + +// operatorKickParams[0] = ISlashingRegistryCoordinator.OperatorKickParam({ +// quorumNumber: defaultQuorumNumber, +// operator: operatorToKick +// }); +// } + +// blsApkRegistry.setBLSPublicKey(operatorToRegister, operatorToRegisterPubKey); + +// uint96 registeringStake = defaultKickBIPsOfOperatorStake * defaultStake; +// _setOperatorWeight(operatorToRegister, defaultQuorumNumber, registeringStake); + +// cheats.roll(registrationBlockNumber); +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit OperatorSocketUpdate(operatorToRegisterId, defaultSocket); +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit OperatorRegistered(operatorToRegister, operatorToRegisterId); + +// cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); +// emit OperatorAddedToQuorums(operatorToRegister, operatorToRegisterId, quorumNumbers); +// cheats.expectEmit(true, true, true, false, address(stakeRegistry)); +// emit OperatorStakeUpdate(operatorToRegisterId, defaultQuorumNumber, registeringStake - 1); +// cheats.expectEmit(true, true, true, true, address(indexRegistry)); +// emit QuorumIndexUpdate(operatorToRegisterId, defaultQuorumNumber, numOperators); + + +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit OperatorDeregistered(operatorKickParams[0].operator, operatorToKickId); +// cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); +// emit OperatorRemovedFromQuorums(operatorKickParams[0].operator, operatorToKickId, quorumNumbers); +// cheats.expectEmit(true, true, true, true, address(stakeRegistry)); +// emit OperatorStakeUpdate(operatorToKickId, defaultQuorumNumber, 0); +// cheats.expectEmit(true, true, true, true, address(indexRegistry)); +// emit QuorumIndexUpdate(operatorToRegisterId, defaultQuorumNumber, numOperators - 1); + +// { +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; +// ISignatureUtils.SignatureWithSaltAndExpiry memory signatureWithExpiry = +// _signOperatorChurnApproval(operatorToRegister, operatorToRegisterId, operatorKickParams, defaultSalt, block.timestamp + 10); +// cheats.prank(operatorToRegister); +// uint256 gasBefore = gasleft(); +// registryCoordinator.registerOperatorWithChurn( +// quorumNumbers, +// defaultSocket, +// pubkeyRegistrationParams, +// operatorKickParams, +// signatureWithExpiry, +// emptyAVSRegSig +// ); +// uint256 gasAfter = gasleft(); +// emit log_named_uint("gasUsed", gasBefore - gasAfter); +// } + +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(operatorToRegister))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: operatorToRegisterId, +// status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED +// }))) +// ); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getOperator(operatorToKick))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ +// operatorId: operatorToKickId, +// status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED +// }))) +// ); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToKickId, 0))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(quorumBitmap), +// updateBlockNumber: kickRegistrationBlockNumber, +// nextUpdateBlockNumber: registrationBlockNumber +// }))) +// ); +// } + +// function test_registerOperatorWithChurn_revert_lessThanKickBIPsOfOperatorStake(uint256 pseudoRandomNumber) public { +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; + +// ( +// address operatorToRegister, +// BN254.G1Point memory operatorToRegisterPubKey, +// ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams +// ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, defaultStake); +// bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); + +// _setOperatorWeight(operatorToRegister, defaultQuorumNumber, defaultStake); + +// cheats.roll(registrationBlockNumber); +// ISignatureUtils.SignatureWithSaltAndExpiry memory signatureWithExpiry = +// _signOperatorChurnApproval(operatorToRegister, operatorToRegisterId, operatorKickParams, defaultSalt, block.timestamp + 10); +// cheats.prank(operatorToRegister); +// cheats.expectRevert(bytes4(keccak256("InsufficientStakeForChurn()"))); +// registryCoordinator.registerOperatorWithChurn( +// quorumNumbers, +// defaultSocket, +// pubkeyRegistrationParams, +// operatorKickParams, +// signatureWithExpiry, +// emptyAVSRegSig +// ); +// } + +// function test_registerOperatorWithChurn_revert_lessThanKickBIPsOfTotalStake(uint256 pseudoRandomNumber) public { +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; + +// uint96 operatorToKickStake = defaultMaxOperatorCount * defaultStake; +// ( +// address operatorToRegister, +// BN254.G1Point memory operatorToRegisterPubKey, +// ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams +// ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, operatorToKickStake); +// bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); + + +// // set the stake of the operator to register to the defaultKickBIPsOfOperatorStake multiple of the operatorToKickStake +// _setOperatorWeight(operatorToRegister, defaultQuorumNumber, operatorToKickStake * defaultKickBIPsOfOperatorStake / 10000 + 1); + +// cheats.roll(registrationBlockNumber); +// ISignatureUtils.SignatureWithSaltAndExpiry memory signatureWithExpiry = +// _signOperatorChurnApproval(operatorToRegister, operatorToRegisterId, operatorKickParams, defaultSalt, block.timestamp + 10); +// cheats.prank(operatorToRegister); +// cheats.expectRevert(bytes4(keccak256("CannotKickOperatorAboveThreshold()"))); +// registryCoordinator.registerOperatorWithChurn( +// quorumNumbers, +// defaultSocket, +// pubkeyRegistrationParams, +// operatorKickParams, +// signatureWithExpiry, +// emptyAVSRegSig +// ); +// } + +// function test_registerOperatorWithChurn_revert_invalidChurnApproverSignature(uint256 pseudoRandomNumber) public { +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; + +// ( +// address operatorToRegister, +// , +// ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams +// ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, defaultStake); + +// uint96 registeringStake = defaultKickBIPsOfOperatorStake * defaultStake; +// _setOperatorWeight(operatorToRegister, defaultQuorumNumber, registeringStake); + +// cheats.roll(registrationBlockNumber); +// ISignatureUtils.SignatureWithSaltAndExpiry memory signatureWithSaltAndExpiry; +// signatureWithSaltAndExpiry.expiry = block.timestamp + 10; +// signatureWithSaltAndExpiry.signature = +// hex"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001B"; +// signatureWithSaltAndExpiry.salt = defaultSalt; +// cheats.prank(operatorToRegister); +// cheats.expectRevert(bytes4(keccak256("InvalidSignature()"))); +// registryCoordinator.registerOperatorWithChurn( +// quorumNumbers, +// defaultSocket, +// pubkeyRegistrationParams, +// operatorKickParams, +// signatureWithSaltAndExpiry, +// emptyAVSRegSig +// ); +// } + +// function test_registerOperatorWithChurn_revert_expiredChurnApproverSignature(uint256 pseudoRandomNumber) public { +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptyAVSRegSig; + +// ( +// address operatorToRegister, +// BN254.G1Point memory operatorToRegisterPubKey, +// ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams +// ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, defaultStake); +// bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); + +// uint96 registeringStake = defaultKickBIPsOfOperatorStake * defaultStake; +// _setOperatorWeight(operatorToRegister, defaultQuorumNumber, registeringStake); + +// cheats.roll(registrationBlockNumber); +// ISignatureUtils.SignatureWithSaltAndExpiry memory signatureWithSaltAndExpiry = +// _signOperatorChurnApproval(operatorToRegister, operatorToRegisterId, operatorKickParams, defaultSalt, block.timestamp - 1); +// cheats.prank(operatorToRegister); +// cheats.expectRevert(bytes4(keccak256("SignatureExpired()"))); +// registryCoordinator.registerOperatorWithChurn( +// quorumNumbers, +// defaultSocket, +// pubkeyRegistrationParams, +// operatorKickParams, +// signatureWithSaltAndExpiry, +// emptyAVSRegSig +// ); +// } +// } + +// contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnitTests { +// function test_updateOperators_revert_paused() public { +// cheats.prank(pauser); +// registryCoordinator.pause(2 ** PAUSED_UPDATE_OPERATOR); + +// address[] memory operatorsToUpdate = new address[](1); +// operatorsToUpdate[0] = defaultOperator; + +// cheats.expectRevert(bytes4(keccak256("CurrentlyPaused()"))); +// registryCoordinator.updateOperators(operatorsToUpdate); +// } + +// // @notice tests the `updateOperators` function with a single registered operator as input +// function test_updateOperators_singleOperator() public { +// // register the default operator +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// uint32 registrationBlockNumber = 100; +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); +// cheats.startPrank(defaultOperator); +// cheats.roll(registrationBlockNumber); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// address[] memory operatorsToUpdate = new address[](1); +// operatorsToUpdate[0] = defaultOperator; + +// registryCoordinator.updateOperators(operatorsToUpdate); +// } + +// // @notice tests the `updateOperators` function with a single registered operator as input +// // @dev also sets up return data from the StakeRegistry +// function testFuzz_updateOperators_singleOperator(uint192 registrationBitmap, uint192 mockReturnData) public { +// // filter fuzzed inputs to only valid inputs +// cheats.assume(registrationBitmap != 0); +// mockReturnData = (mockReturnData & registrationBitmap); +// emit log_named_uint("mockReturnData", mockReturnData); + +// // register the default operator +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// uint32 registrationBlockNumber = 100; +// bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(registrationBitmap); +// for (uint256 i = 0; i < quorumNumbers.length; ++i) { +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[i]), defaultStake); +// } +// cheats.startPrank(defaultOperator); +// cheats.roll(registrationBlockNumber); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// address[] memory operatorsToUpdate = new address[](1); +// operatorsToUpdate[0] = defaultOperator; + +// uint192 quorumBitmapBefore = registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId); +// assertEq(quorumBitmapBefore, registrationBitmap, "operator bitmap somehow incorrect"); + +// // make the stake registry return info that the operator should be removed from quorums +// uint192 quorumBitmapToRemove = mockReturnData; +// bytes memory quorumNumbersToRemove = BitmapUtils.bitmapToBytesArray(quorumBitmapToRemove); +// for (uint256 i = 0; i < quorumNumbersToRemove.length; ++i) { +// _setOperatorWeight(defaultOperator, uint8(quorumNumbersToRemove[i]), 0); +// } +// uint256 expectedQuorumBitmap = BitmapUtils.minus(quorumBitmapBefore, quorumBitmapToRemove); + +// registryCoordinator.updateOperators(operatorsToUpdate); +// uint192 quorumBitmapAfter = registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId); +// assertEq(expectedQuorumBitmap, quorumBitmapAfter, "quorum bitmap did not update correctly"); +// } + +// // @notice tests the `updateOperators` function with a single *un*registered operator as input +// function test_updateOperators_unregisteredOperator() public view { +// address[] memory operatorsToUpdate = new address[](1); +// operatorsToUpdate[0] = defaultOperator; + +// // force a staticcall to the `updateOperators` function -- this should *pass* because the call should be a strict no-op! +// (bool success, ) = address(registryCoordinator).staticcall(abi.encodeWithSignature("updateOperators(address[])", operatorsToUpdate)); +// require(success, "staticcall failed!"); +// } + +// function test_updateOperatorsForQuorum_revert_paused() public { +// cheats.prank(pauser); +// registryCoordinator.pause(2 ** PAUSED_UPDATE_OPERATOR); + +// address[][] memory operatorsToUpdate = new address[][](1); +// address[] memory operatorArray = new address[](1); +// operatorArray[0] = defaultOperator; +// operatorsToUpdate[0] = operatorArray; +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// cheats.expectRevert(bytes4(keccak256("CurrentlyPaused()"))); +// registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); +// } + +// function test_updateOperatorsForQuorum_revert_nonexistentQuorum() public { +// _deployMockEigenLayerAndAVS(10); +// bytes memory quorumNumbersNotCreated = new bytes(1); +// quorumNumbersNotCreated[0] = 0x0B; +// address[][] memory operatorsToUpdate = new address[][](1); + +// cheats.prank(defaultOperator); +// cheats.expectRevert(BitmapUtils.BitmapValueTooLarge.selector); +// registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbersNotCreated); +// } + +// function test_updateOperatorsForQuorum_revert_inputLengthMismatch() public { +// address[][] memory operatorsToUpdate = new address[][](2); +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// cheats.expectRevert(bytes4(keccak256("InputLengthMismatch()"))); +// registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); +// } + +// function test_updateOperatorsForQuorum_revert_incorrectNumberOfOperators() public { +// address[][] memory operatorsToUpdate = new address[][](1); +// address[] memory operatorArray = new address[](1); +// operatorArray[0] = defaultOperator; +// operatorsToUpdate[0] = operatorArray; +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); + +// cheats.expectRevert(bytes4(keccak256("QuorumOperatorCountMismatch()"))); +// registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); +// } + +// function test_updateOperatorsForQuorum_revert_unregisteredOperator() public { +// // register the default operator +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// uint32 registrationBlockNumber = 100; +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); +// cheats.startPrank(defaultOperator); +// cheats.roll(registrationBlockNumber); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// address[][] memory operatorsToUpdate = new address[][](1); +// address[] memory operatorArray = new address[](1); +// // use an unregistered operator address as input +// operatorArray[0] = _incrementAddress(defaultOperator, 1); +// operatorsToUpdate[0] = operatorArray; + +// cheats.expectRevert(bytes4(keccak256("NotRegisteredForQuorum()"))); +// registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); +// } + +// // note: there is not an explicit check for duplicates, as checking for explicit ordering covers this +// function test_updateOperatorsForQuorum_revert_duplicateOperator(uint256 pseudoRandomNumber) public { +// // register 2 operators +// uint32 numOperators = 2; +// uint32 registrationBlockNumber = 200; +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); +// cheats.roll(registrationBlockNumber); +// for (uint i = 0; i < numOperators; i++) { +// BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); +// address operator = _incrementAddress(defaultOperator, i); + +// _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); +// } + +// address[][] memory operatorsToUpdate = new address[][](1); +// address[] memory operatorArray = new address[](2); +// // use the same operator address twice as input +// operatorArray[0] = defaultOperator; +// operatorArray[1] = defaultOperator; +// operatorsToUpdate[0] = operatorArray; + +// // note: there is not an explicit check for duplicates, as checking for explicit ordering covers this +// cheats.expectRevert(bytes4(keccak256("NotSorted()"))); +// registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); +// } + +// function test_updateOperatorsForQuorum_revert_incorrectListOrder(uint256 pseudoRandomNumber) public { +// // register 2 operators +// uint32 numOperators = 2; +// uint32 registrationBlockNumber = 200; +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); +// cheats.roll(registrationBlockNumber); +// for (uint i = 0; i < numOperators; i++) { +// BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); +// address operator = _incrementAddress(defaultOperator, i); + +// _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); +// } + +// address[][] memory operatorsToUpdate = new address[][](1); +// address[] memory operatorArray = new address[](2); +// // order the operator addresses in descending order, instead of ascending order +// operatorArray[0] = _incrementAddress(defaultOperator, 1); +// operatorArray[1] = defaultOperator; +// operatorsToUpdate[0] = operatorArray; + +// cheats.expectRevert(bytes4(keccak256("NotSorted()"))); +// registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); +// } + +// function test_updateOperatorsForQuorum_singleOperator() public { +// // register the default operator +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; +// uint32 registrationBlockNumber = 100; +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); +// cheats.startPrank(defaultOperator); +// cheats.roll(registrationBlockNumber); +// registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + +// address[][] memory operatorsToUpdate = new address[][](1); +// address[] memory operatorArray = new address[](1); +// operatorArray[0] = defaultOperator; +// operatorsToUpdate[0] = operatorArray; + +// uint256 quorumUpdateBlockNumberBefore = registryCoordinator.quorumUpdateBlockNumber(defaultQuorumNumber); +// require(quorumUpdateBlockNumberBefore != block.number, "bad test setup!"); + +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit QuorumBlockNumberUpdated(defaultQuorumNumber, block.number); +// registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); + +// uint256 quorumUpdateBlockNumberAfter = registryCoordinator.quorumUpdateBlockNumber(defaultQuorumNumber); +// assertEq(quorumUpdateBlockNumberAfter, block.number, "quorumUpdateBlockNumber not set correctly"); +// } + +// function test_updateOperatorsForQuorum_twoOperators(uint256 pseudoRandomNumber) public { +// // register 2 operators +// uint32 numOperators = 2; +// uint32 registrationBlockNumber = 200; +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(defaultQuorumNumber); +// uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); +// cheats.roll(registrationBlockNumber); +// for (uint i = 0; i < numOperators; i++) { +// BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, i))); +// address operator = _incrementAddress(defaultOperator, i); + +// _registerOperatorWithCoordinator(operator, quorumBitmap, pubKey); +// } + +// address[][] memory operatorsToUpdate = new address[][](1); +// address[] memory operatorArray = new address[](2); +// // order the operator addresses in descending order, instead of ascending order +// operatorArray[0] = defaultOperator; +// operatorArray[1] = _incrementAddress(defaultOperator, 1); +// operatorsToUpdate[0] = operatorArray; + +// uint256 quorumUpdateBlockNumberBefore = registryCoordinator.quorumUpdateBlockNumber(defaultQuorumNumber); +// require(quorumUpdateBlockNumberBefore != block.number, "bad test setup!"); + +// cheats.expectEmit(true, true, true, true, address(registryCoordinator)); +// emit QuorumBlockNumberUpdated(defaultQuorumNumber, block.number); +// registryCoordinator.updateOperatorsForQuorum(operatorsToUpdate, quorumNumbers); + +// uint256 quorumUpdateBlockNumberAfter = registryCoordinator.quorumUpdateBlockNumber(defaultQuorumNumber); +// assertEq(quorumUpdateBlockNumberAfter, block.number, "quorumUpdateBlockNumber not set correctly"); +// } + +// // @notice tests that the internal `_updateOperatorBitmap` function works as expected, for fuzzed inputs +// function testFuzz_updateOperatorBitmapInternal_noPreviousEntries(uint192 newBitmap) public { +// registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(newBitmap), +// updateBlockNumber: uint32(block.number), +// nextUpdateBlockNumber: 0 +// }))) +// ); +// } + +// // @notice tests that the internal `_updateOperatorBitmap` function works as expected, for fuzzed inputs +// function testFuzz_updateOperatorBitmapInternal_previousEntryInCurrentBlock(uint192 newBitmap) public { +// uint192 pastBitmap = 1; +// testFuzz_updateOperatorBitmapInternal_noPreviousEntries(pastBitmap); + +// registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(newBitmap), +// updateBlockNumber: uint32(block.number), +// nextUpdateBlockNumber: 0 +// }))) +// ); +// } + +// // @notice tests that the internal `_updateOperatorBitmap` function works as expected, for fuzzed inputs +// function testFuzz_updateOperatorBitmapInternal_previousEntryInPastBlock(uint192 newBitmap) public { +// uint192 pastBitmap = 1; +// testFuzz_updateOperatorBitmapInternal_noPreviousEntries(pastBitmap); + +// // advance the block number +// uint256 previousBlockNumber = block.number; +// cheats.roll(previousBlockNumber + 1); + +// registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(pastBitmap), +// updateBlockNumber: uint32(previousBlockNumber), +// nextUpdateBlockNumber: uint32(block.number) +// }))) +// ); +// assertEq( +// keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), +// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// quorumBitmap: uint192(newBitmap), +// updateBlockNumber: uint32(block.number), +// nextUpdateBlockNumber: 0 +// }))) +// ); +// } +// } + +// contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnitTests { +// function test_registerALMHook_Reverts() public { +// cheats.prank(address(registryCoordinator.allocationManager())); +// cheats.expectRevert(); +// registryCoordinator.registerOperator(defaultOperator, new uint32[](0), abi.encode(defaultSocket, pubkeyRegistrationParams)); +// } + +// function test_deregisterALMHook_Reverts() public { +// uint32[] memory operatorSetIds = new uint32[](1); +// operatorSetIds[0] = 0; +// cheats.prank(address(registryCoordinator.allocationManager())); +// cheats.expectRevert(); +// registryCoordinator.deregisterOperator(defaultOperator, operatorSetIds); +// } + +// function test_CreateTotalDelegatedStakeQuorum() public { +// _deployMockEigenLayerAndAVS(0); +// // Set up test params +// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// maxOperatorCount: 10, +// kickBIPsOfOperatorStake: 0, +// kickBIPsOfTotalStake: 0 +// }); +// uint96 minimumStake = 100; +// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); +// strategyParams[0] = IStakeRegistry.StrategyParams({ +// strategy: IStrategy(address(0x1)), +// multiplier: 1000 +// }); + +// // Get initial quorum count +// uint8 initialQuorumCount = registryCoordinator.quorumCount(); + +// // Create quorum with total delegated stake type +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.createTotalDelegatedStakeQuorum( +// operatorSetParams, +// minimumStake, +// strategyParams +// ); + +// // Verify quorum was created +// assertEq(registryCoordinator.quorumCount(), initialQuorumCount + 1); + +// // Verify quorum params were set correctly +// ISlashingRegistryCoordinator.OperatorSetParam memory storedParams = registryCoordinator.getOperatorSetParams(initialQuorumCount); +// assertEq(storedParams.maxOperatorCount, operatorSetParams.maxOperatorCount); +// assertEq(storedParams.kickBIPsOfOperatorStake, operatorSetParams.kickBIPsOfOperatorStake); +// assertEq(storedParams.kickBIPsOfTotalStake, operatorSetParams.kickBIPsOfTotalStake); +// } + +// function test_CreateSlashableStakeQuorum_Reverts() public { +// _deployMockEigenLayerAndAVS(0); +// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// maxOperatorCount: 10, +// kickBIPsOfOperatorStake: 0, +// kickBIPsOfTotalStake: 0 +// }); +// uint96 minimumStake = 100; +// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); +// strategyParams[0] = IStakeRegistry.StrategyParams({ +// strategy: IStrategy(address(0x1)), +// multiplier: 1000 +// }); +// uint32 lookAheadPeriod = 100; + +// // Attempt to create quorum with slashable stake type before enabling operator sets +// cheats.prank(registryCoordinatorOwner); +// cheats.expectRevert(); +// registryCoordinator.createSlashableStakeQuorum( +// operatorSetParams, +// minimumStake, +// strategyParams, +// lookAheadPeriod +// ); +// } + +// function test_MigrateToOperatorSets() public { +// _deployMockEigenLayerAndAVS(0); +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.enableOperatorSets(); +// assertTrue(registryCoordinator.operatorSetsEnabled()); +// } +// } + +// contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitTests { +// function test_MigrateToOperatorSets() public { +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.enableOperatorSets(); +// assertTrue(registryCoordinator.operatorSetsEnabled()); +// } + +// function test_M2_Deregister() public { +// vm.skip(true); +// /// Create 2 M2 quorums +// _deployMockEigenLayerAndAVS(2); + +// address operatorToRegister = address(420); + +// ISignatureUtils.SignatureWithSaltAndExpiry memory emptySignature = ISignatureUtils.SignatureWithSaltAndExpiry({ +// signature: new bytes(0), +// salt: bytes32(0), +// expiry: 0 +// }); + +// IBLSApkRegistry.PubkeyRegistrationParams memory operatorRegisterApkParams = IBLSApkRegistry.PubkeyRegistrationParams({ +// pubkeyRegistrationSignature: BN254.G1Point({ +// X: 0, +// Y: 0 +// }), +// pubkeyG1: BN254.G1Point({ +// X: 0, +// Y: 0 +// }), +// pubkeyG2: BN254.G2Point({ +// X: [uint256(0), uint256(0)], +// Y: [uint256(0), uint256(0)] +// }) +// }); + +// string memory socket = "socket"; + +// // register for quorum 0 +// vm.prank(operatorToRegister); +// registryCoordinator.registerOperator( +// new bytes(1), // Convert 0 to bytes1 first +// socket, +// operatorRegisterApkParams, +// emptySignature +// ); + +// /// migrate to operator sets +// registryCoordinator.enableOperatorSets(); + +// /// Deregistration for m2 should for the first two operator sets +// vm.prank(defaultOperator); +// registryCoordinator.deregisterOperator(new bytes(1)); + +// // Verify operator was deregistered by checking their bitmap is empty +// bytes32 operatorId = registryCoordinator.getOperatorId(operatorToRegister); +// uint192 bitmap = registryCoordinator.getCurrentQuorumBitmap(operatorId); +// assertEq(bitmap, 0, "Operator bitmap should be empty after deregistration"); + +// // Verify operator status is NEVER_REGISTERED +// ISlashingRegistryCoordinator.OperatorStatus status = registryCoordinator.getOperatorStatus(operatorToRegister); +// assertEq(uint8(status), uint8(ISlashingRegistryCoordinator.OperatorStatus.NEVER_REGISTERED), "Operator status should be NEVER_REGISTERED"); +// } + +// function test_M2_Register_Reverts() public { +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.enableOperatorSets(); + +// bytes memory quorumNumbers = new bytes(1); +// quorumNumbers[0] = bytes1(uint8(0)); +// IBLSApkRegistry.PubkeyRegistrationParams memory params; +// ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; + +// cheats.expectRevert(); +// registryCoordinator.registerOperator( +// quorumNumbers, +// defaultSocket, +// params, +// operatorSignature +// ); +// } + +// function test_createSlashableStakeQuorum() public { +// // Deploy with 0 quorums +// _deployMockEigenLayerAndAVS(0); + +// // Enable operator sets first +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.enableOperatorSets(); + +// // Create quorum params +// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// maxOperatorCount: 10, +// kickBIPsOfOperatorStake: 1000, +// kickBIPsOfTotalStake: 100 +// }); +// uint96 minimumStake = 100; +// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); +// strategyParams[0] = IStakeRegistry.StrategyParams({ +// strategy: IStrategy(address(1)), +// multiplier: 1 +// }); +// uint32 lookAheadPeriod = 100; + +// // Create slashable stake quorum +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.createSlashableStakeQuorum( +// operatorSetParams, +// minimumStake, +// strategyParams, +// lookAheadPeriod +// ); +// } + +// function test_createTotalDelegatedStakeQuorum() public { +// // Deploy with 0 quorums +// _deployMockEigenLayerAndAVS(0); + +// // Enable operator sets first +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.enableOperatorSets(); + +// // Create quorum params +// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// maxOperatorCount: 10, +// kickBIPsOfOperatorStake: 1000, +// kickBIPsOfTotalStake: 100 +// }); +// uint96 minimumStake = 100; +// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); +// strategyParams[0] = IStakeRegistry.StrategyParams({ +// strategy: IStrategy(address(1)), +// multiplier: 10000 +// }); + +// // Create total delegated stake quorum +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.createTotalDelegatedStakeQuorum( +// operatorSetParams, +// minimumStake, +// strategyParams +// ); +// } + +// function test_registerHook() public { +// vm.skip(true); + +// _deployMockEigenLayerAndAVS(0); +// // Enable operator sets first +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.enableOperatorSets(); + +// // Create quorum params +// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// maxOperatorCount: 10, +// kickBIPsOfOperatorStake: 1000, +// kickBIPsOfTotalStake: 100 +// }); + +// uint96 minimumStake = 100; +// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); +// strategyParams[0] = IStakeRegistry.StrategyParams({ +// strategy: IStrategy(address(1)), +// multiplier: 10000 +// }); + +// // Create total delegated stake quorum +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.createTotalDelegatedStakeQuorum( +// operatorSetParams, +// 0, +// strategyParams +// ); + + +// uint32[] memory operatorSetIds = new uint32[](1); +// operatorSetIds[0] = 0; + +// string memory socket = "socket"; +// IBLSApkRegistry.PubkeyRegistrationParams memory params; +// // TODO: +// // params = IBLSApkRegistry.PubkeyRegistrationParams({ +// // pubkeyG1: defaultPubKey, +// // pubkeyG2: defaultPubKeyG2, +// // pubkeySignature: defaultPubKeySignature +// // }); + +// bytes memory data = abi.encode(socket, params); + +// cheats.prank(address(registryCoordinator.allocationManager())); +// registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); +// } + +// function test_registerHook_WithChurn() public { +// _deployMockEigenLayerAndAVS(0); +// // Enable operator sets first +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.enableOperatorSets(); + +// // Create quorum params +// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// maxOperatorCount: 10, +// kickBIPsOfOperatorStake: 1000, +// kickBIPsOfTotalStake: 100 +// }); + +// uint96 minimumStake = 100; +// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); +// strategyParams[0] = IStakeRegistry.StrategyParams({ +// strategy: IStrategy(address(1)), +// multiplier: 10000 +// }); + +// // Create total delegated stake quorum +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.createTotalDelegatedStakeQuorum( +// operatorSetParams, +// 0, +// strategyParams +// ); + +// uint32[] memory operatorSetIds = new uint32[](1); +// operatorSetIds[0] = 0; + +// string memory socket = "socket"; +// IBLSApkRegistry.PubkeyRegistrationParams memory params; +// // TODO: +// // params = IBLSApkRegistry.PubkeyRegistrationParams({ +// // pubkeyG1: defaultPubKey, +// // pubkeyG2: defaultPubKeyG2, +// // pubkeySignature: defaultPubKeySignature +// // }); + +// ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = new ISlashingRegistryCoordinator.OperatorKickParam[](1); +// operatorKickParams[0] = ISlashingRegistryCoordinator.OperatorKickParam({ +// operator: address(0x1), +// quorumNumber: 0 +// }); + +// ISignatureUtils.SignatureWithSaltAndExpiry memory churnApproverSignature; +// ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; + +// bytes memory registerParams = abi.encode( +// socket, +// params, +// operatorKickParams, +// churnApproverSignature, +// operatorSignature +// ); + +// // Prank as allocation manager and call register hook +// cheats.prank(address(registryCoordinator.allocationManager())); +// registryCoordinator.registerOperator(defaultOperator, operatorSetIds, registerParams); +// } + +// function test_updateStakesForQuorum() public { +// vm.skip(true); +// _deployMockEigenLayerAndAVS(0); + +// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// maxOperatorCount: defaultMaxOperatorCount, +// kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, +// kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake +// }); + +// uint96 minimumStake = 100; +// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); +// strategyParams[0] = IStakeRegistry.StrategyParams({ +// strategy: IStrategy(address(1)), +// multiplier: 10000 +// }); + +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.createTotalDelegatedStakeQuorum( +// operatorSetParams, +// minimumStake, +// strategyParams +// ); + +// uint256 quorumBitmap = 0; + +// // TODO: register actually and update stakes +// } + +// function test_deregisterHook() public { + +// _deployMockEigenLayerAndAVS(0); +// // Enable operator sets first +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.enableOperatorSets(); + +// // Create quorum params +// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// maxOperatorCount: 10, +// kickBIPsOfOperatorStake: 1000, +// kickBIPsOfTotalStake: 100 +// }); + +// uint96 minimumStake = 100; +// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); +// strategyParams[0] = IStakeRegistry.StrategyParams({ +// strategy: IStrategy(address(1)), +// multiplier: 10000 +// }); + +// // Create total delegated stake quorum +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.createTotalDelegatedStakeQuorum( +// operatorSetParams, +// 0, +// strategyParams +// ); + +// // Prank as allocation manager and call register hook +// uint32[] memory operatorSetIds = new uint32[](1); +// operatorSetIds[0] = 0; + +// string memory socket = "socket"; +// IBLSApkRegistry.PubkeyRegistrationParams memory params; +// // TODO: +// // params = IBLSApkRegistry.PubkeyRegistrationParams({ +// // pubkeyG1: defaultPubKey, +// // pubkeyG2: defaultPubKeyG2, +// // pubkeySignature: defaultPubKeySignature +// // }); + +// bytes memory data = abi.encode(socket, params); + + +// cheats.startPrank(address(registryCoordinator.allocationManager())); +// registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); + +// registryCoordinator.deregisterOperator(defaultOperator, operatorSetIds); + +// cheats.stopPrank(); +// } + +// function test_registerHook_Reverts_WhenNotALM() public { + +// _deployMockEigenLayerAndAVS(0); +// // Enable operator sets first +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.enableOperatorSets(); + +// // Create quorum params +// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// maxOperatorCount: 10, +// kickBIPsOfOperatorStake: 1000, +// kickBIPsOfTotalStake: 100 +// }); + +// uint96 minimumStake = 100; +// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); +// strategyParams[0] = IStakeRegistry.StrategyParams({ +// strategy: IStrategy(address(1)), +// multiplier: 10000 +// }); + +// // Create total delegated stake quorum +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.createTotalDelegatedStakeQuorum( +// operatorSetParams, +// 0, +// strategyParams +// ); + + +// uint32[] memory operatorSetIds = new uint32[](1); +// operatorSetIds[0] = 0; + +// string memory socket = "socket"; +// IBLSApkRegistry.PubkeyRegistrationParams memory params; +// // TODO: +// // params = IBLSApkRegistry.PubkeyRegistrationParams({ +// // pubkeyG1: defaultPubKey, +// // pubkeyG2: defaultPubKeyG2, +// // pubkeySignature: defaultPubKeySignature +// // }); + +// bytes memory data = abi.encode(socket, params); + +// vm.expectRevert(); +// registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); +// } + +// function test_deregisterHook_Reverts_WhenNotALM() public { + +// _deployMockEigenLayerAndAVS(0); +// // Enable operator sets first +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.enableOperatorSets(); + +// // Create quorum params +// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// maxOperatorCount: 10, +// kickBIPsOfOperatorStake: 1000, +// kickBIPsOfTotalStake: 100 +// }); + +// uint96 minimumStake = 100; +// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); +// strategyParams[0] = IStakeRegistry.StrategyParams({ +// strategy: IStrategy(address(1)), +// multiplier: 10000 +// }); + +// // Create total delegated stake quorum +// cheats.prank(registryCoordinatorOwner); +// registryCoordinator.createTotalDelegatedStakeQuorum( +// operatorSetParams, +// 0, +// strategyParams +// ); + +// // Prank as allocation manager and call register hook +// uint32[] memory operatorSetIds = new uint32[](1); +// operatorSetIds[0] = 0; + +// string memory socket = "socket"; +// IBLSApkRegistry.PubkeyRegistrationParams memory params; +// // TODO: +// // params = IBLSApkRegistry.PubkeyRegistrationParams({ +// // pubkeyG1: defaultPubKey, +// // pubkeyG2: defaultPubKeyG2, +// // pubkeySignature: defaultPubKeySignature +// // }); + +// bytes memory data = abi.encode(socket, params); + + +// cheats.prank(address(registryCoordinator.allocationManager())); +// registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); +// cheats.stopPrank(); + +// cheats.expectRevert(); +// registryCoordinator.deregisterOperator(defaultOperator, operatorSetIds); + +// } + +// function test_DeregisterHook_Reverts_WhenM2Quorum() public { +// vm.skip(true); +// } + +// function test_registerHook_Reverts_WhenM2Quorum() public { +// vm.skip(true); +// } + +// } diff --git a/test/unit/StakeRegistryUnit.t.sol b/test/unit/StakeRegistryUnit.t.sol index ef479d7e..2352dfeb 100644 --- a/test/unit/StakeRegistryUnit.t.sol +++ b/test/unit/StakeRegistryUnit.t.sol @@ -56,11 +56,7 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { ); stakeRegistryImplementation = new StakeRegistryHarness( - IRegistryCoordinator(address(registryCoordinator)), - delegationMock, - avsDirectoryMock, - allocationManager, - serviceManager + ISlashingRegistryCoordinator(address(registryCoordinator)), delegationMock, avsDirectoryMock, allocationManager ); stakeRegistry = StakeRegistryHarness( @@ -589,7 +585,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint96 minimumStake, IStakeRegistry.StrategyParams[] memory strategyParams ) public { - cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinator.selector); + cheats.expectRevert(IStakeRegistryErrors.OnlySlashingRegistryCoordinator.selector); stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); } @@ -732,7 +728,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint8 quorumNumber, uint96 minimumStakeForQuorum ) public fuzzOnlyInitializedQuorums(quorumNumber) { - cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinatorOwner.selector); + cheats.expectRevert(IStakeRegistryErrors.OnlySlashingRegistryCoordinatorOwner.selector); stakeRegistry.setMinimumStakeForQuorum(quorumNumber, minimumStakeForQuorum); } @@ -770,7 +766,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint8 quorumNumber, IStakeRegistry.StrategyParams[] memory strategyParams ) public fuzzOnlyInitializedQuorums(quorumNumber) { - cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinatorOwner.selector); + cheats.expectRevert(IStakeRegistryErrors.OnlySlashingRegistryCoordinatorOwner.selector); stakeRegistry.addStrategies(quorumNumber, strategyParams); } @@ -869,7 +865,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint8 quorumNumber, uint256[] memory indicesToRemove ) public fuzzOnlyInitializedQuorums(quorumNumber) { - cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinatorOwner.selector); + cheats.expectRevert(IStakeRegistryErrors.OnlySlashingRegistryCoordinatorOwner.selector); stakeRegistry.removeStrategies(quorumNumber, indicesToRemove); } @@ -970,7 +966,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint256[] calldata strategyIndices, uint96[] calldata newMultipliers ) public fuzzOnlyInitializedQuorums(quorumNumber) { - cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinatorOwner.selector); + cheats.expectRevert(IStakeRegistryErrors.OnlySlashingRegistryCoordinatorOwner.selector); stakeRegistry.modifyStrategyParams(quorumNumber, strategyIndices, newMultipliers); } @@ -1062,7 +1058,7 @@ contract StakeRegistryUnitTests_Register is StakeRegistryUnitTests { function test_registerOperator_Revert_WhenNotRegistryCoordinator() public { (address operator, bytes32 operatorId) = _selectNewOperator(); - cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinator.selector); + cheats.expectRevert(IStakeRegistryErrors.OnlySlashingRegistryCoordinator.selector); stakeRegistry.registerOperator(operator, operatorId, initializedQuorumBytes); } @@ -1413,7 +1409,7 @@ contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { fuzzy_addtlStake: 0 }); - cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinator.selector); + cheats.expectRevert(IStakeRegistryErrors.OnlySlashingRegistryCoordinator.selector); stakeRegistry.deregisterOperator(setup.operatorId, setup.quorumsToRemove); } @@ -1777,7 +1773,7 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { UpdateSetup memory setup = _fuzz_setupUpdateOperatorStake({registeredFor: initializedQuorumBitmap, fuzzy_Delta: 0}); - cheats.expectRevert(IStakeRegistryErrors.OnlyRegistryCoordinator.selector); + cheats.expectRevert(IStakeRegistryErrors.OnlySlashingRegistryCoordinator.selector); stakeRegistry.updateOperatorStake(setup.operator, setup.operatorId, setup.quorumNumbers); } diff --git a/test/utils/MockAVSDeployer.sol b/test/utils/MockAVSDeployer.sol index a593e23e..20bdbb1d 100644 --- a/test/utils/MockAVSDeployer.sol +++ b/test/utils/MockAVSDeployer.sol @@ -11,6 +11,7 @@ import {BitmapUtils} from "../../src/libraries/BitmapUtils.sol"; import {BN254} from "../../src/libraries/BN254.sol"; import {OperatorStateRetriever} from "../../src/OperatorStateRetriever.sol"; +import {SlashingRegistryCoordinator} from "../../src/SlashingRegistryCoordinator.sol"; import {RegistryCoordinator} from "../../src/RegistryCoordinator.sol"; import {RegistryCoordinatorHarness} from "../harnesses/RegistryCoordinatorHarness.t.sol"; import {BLSApkRegistry} from "../../src/BLSApkRegistry.sol"; @@ -21,6 +22,8 @@ import {IBLSApkRegistry} from "../../src/interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry} from "../../src/interfaces/IStakeRegistry.sol"; import {IIndexRegistry} from "../../src/interfaces/IIndexRegistry.sol"; import {IRegistryCoordinator} from "../../src/interfaces/IRegistryCoordinator.sol"; + +import {ISlashingRegistryCoordinator} from "../../src/interfaces/ISlashingRegistryCoordinator.sol"; import {IServiceManager} from "../../src/interfaces/IServiceManager.sol"; import {StrategyManagerMock} from "eigenlayer-contracts/src/test/mocks/StrategyManagerMock.sol"; @@ -115,7 +118,7 @@ contract MockAVSDeployer is Test { uint16 defaultKickBIPsOfTotalStake = 150; uint8 numQuorums = 192; - IRegistryCoordinator.OperatorSetParam[] operatorSetParams; + ISlashingRegistryCoordinator.OperatorSetParam[] operatorSetParams; uint8 maxQuorumsToRegisterFor = 4; uint256 maxOperatorsToRegister = 4; @@ -208,13 +211,8 @@ contract MockAVSDeployer is Test { cheats.startPrank(proxyAdminOwner); - stakeRegistryImplementation = new StakeRegistryHarness( - IRegistryCoordinator(registryCoordinator), - delegationMock, - avsDirectory, - allocationManagerMock, - serviceManager - ); + stakeRegistryImplementation = + new StakeRegistryHarness(ISlashingRegistryCoordinator(registryCoordinator), delegationMock, avsDirectory, allocationManagerMock); proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(stakeRegistry))), address(stakeRegistryImplementation) @@ -290,11 +288,26 @@ contract MockAVSDeployer is Test { pauserRegistry ); { + proxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(registryCoordinator))), + address(registryCoordinatorImplementation), + abi.encodeCall( + SlashingRegistryCoordinator.initialize, + ( + registryCoordinatorOwner, // _initialOwner + churnApprover, // _churnApprover + ejector, // _ejector + 0, // _initialPausedStatus + address(serviceManager) // _accountIdentifier + ) + ) + ); + delete operatorSetParams; for (uint256 i = 0; i < numQuorumsToAdd; i++) { // hard code these for now operatorSetParams.push( - IRegistryCoordinator.OperatorSetParam({ + ISlashingRegistryCoordinator.OperatorSetParam({ maxOperatorCount: defaultMaxOperatorCount, kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake @@ -302,39 +315,24 @@ contract MockAVSDeployer is Test { ); } - // Create arrays for quorum types and lookahead periods - StakeType[] memory quorumStakeTypes = new StakeType[](numQuorumsToAdd); - uint32[] memory slashableStakeQuorumLookAheadPeriods = new uint32[](numQuorumsToAdd); + cheats.stopPrank(); - // Set all quorums to TOTAL_DELEGATED type with 0 lookahead period + // add TOTAL_DELEGATED stake type quorums for (uint256 i = 0; i < numQuorumsToAdd; i++) { - quorumStakeTypes[i] = StakeType.TOTAL_DELEGATED; - slashableStakeQuorumLookAheadPeriods[i] = 0; + cheats.prank(registryCoordinator.owner()); + registryCoordinator.createTotalDelegatedStakeQuorum( + operatorSetParams[i], + minimumStakeForQuorum[i], + quorumStrategiesConsideredAndMultipliers[i] + ); } - proxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(registryCoordinator))), - address(registryCoordinatorImplementation), - abi.encodeCall( - RegistryCoordinator.initialize, - ( - registryCoordinatorOwner, // _initialOwner - churnApprover, // _churnApprover - ejector, // _ejector - 0, // _initialPausedStatus - operatorSetParams, // _operatorSetParams - minimumStakeForQuorum, // _minimumStakes - quorumStrategiesConsideredAndMultipliers, // _strategyParams - quorumStakeTypes, // _stakeTypes - slashableStakeQuorumLookAheadPeriods // _lookAheadPeriods - ) - ) - ); } operatorStateRetriever = new OperatorStateRetriever(); - cheats.stopPrank(); + registryCoordinator.setOperatorSetsEnabled(false); + registryCoordinator.setM2QuorumsDisabled(false); } function _labelContracts() internal { @@ -510,7 +508,7 @@ contract MockAVSDeployer is Test { function _signOperatorChurnApproval( address registeringOperator, bytes32 registeringOperatorId, - IRegistryCoordinator.OperatorKickParam[] memory operatorKickParams, + ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams, bytes32 salt, uint256 expiry ) internal view returns (ISignatureUtils.SignatureWithSaltAndExpiry memory) { From 495413949382fd3a0c0a8096558614cba4ad03ee Mon Sep 17 00:00:00 2001 From: Michael Sun <35479365+8sunyuan@users.noreply.github.com> Date: Mon, 27 Jan 2025 18:12:16 -0500 Subject: [PATCH 47/52] fix: commented out view (#373) --- src/unaudited/ECDSAServiceManagerBase.sol | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/unaudited/ECDSAServiceManagerBase.sol b/src/unaudited/ECDSAServiceManagerBase.sol index a2fa81b6..57a4067e 100644 --- a/src/unaudited/ECDSAServiceManagerBase.sol +++ b/src/unaudited/ECDSAServiceManagerBase.sol @@ -232,10 +232,8 @@ abstract contract ECDSAServiceManagerBase is IServiceManager, OwnableUpgradeable for (uint256 i; i < count; i++) { strategies[i] = quorum.strategies[i].strategy; } - uint256[] memory shares; - // TODO: Fix - // = IDelegationManager(delegationManager) - // .getOperatorShares(_operator, strategies); + uint256[] memory shares = + IDelegationManager(delegationManager).getOperatorShares(_operator, strategies); uint256 activeCount; for (uint256 i; i < count; i++) { From 558613b2a94326bf69528f58b3db2c3e660f8f7c Mon Sep 17 00:00:00 2001 From: "clandestine.eth" <96172957+0xClandestine@users.noreply.github.com> Date: Mon, 27 Jan 2025 18:13:14 -0500 Subject: [PATCH 48/52] refactor: natspec + interface changes (#364) * refactor: natspec + interfaces refactor: natspec + interfaces refactor: natspec + interfaces docs: `RegistryCoordinator` natspec chore: forge fmt refactor: named mapping params docs: natspec `BLSApkRegistry` docs: natspec `BLSApkRegistry` docs: natspec `BLSApkRegistry` refactor: interface structure refactor: separate `BLSSignatureChecker` storage refactor: rename -> `IECDSAStakeRegistry` docs: natspec docs: natspec `ECDSAStakeRegistry` docs: natspec `EjectionManager` + separate storage docs: natspec docs: natspec `IndexRegistry` refactor: remove `IRegistry` chore: forge fmt chore: make storage-report docs: natspec refactor: remove `ISocketUpdater` refactor: use refactor: remove todo refactor: `///` -> `/**` refactor: improve comment refactor: rename var refactor: improve comment * fix: compiling - tests failing * refactor: test passing **mostly** * refactor: add missing gap * refactor: natspec * fix: test - state changes moved out of internal * chore: forge fmt * refactor: reorganize errors * refactor: remove override * refactor: note avsd * Yash/natspec - address comments (#372) * feat: natpsec with inheritance * feat: storage * chore: format * chore: fmt * chore: format * fix: test * fix: test --------- Co-authored-by: Michael Sun Co-authored-by: Yash Patil <40046473+ypatil12@users.noreply.github.com> --- .github/bin/storage-report.sh | 2 +- bin/storage-report.sh | 2 +- docs/RegistryCoordinator.md | 6 +- .../BLSSignatureCheckerStorage.md | 0 .../storage-report/ECDSAServiceManagerBase.md | 19 - docs/storage-report/ECDSAStakeRegistry.md | 37 - .../ECDSAStakeRegistryEqualWeight.md | 39 - .../ECDSAStakeRegistryPermissioned.md | 39 - .../ECDSAStakeRegistryStorage.md | 27 - docs/storage-report/EjectionManagerStorage.md | 0 .../RegistryCoordinatorStorage.md | 62 +- docs/storage-report/ServiceManagerRouter.md | 6 - foundry.toml | 2 +- src/BLSApkRegistry.sol | 73 +- src/BLSApkRegistryStorage.sol | 33 +- src/BLSSignatureChecker.sol | 84 +- src/BLSSignatureCheckerStorage.sol | 38 + src/EjectionManager.sol | 119 +-- src/EjectionManagerStorage.sol | 34 + src/IndexRegistry.sol | 113 +-- src/RegistryCoordinator.sol | 25 +- src/SlashingRegistryCoordinator.sol | 42 +- src/SlashingRegistryCoordinatorStorage.sol | 2 +- src/StakeRegistry.sol | 169 +--- src/StakeRegistryStorage.sol | 8 +- src/interfaces/IBLSApkRegistry.sol | 299 ++++--- src/interfaces/IBLSSignatureChecker.sol | 166 +++- src/interfaces/IECDSAStakeRegistry.sol | 305 +++++++ .../IECDSAStakeRegistryEventsAndErrors.sol | 105 --- src/interfaces/IEjectionManager.sol | 152 +++- src/interfaces/IIndexRegistry.sol | 167 ++-- src/interfaces/IRegistry.sol | 13 - src/interfaces/IRegistryCoordinator.sol | 110 ++- src/interfaces/IServiceManager.sol | 88 +- src/interfaces/IServiceManagerUI.sol | 30 +- src/interfaces/ISlasher.sol | 88 +- .../ISlashingRegistryCoordinator.sol | 601 +++++++++++--- src/interfaces/ISocketUpdater.sol | 22 - src/interfaces/IStakeRegistry.sol | 381 ++++++--- src/libraries/BN254.sol | 20 +- src/libraries/QuorumBitmapHistoryLib.sol | 9 +- src/unaudited/ECDSAServiceManagerBase.sol | 6 +- src/unaudited/ECDSAStakeRegistry.sol | 453 +++++----- src/unaudited/ECDSAStakeRegistryStorage.sol | 12 +- test/ffi/BLSPubKeyCompendiumFFI.t.sol | 4 +- test/ffi/UpdateOperators.t.sol | 4 +- .../RegistryCoordinatorHarness.t.sol | 8 +- test/harnesses/StakeRegistryHarness.sol | 3 +- test/integration/CoreRegistration.t.sol | 2 +- test/integration/IntegrationBase.t.sol | 28 +- test/integration/IntegrationConfig.t.sol | 46 +- test/integration/IntegrationDeployer.t.sol | 32 +- test/integration/User.t.sol | 21 +- test/mocks/AVSRegistrarMock.sol | 1 - test/mocks/DelegationMock.sol | 2 +- test/mocks/ECDSAServiceManagerMock.sol | 5 +- test/mocks/RegistryCoordinatorMock.sol | 208 +++-- test/mocks/StakeRegistryMock.sol | 13 + test/unit/BLSApkRegistryUnit.t.sol | 8 +- test/unit/BLSSignatureCheckerUnit.t.sol | 13 +- test/unit/BitmapUtils.t.sol | 2 +- test/unit/ECDSAServiceManager.t.sol | 4 +- .../ECDSAStakeRegistryEqualWeightUnit.t.sol | 12 +- .../ECDSAStakeRegistryPermissionedUnit.t.sol | 17 +- test/unit/ECDSAStakeRegistryUnit.t.sol | 103 ++- test/unit/EjectionManagerUnit.t.sol | 146 +++- test/unit/IndexRegistryUnit.t.sol | 2 +- test/unit/OperatorStateRetrieverUnit.t.sol | 32 +- test/unit/RegistryCoordinatorUnit.t.sol | 773 +++++++++++------- test/unit/ServiceManagerBase.t.sol | 2 +- .../SlashingRegistryCoordinatorUnit.t.sol | 143 ++-- test/unit/StakeRegistryUnit.t.sol | 126 +-- test/utils/BLSMockAVSDeployer.sol | 16 +- test/utils/MockAVSDeployer.sol | 34 +- 74 files changed, 3421 insertions(+), 2397 deletions(-) create mode 100644 docs/storage-report/BLSSignatureCheckerStorage.md create mode 100644 docs/storage-report/EjectionManagerStorage.md create mode 100644 src/BLSSignatureCheckerStorage.sol create mode 100644 src/EjectionManagerStorage.sol create mode 100644 src/interfaces/IECDSAStakeRegistry.sol delete mode 100644 src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol delete mode 100644 src/interfaces/IRegistry.sol delete mode 100644 src/interfaces/ISocketUpdater.sol diff --git a/.github/bin/storage-report.sh b/.github/bin/storage-report.sh index 71fbd9a0..4c34d5ac 100644 --- a/.github/bin/storage-report.sh +++ b/.github/bin/storage-report.sh @@ -37,7 +37,7 @@ for file in $(find src/ -name "*.sol" ! -path "*/interfaces/*" ! -path "*/librar log "Processing contract: $contract_name" # Run forge inspect and capture errors - if ! forge inspect "$contract_name" storage --pretty > "$OUTPUT_DIR/$contract_name.md"; then + if ! forge inspect "$contract_name" storage > "$OUTPUT_DIR/$contract_name.md"; then error "Failed to generate storage report for contract: $contract_name" else log "Storage report generated for contract: $contract_name" diff --git a/bin/storage-report.sh b/bin/storage-report.sh index 71fbd9a0..4c34d5ac 100644 --- a/bin/storage-report.sh +++ b/bin/storage-report.sh @@ -37,7 +37,7 @@ for file in $(find src/ -name "*.sol" ! -path "*/interfaces/*" ! -path "*/librar log "Processing contract: $contract_name" # Run forge inspect and capture errors - if ! forge inspect "$contract_name" storage --pretty > "$OUTPUT_DIR/$contract_name.md"; then + if ! forge inspect "$contract_name" storage > "$OUTPUT_DIR/$contract_name.md"; then error "Failed to generate storage report for contract: $contract_name" else log "Storage report generated for contract: $contract_name" diff --git a/docs/RegistryCoordinator.md b/docs/RegistryCoordinator.md index 1f917638..4752c7f7 100644 --- a/docs/RegistryCoordinator.md +++ b/docs/RegistryCoordinator.md @@ -42,7 +42,7 @@ These methods allow operators to register for/deregister from one or more quorum function registerOperator( bytes calldata quorumNumbers, string calldata socket, - IBLSApkRegistry.PubkeyRegistrationParams calldata params, + IBLSApkRegistryTypes.PubkeyRegistrationParams calldata params, SignatureWithSaltAndExpiry memory operatorSignature ) external @@ -88,7 +88,7 @@ If the Operator was not currently registered for any quorums, this method will r function registerOperatorWithChurn( bytes calldata quorumNumbers, string calldata socket, - IBLSApkRegistry.PubkeyRegistrationParams calldata params, + IBLSApkRegistryTypes.PubkeyRegistrationParams calldata params, OperatorKickParam[] calldata operatorKickParams, SignatureWithSaltAndExpiry memory churnApproverSignature, SignatureWithSaltAndExpiry memory operatorSignature @@ -256,7 +256,7 @@ These methods are used by the Owner to configure the `RegistryCoordinator`: function createQuorum( OperatorSetParam memory operatorSetParams, uint96 minimumStake, - IStakeRegistry.StrategyParams[] memory strategyParams + IStakeRegistryTypes.StrategyParams[] memory strategyParams ) external virtual diff --git a/docs/storage-report/BLSSignatureCheckerStorage.md b/docs/storage-report/BLSSignatureCheckerStorage.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/storage-report/ECDSAServiceManagerBase.md b/docs/storage-report/ECDSAServiceManagerBase.md index 2251f673..e69de29b 100644 --- a/docs/storage-report/ECDSAServiceManagerBase.md +++ b/docs/storage-report/ECDSAServiceManagerBase.md @@ -1,19 +0,0 @@ - -╭------------------+-------------+------+--------+-------+-------------------------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+============================================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/unaudited/ECDSAServiceManagerBase.sol:ECDSAServiceManagerBase | -|------------------+-------------+------+--------+-------+-------------------------------------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/unaudited/ECDSAServiceManagerBase.sol:ECDSAServiceManagerBase | -|------------------+-------------+------+--------+-------+-------------------------------------------------------------------| -| __gap | uint256[50] | 1 | 0 | 1600 | src/unaudited/ECDSAServiceManagerBase.sol:ECDSAServiceManagerBase | -|------------------+-------------+------+--------+-------+-------------------------------------------------------------------| -| _owner | address | 51 | 0 | 20 | src/unaudited/ECDSAServiceManagerBase.sol:ECDSAServiceManagerBase | -|------------------+-------------+------+--------+-------+-------------------------------------------------------------------| -| __gap | uint256[49] | 52 | 0 | 1568 | src/unaudited/ECDSAServiceManagerBase.sol:ECDSAServiceManagerBase | -|------------------+-------------+------+--------+-------+-------------------------------------------------------------------| -| rewardsInitiator | address | 101 | 0 | 20 | src/unaudited/ECDSAServiceManagerBase.sol:ECDSAServiceManagerBase | -|------------------+-------------+------+--------+-------+-------------------------------------------------------------------| -| __GAP | uint256[49] | 102 | 0 | 1568 | src/unaudited/ECDSAServiceManagerBase.sol:ECDSAServiceManagerBase | -╰------------------+-------------+------+--------+-------+-------------------------------------------------------------------╯ - diff --git a/docs/storage-report/ECDSAStakeRegistry.md b/docs/storage-report/ECDSAStakeRegistry.md index df768c27..e69de29b 100644 --- a/docs/storage-report/ECDSAStakeRegistry.md +++ b/docs/storage-report/ECDSAStakeRegistry.md @@ -1,37 +0,0 @@ - -╭----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+==========================================================================================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| __gap | uint256[50] | 1 | 0 | 1600 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| _owner | address | 51 | 0 | 20 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| __gap | uint256[49] | 52 | 0 | 1568 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| _totalOperators | uint256 | 101 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| _quorum | struct Quorum | 102 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| _minimumWeight | uint256 | 103 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| _serviceManager | address | 104 | 0 | 20 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| _stakeExpiry | uint256 | 105 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| _operatorSigningKeyHistory | mapping(address => struct CheckpointsUpgradeable.History) | 106 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| _totalWeightHistory | struct CheckpointsUpgradeable.History | 107 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| _thresholdWeightHistory | struct CheckpointsUpgradeable.History | 108 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| _operatorWeightHistory | mapping(address => struct CheckpointsUpgradeable.History) | 109 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| _operatorRegistered | mapping(address => bool) | 110 | 0 | 32 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -|----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------| -| __gap | uint256[40] | 111 | 0 | 1280 | src/unaudited/ECDSAStakeRegistry.sol:ECDSAStakeRegistry | -╰----------------------------+-----------------------------------------------------------+------+--------+-------+---------------------------------------------------------╯ - diff --git a/docs/storage-report/ECDSAStakeRegistryEqualWeight.md b/docs/storage-report/ECDSAStakeRegistryEqualWeight.md index e1e1c166..e69de29b 100644 --- a/docs/storage-report/ECDSAStakeRegistryEqualWeight.md +++ b/docs/storage-report/ECDSAStakeRegistryEqualWeight.md @@ -1,39 +0,0 @@ - -╭----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+=========================================================================================================================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| __gap | uint256[50] | 1 | 0 | 1600 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| _owner | address | 51 | 0 | 20 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| __gap | uint256[49] | 52 | 0 | 1568 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| _totalOperators | uint256 | 101 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| _quorum | struct Quorum | 102 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| _minimumWeight | uint256 | 103 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| _serviceManager | address | 104 | 0 | 20 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| _stakeExpiry | uint256 | 105 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| _operatorSigningKeyHistory | mapping(address => struct CheckpointsUpgradeable.History) | 106 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| _totalWeightHistory | struct CheckpointsUpgradeable.History | 107 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| _thresholdWeightHistory | struct CheckpointsUpgradeable.History | 108 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| _operatorWeightHistory | mapping(address => struct CheckpointsUpgradeable.History) | 109 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| _operatorRegistered | mapping(address => bool) | 110 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| __gap | uint256[40] | 111 | 0 | 1280 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -|----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------| -| allowlistedOperators | mapping(address => bool) | 151 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol:ECDSAStakeRegistryEqualWeight | -╰----------------------------+-----------------------------------------------------------+------+--------+-------+----------------------------------------------------------------------------------------╯ - diff --git a/docs/storage-report/ECDSAStakeRegistryPermissioned.md b/docs/storage-report/ECDSAStakeRegistryPermissioned.md index bdc5b32e..e69de29b 100644 --- a/docs/storage-report/ECDSAStakeRegistryPermissioned.md +++ b/docs/storage-report/ECDSAStakeRegistryPermissioned.md @@ -1,39 +0,0 @@ - -╭----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+===========================================================================================================================================================================================================+ -| _initialized | uint8 | 0 | 0 | 1 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| _initializing | bool | 0 | 1 | 1 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| __gap | uint256[50] | 1 | 0 | 1600 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| _owner | address | 51 | 0 | 20 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| __gap | uint256[49] | 52 | 0 | 1568 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| _totalOperators | uint256 | 101 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| _quorum | struct Quorum | 102 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| _minimumWeight | uint256 | 103 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| _serviceManager | address | 104 | 0 | 20 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| _stakeExpiry | uint256 | 105 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| _operatorSigningKeyHistory | mapping(address => struct CheckpointsUpgradeable.History) | 106 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| _totalWeightHistory | struct CheckpointsUpgradeable.History | 107 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| _thresholdWeightHistory | struct CheckpointsUpgradeable.History | 108 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| _operatorWeightHistory | mapping(address => struct CheckpointsUpgradeable.History) | 109 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| _operatorRegistered | mapping(address => bool) | 110 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| __gap | uint256[40] | 111 | 0 | 1280 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -|----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------| -| allowlistedOperators | mapping(address => bool) | 151 | 0 | 32 | src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol:ECDSAStakeRegistryPermissioned | -╰----------------------------+-----------------------------------------------------------+------+--------+-------+------------------------------------------------------------------------------------------╯ - diff --git a/docs/storage-report/ECDSAStakeRegistryStorage.md b/docs/storage-report/ECDSAStakeRegistryStorage.md index 69ef3d05..e69de29b 100644 --- a/docs/storage-report/ECDSAStakeRegistryStorage.md +++ b/docs/storage-report/ECDSAStakeRegistryStorage.md @@ -1,27 +0,0 @@ - -╭----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+========================================================================================================================================================================================+ -| _totalOperators | uint256 | 0 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | -|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| -| _quorum | struct Quorum | 1 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | -|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| -| _minimumWeight | uint256 | 2 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | -|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| -| _serviceManager | address | 3 | 0 | 20 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | -|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| -| _stakeExpiry | uint256 | 4 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | -|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| -| _operatorSigningKeyHistory | mapping(address => struct CheckpointsUpgradeable.History) | 5 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | -|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| -| _totalWeightHistory | struct CheckpointsUpgradeable.History | 6 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | -|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| -| _thresholdWeightHistory | struct CheckpointsUpgradeable.History | 7 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | -|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| -| _operatorWeightHistory | mapping(address => struct CheckpointsUpgradeable.History) | 8 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | -|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| -| _operatorRegistered | mapping(address => bool) | 9 | 0 | 32 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | -|----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------| -| __gap | uint256[40] | 10 | 0 | 1280 | src/unaudited/ECDSAStakeRegistryStorage.sol:ECDSAStakeRegistryStorage | -╰----------------------------+-----------------------------------------------------------+------+--------+-------+-----------------------------------------------------------------------╯ - diff --git a/docs/storage-report/EjectionManagerStorage.md b/docs/storage-report/EjectionManagerStorage.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/storage-report/RegistryCoordinatorStorage.md b/docs/storage-report/RegistryCoordinatorStorage.md index 47e30da8..e28515ac 100644 --- a/docs/storage-report/RegistryCoordinatorStorage.md +++ b/docs/storage-report/RegistryCoordinatorStorage.md @@ -1,33 +1,33 @@ -╭-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+========================================================================================================================================================================================+ -| quorumCount | uint8 | 0 | 0 | 1 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | -|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| -| _quorumParams | mapping(uint8 => struct IRegistryCoordinator.OperatorSetParam) | 1 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | -|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| -| _operatorBitmapHistory | mapping(bytes32 => struct IRegistryCoordinator.QuorumBitmapUpdate[]) | 2 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | -|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| -| _operatorInfo | mapping(address => struct IRegistryCoordinator.OperatorInfo) | 3 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | -|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| -| isChurnApproverSaltUsed | mapping(bytes32 => bool) | 4 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | -|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| -| quorumUpdateBlockNumber | mapping(uint8 => uint256) | 5 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | -|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| -| registries | address[] | 6 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | -|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| -| churnApprover | address | 7 | 0 | 20 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | -|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| -| ejector | address | 8 | 0 | 20 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | -|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| -| lastEjectionTimestamp | mapping(address => uint256) | 9 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | -|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| -| ejectionCooldown | uint256 | 10 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | -|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| -| operatorSetsEnabled | bool | 11 | 0 | 1 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | -|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| -| isM2Quorum | mapping(uint8 => bool) | 12 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | -|-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| -| __GAP | uint256[37] | 13 | 0 | 1184 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | -╰-------------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------╯ +╭-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++=============================================================================================================================================================================================+ +| quorumCount | uint8 | 0 | 0 | 1 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| _quorumParams | mapping(uint8 => struct ISlashingRegistryCoordinatorTypes.OperatorSetParam) | 1 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| _operatorBitmapHistory | mapping(bytes32 => struct ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate[]) | 2 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| _operatorInfo | mapping(address => struct ISlashingRegistryCoordinatorTypes.OperatorInfo) | 3 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| isChurnApproverSaltUsed | mapping(bytes32 => bool) | 4 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| quorumUpdateBlockNumber | mapping(uint8 => uint256) | 5 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| registries | address[] | 6 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| churnApprover | address | 7 | 0 | 20 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| ejector | address | 8 | 0 | 20 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| lastEjectionTimestamp | mapping(address => uint256) | 9 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| ejectionCooldown | uint256 | 10 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| isOperatorSetAVS | bool | 11 | 0 | 1 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| isM2Quorum | mapping(uint8 => bool) | 12 | 0 | 32 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +|-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------| +| __GAP | uint256[37] | 13 | 0 | 1184 | src/RegistryCoordinatorStorage.sol:RegistryCoordinatorStorage | +╰-------------------------+---------------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------╯ diff --git a/docs/storage-report/ServiceManagerRouter.md b/docs/storage-report/ServiceManagerRouter.md index 1ec5dc07..e69de29b 100644 --- a/docs/storage-report/ServiceManagerRouter.md +++ b/docs/storage-report/ServiceManagerRouter.md @@ -1,6 +0,0 @@ - -╭------+------+------+--------+-------+----------╮ -| Name | Type | Slot | Offset | Bytes | Contract | -+================================================+ -╰------+------+------+--------+-------+----------╯ - diff --git a/foundry.toml b/foundry.toml index 7b02b1c8..ce96ecd1 100644 --- a/foundry.toml +++ b/foundry.toml @@ -74,7 +74,7 @@ # Quotation mark style quote_style = "double" # Options: "double", "single", "preserve" # Style of underscores in number literals - number_underscore = "thousands" # Options: "preserve", "thousands", "remove" + number_underscore = "remove" # Options: "preserve", "thousands", "remove" # Whether or not to wrap comments at line_length wrap_comments = false # List of files to ignore during formatting (can use glob patterns) diff --git a/src/BLSApkRegistry.sol b/src/BLSApkRegistry.sol index 65d125fb..831210ea 100644 --- a/src/BLSApkRegistry.sol +++ b/src/BLSApkRegistry.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {BLSApkRegistryStorage} from "./BLSApkRegistryStorage.sol"; +import {BLSApkRegistryStorage, IBLSApkRegistry} from "./BLSApkRegistryStorage.sol"; import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; @@ -27,17 +27,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage { * */ - /** - * @notice Registers the `operator`'s pubkey for the specified `quorumNumbers`. - * @param operator The address of the operator to register. - * @param quorumNumbers The quorum numbers the operator is registering for, where each byte is an 8 bit integer quorumNumber. - * @dev access restricted to the RegistryCoordinator - * @dev Preconditions (these are assumed, not validated in this contract): - * 1) `quorumNumbers` has no duplicates - * 2) `quorumNumbers.length` != 0 - * 3) `quorumNumbers` is ordered in ascending order - * 4) the operator is not already registered - */ + /// @inheritdoc IBLSApkRegistry function registerOperator( address operator, bytes memory quorumNumbers @@ -52,18 +42,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage { emit OperatorAddedToQuorums(operator, getOperatorId(operator), quorumNumbers); } - /** - * @notice Deregisters the `operator`'s pubkey for the specified `quorumNumbers`. - * @param operator The address of the operator to deregister. - * @param quorumNumbers The quorum numbers the operator is deregistering from, where each byte is an 8 bit integer quorumNumber. - * @dev access restricted to the RegistryCoordinator - * @dev Preconditions (these are assumed, not validated in this contract): - * 1) `quorumNumbers` has no duplicates - * 2) `quorumNumbers.length` != 0 - * 3) `quorumNumbers` is ordered in ascending order - * 4) the operator is not already deregistered - * 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for - */ + /// @inheritdoc IBLSApkRegistry function deregisterOperator( address operator, bytes memory quorumNumbers @@ -76,10 +55,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage { emit OperatorRemovedFromQuorums(operator, getOperatorId(operator), quorumNumbers); } - /** - * @notice Initializes a new quorum by pushing its first apk update - * @param quorumNumber The number of the new quorum - */ + /// @inheritdoc IBLSApkRegistry function initializeQuorum( uint8 quorumNumber ) public virtual onlyRegistryCoordinator { @@ -94,12 +70,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage { ); } - /** - * @notice Called by the RegistryCoordinator register an operator as the owner of a BLS public key. - * @param operator is the operator for whom the key is being registered - * @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership - * @param pubkeyRegistrationMessageHash is a hash that the operator must sign to prove key ownership - */ + /// @inheritdoc IBLSApkRegistry function registerBLSPublicKey( address operator, PubkeyRegistrationParams calldata params, @@ -107,7 +78,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage { ) external onlyRegistryCoordinator returns (bytes32 operatorId) { bytes32 pubkeyHash = BN254.hashG1Point(params.pubkeyG1); require(pubkeyHash != ZERO_PK_HASH, ZeroPubKey()); - require(operatorToPubkeyHash[operator] == bytes32(0), OperatorAlreadyRegistered()); + require(getOperatorId(operator) == bytes32(0), OperatorAlreadyRegistered()); require(pubkeyHashToOperator[pubkeyHash] == address(0), BLSPubkeyAlreadyRegistered()); // gamma = h(sigma, P, P', H(m)) @@ -190,25 +161,20 @@ contract BLSApkRegistry is BLSApkRegistryStorage { * VIEW FUNCTIONS * */ - /** - * @notice Returns the pubkey and pubkey hash of an operator - * @dev Reverts if the operator has not registered a valid pubkey - */ + + /// @inheritdoc IBLSApkRegistry function getRegisteredPubkey( address operator ) public view returns (BN254.G1Point memory, bytes32) { BN254.G1Point memory pubkey = operatorToPubkey[operator]; - bytes32 pubkeyHash = operatorToPubkeyHash[operator]; + bytes32 pubkeyHash = getOperatorId(operator); require(pubkeyHash != bytes32(0), OperatorNotRegistered()); return (pubkey, pubkeyHash); } - /** - * @notice Returns the indices of the quorumApks index at `blockNumber` for the provided `quorumNumbers` - * @dev Returns the current indices if `blockNumber >= block.number` - */ + /// @inheritdoc IBLSApkRegistry function getApkIndicesAtBlockNumber( bytes calldata quorumNumbers, uint256 blockNumber @@ -239,14 +205,14 @@ contract BLSApkRegistry is BLSApkRegistryStorage { return indices; } - /// @notice Returns the current APK for the provided `quorumNumber ` + /// @inheritdoc IBLSApkRegistry function getApk( uint8 quorumNumber ) external view returns (BN254.G1Point memory) { return currentApk[quorumNumber]; } - /// @notice Returns the `ApkUpdate` struct at `index` in the list of APK updates for the `quorumNumber` + /// @inheritdoc IBLSApkRegistry function getApkUpdateAtIndex( uint8 quorumNumber, uint256 index @@ -254,13 +220,7 @@ contract BLSApkRegistry is BLSApkRegistryStorage { return apkHistory[quorumNumber][index]; } - /** - * @notice get hash of the apk of `quorumNumber` at `blockNumber` using the provided `index`; - * called by checkSignatures in BLSSignatureChecker.sol. - * @param quorumNumber is the quorum whose ApkHash is being retrieved - * @param blockNumber is the number of the block for which the latest ApkHash will be retrieved - * @param index is the index of the apkUpdate being retrieved from the list of quorum apkUpdates in storage - */ + /// @inheritdoc IBLSApkRegistry function getApkHashAtBlockNumberAndIndex( uint8 quorumNumber, uint32 blockNumber, @@ -283,22 +243,21 @@ contract BLSApkRegistry is BLSApkRegistryStorage { return quorumApkUpdate.apkHash; } - /// @notice Returns the length of ApkUpdates for the provided `quorumNumber` + /// @inheritdoc IBLSApkRegistry function getApkHistoryLength( uint8 quorumNumber ) external view returns (uint32) { return uint32(apkHistory[quorumNumber].length); } - /// @notice Returns the operator address for the given `pubkeyHash` + /// @inheritdoc IBLSApkRegistry function getOperatorFromPubkeyHash( bytes32 pubkeyHash ) public view returns (address) { return pubkeyHashToOperator[pubkeyHash]; } - /// @notice returns the ID used to identify the `operator` within this AVS - /// @dev Returns zero in the event that the `operator` has never registered for the AVS + /// @inheritdoc IBLSApkRegistry function getOperatorId( address operator ) public view returns (bytes32) { diff --git a/src/BLSApkRegistryStorage.sol b/src/BLSApkRegistryStorage.sol index ffbd075d..2d07a1a9 100644 --- a/src/BLSApkRegistryStorage.sol +++ b/src/BLSApkRegistryStorage.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; +import {IBLSApkRegistry, IBLSApkRegistryTypes} from "./interfaces/IBLSApkRegistry.sol"; import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initializable.sol"; @@ -9,26 +9,28 @@ import {Initializable} from "@openzeppelin-upgrades/contracts/proxy/utils/Initia import {BN254} from "./libraries/BN254.sol"; abstract contract BLSApkRegistryStorage is Initializable, IBLSApkRegistry { - /// @notice the hash of the zero pubkey aka BN254.G1Point(0,0) + /// @dev Returns the hash of the zero pubkey aka BN254.G1Point(0,0) bytes32 internal constant ZERO_PK_HASH = hex"ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5"; - /// @notice the registry coordinator contract + /// @inheritdoc IBLSApkRegistry address public immutable registryCoordinator; - // storage for individual pubkeys - /// @notice maps operator address to pubkey hash - mapping(address => bytes32) public operatorToPubkeyHash; - /// @notice maps pubkey hash to operator address - mapping(bytes32 => address) public pubkeyHashToOperator; - /// @notice maps operator address to pubkeyG1 - mapping(address => BN254.G1Point) public operatorToPubkey; + /// INDIVIDUAL PUBLIC KEY STORAGE - // storage for aggregate pubkeys (APKs) - /// @notice maps quorumNumber => historical aggregate pubkey updates - mapping(uint8 => ApkUpdate[]) public apkHistory; - /// @notice maps quorumNumber => current aggregate pubkey of quorum - mapping(uint8 => BN254.G1Point) public currentApk; + /// @inheritdoc IBLSApkRegistry + mapping(address operator => bytes32 operatorId) public operatorToPubkeyHash; + /// @inheritdoc IBLSApkRegistry + mapping(bytes32 pubkeyHash => address operator) public pubkeyHashToOperator; + /// @inheritdoc IBLSApkRegistry + mapping(address operator => BN254.G1Point pubkeyG1) public operatorToPubkey; + + /// AGGREGATE PUBLIC KEY STORAGE + + /// @inheritdoc IBLSApkRegistry + mapping(uint8 quorumNumber => IBLSApkRegistryTypes.ApkUpdate[]) public apkHistory; + /// @inheritdoc IBLSApkRegistry + mapping(uint8 quorumNumber => BN254.G1Point) public currentApk; constructor( ISlashingRegistryCoordinator _slashingRegistryCoordinator @@ -38,6 +40,5 @@ abstract contract BLSApkRegistryStorage is Initializable, IBLSApkRegistry { _disableInitializers(); } - // storage gap for upgradeability uint256[45] private __GAP; } diff --git a/src/BLSSignatureChecker.sol b/src/BLSSignatureChecker.sol index aaaa094e..5743be64 100644 --- a/src/BLSSignatureChecker.sol +++ b/src/BLSSignatureChecker.sol @@ -1,91 +1,45 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IBLSSignatureChecker} from "./interfaces/IBLSSignatureChecker.sol"; -import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; -import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; -import {IStakeRegistry, IDelegationManager} from "./interfaces/IStakeRegistry.sol"; - import {BitmapUtils} from "./libraries/BitmapUtils.sol"; import {BN254} from "./libraries/BN254.sol"; +import "./BLSSignatureCheckerStorage.sol"; + /** * @title Used for checking BLS aggregate signatures from the operators of a `BLSRegistry`. * @author Layr Labs, Inc. * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service * @notice This is the contract for checking the validity of aggregate operator signatures. */ -contract BLSSignatureChecker is IBLSSignatureChecker { +contract BLSSignatureChecker is BLSSignatureCheckerStorage { using BN254 for BN254.G1Point; - // CONSTANTS & IMMUTABLES - - // gas cost of multiplying 2 pairings - uint256 internal constant PAIRING_EQUALITY_CHECK_GAS = 120_000; - - ISlashingRegistryCoordinator public immutable registryCoordinator; - IStakeRegistry public immutable stakeRegistry; - IBLSApkRegistry public immutable blsApkRegistry; - IDelegationManager public immutable delegation; - /// @notice If true, check the staleness of the operator stakes and that its within the delegation withdrawalDelayBlocks window. - bool public staleStakesForbidden; + /// MODIFIERS modifier onlyCoordinatorOwner() { require(msg.sender == registryCoordinator.owner(), OnlyRegistryCoordinatorOwner()); _; } + /// CONSTRUCTION + constructor( ISlashingRegistryCoordinator _registryCoordinator - ) { - registryCoordinator = _registryCoordinator; - stakeRegistry = _registryCoordinator.stakeRegistry(); - blsApkRegistry = _registryCoordinator.blsApkRegistry(); - delegation = stakeRegistry.delegation(); - } + ) BLSSignatureCheckerStorage(_registryCoordinator) {} + + /// ACTIONS - /** - * /** - * RegistryCoordinator owner can either enforce or not that operator stakes are staler - * than the delegation.minWithdrawalDelayBlocks() window. - * @param value to toggle staleStakesForbidden - */ + /// @inheritdoc IBLSSignatureChecker function setStaleStakesForbidden( bool value ) external onlyCoordinatorOwner { _setStaleStakesForbidden(value); } - struct NonSignerInfo { - uint256[] quorumBitmaps; - bytes32[] pubkeyHashes; - } + /// VIEW - /** - * @notice This function is called by disperser when it has aggregated all the signatures of the operators - * that are part of the quorum for a particular taskNumber and is asserting them into onchain. The function - * checks that the claim for aggregated signatures are valid. - * - * The thesis of this procedure entails: - * - getting the aggregated pubkey of all registered nodes at the time of pre-commit by the - * disperser (represented by apk in the parameters), - * - subtracting the pubkeys of all the signers not in the quorum (nonSignerPubkeys) and storing - * the output in apk to get aggregated pubkey of all operators that are part of quorum. - * - use this aggregated pubkey to verify the aggregated signature under BLS scheme. - * - * @dev Before signature verification, the function verifies operator stake information. This includes ensuring that the provided `referenceBlockNumber` - * 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 - * for the total stake (of the operator) or latest before the referenceBlockNumber. - * @param msgHash is the hash being signed - * @dev NOTE: Be careful to ensure `msgHash` is collision-resistant! This method does not hash - * `msgHash` in any way, so if an attacker is able to pass in an arbitrary value, they may be able - * to tamper with signature verification. - * @param quorumNumbers is the bytes array of quorum numbers that are being signed for - * @param referenceBlockNumber is the block number at which the stake information is being verified - * @param params is the struct containing information on nonsigners, stakes, quorum apks, and the aggregate signature - * @return quorumStakeTotals is the struct containing the total and signed stake for each quorum - * @return signatoryRecordHash is the hash of the signatory record, which is used for fraud proofs - */ + /// @inheritdoc IBLSSignatureChecker function checkSignatures( bytes32 msgHash, bytes calldata quorumNumbers, @@ -253,15 +207,7 @@ contract BLSSignatureChecker is IBLSSignatureChecker { return (stakeTotals, signatoryRecordHash); } - /** - * trySignatureAndApkVerification verifies a BLS aggregate signature and the veracity of a calculated G1 Public key - * @param msgHash is the hash being signed - * @param apk is the claimed G1 public key - * @param apkG2 is provided G2 public key - * @param sigma is the G1 point signature - * @return pairingSuccessful is true if the pairing precompile call was successful - * @return siganatureIsValid is true if the signature is valid - */ + /// @inheritdoc IBLSSignatureChecker function trySignatureAndApkVerification( bytes32 msgHash, BN254.G1Point memory apk, @@ -300,8 +246,4 @@ contract BLSSignatureChecker is IBLSSignatureChecker { staleStakesForbidden = value; emit StaleStakesForbiddenUpdate(value); } - - // storage gap for upgradeability - // slither-disable-next-line shadowing-state - uint256[49] private __GAP; } diff --git a/src/BLSSignatureCheckerStorage.sol b/src/BLSSignatureCheckerStorage.sol new file mode 100644 index 00000000..59bd073a --- /dev/null +++ b/src/BLSSignatureCheckerStorage.sol @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.27; + +import {IBLSSignatureChecker} from "./interfaces/IBLSSignatureChecker.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; +import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; +import {IStakeRegistry, IDelegationManager} from "./interfaces/IStakeRegistry.sol"; + +abstract contract BLSSignatureCheckerStorage is IBLSSignatureChecker { + /// @dev Returns the assumed gas cost of multiplying 2 pairings. + uint256 internal constant PAIRING_EQUALITY_CHECK_GAS = 120000; + + /// @inheritdoc IBLSSignatureChecker + ISlashingRegistryCoordinator public immutable registryCoordinator; + /// @inheritdoc IBLSSignatureChecker + IStakeRegistry public immutable stakeRegistry; + /// @inheritdoc IBLSSignatureChecker + IBLSApkRegistry public immutable blsApkRegistry; + /// @inheritdoc IBLSSignatureChecker + IDelegationManager public immutable delegation; + + /// STATE + + /// @inheritdoc IBLSSignatureChecker + bool public staleStakesForbidden; + + constructor( + ISlashingRegistryCoordinator _registryCoordinator + ) { + registryCoordinator = _registryCoordinator; + stakeRegistry = _registryCoordinator.stakeRegistry(); + blsApkRegistry = _registryCoordinator.blsApkRegistry(); + delegation = stakeRegistry.delegation(); + } + + // slither-disable-next-line shadowing-state + uint256[49] private __GAP; +} diff --git a/src/EjectionManager.sol b/src/EjectionManager.sol index 578a2222..c9078a81 100644 --- a/src/EjectionManager.sol +++ b/src/EjectionManager.sol @@ -2,46 +2,27 @@ pragma solidity ^0.8.27; import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; -import {IEjectionManager} from "./interfaces/IEjectionManager.sol"; -import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; -import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; +import { + EjectionManagerStorage, + IEjectionManager, + IRegistryCoordinator, + IStakeRegistry +} from "./EjectionManagerStorage.sol"; + +// TODO: double check order of inheritance since we separated storage from logic... /** * @title Used for automated ejection of operators from the RegistryCoordinator under a ratelimit * @author Layr Labs, Inc. */ -contract EjectionManager is IEjectionManager, OwnableUpgradeable { - /// @notice The basis point denominator for the ejectable stake percent - uint16 internal constant BIPS_DENOMINATOR = 10_000; - - /// @notice The max number of quorums - uint8 internal constant MAX_QUORUM_COUNT = 192; - - /// @notice the RegistryCoordinator contract that is the entry point for ejection - ISlashingRegistryCoordinator public immutable registryCoordinator; - /// @notice the StakeRegistry contract that keeps track of quorum stake - IStakeRegistry public immutable stakeRegistry; - - /// @notice Addresses permissioned to eject operators under a ratelimit - mapping(address => bool) public isEjector; - - /// @notice Keeps track of the total stake ejected for a quorum - mapping(uint8 => StakeEjection[]) public stakeEjectedForQuorum; - /// @notice Ratelimit parameters for each quorum - mapping(uint8 => QuorumEjectionParams) public quorumEjectionParams; - - constructor(ISlashingRegistryCoordinator _registryCoordinator, IStakeRegistry _stakeRegistry) { - registryCoordinator = _registryCoordinator; - stakeRegistry = _stakeRegistry; - +contract EjectionManager is OwnableUpgradeable, EjectionManagerStorage { + constructor( + IRegistryCoordinator _registryCoordinator, + IStakeRegistry _stakeRegistry + ) EjectionManagerStorage(_registryCoordinator, _stakeRegistry) { _disableInitializers(); } - /** - * @param _owner will hold the owner role - * @param _ejectors will hold the ejector role - * @param _quorumEjectionParams are the ratelimit parameters for the quorum at each index - */ function initialize( address _owner, address[] memory _ejectors, @@ -56,18 +37,13 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { } } - /** - * @notice Ejects operators from the AVSs RegistryCoordinator under a ratelimit - * @param _operatorIds The ids of the operators 'j' to eject for each quorum 'i' - * @dev This function will eject as many operators as possible prioritizing operators at the lower index - * @dev The owner can eject operators without recording of stake ejection - */ + /// @inheritdoc IEjectionManager function ejectOperators( - bytes32[][] memory _operatorIds + bytes32[][] memory operatorIds ) external { require(isEjector[msg.sender] || msg.sender == owner(), OnlyOwnerOrEjector()); - for (uint256 i = 0; i < _operatorIds.length; ++i) { + for (uint256 i = 0; i < operatorIds.length; ++i) { uint8 quorumNumber = uint8(i); uint256 amountEjectable = amountEjectableForQuorum(quorumNumber); @@ -75,9 +51,9 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { uint32 ejectedOperators; bool ratelimitHit; - for (uint8 j = 0; j < _operatorIds[i].length; ++j) { + for (uint8 j = 0; j < operatorIds[i].length; ++j) { uint256 operatorStake = - stakeRegistry.getCurrentStake(_operatorIds[i][j], quorumNumber); + stakeRegistry.getCurrentStake(operatorIds[i][j], quorumNumber); //if caller is ejector enforce ratelimit if ( @@ -95,11 +71,11 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { ++ejectedOperators; registryCoordinator.ejectOperator( - registryCoordinator.getOperatorFromId(_operatorIds[i][j]), + registryCoordinator.getOperatorFromId(operatorIds[i][j]), abi.encodePacked(quorumNumber) ); - emit OperatorEjected(_operatorIds[i][j], quorumNumber); + emit OperatorEjected(operatorIds[i][j], quorumNumber); } //record the stake ejected if ejector and ratelimit enforced @@ -113,67 +89,56 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable { } } - /** - * @notice Sets the ratelimit parameters for a quorum - * @param _quorumNumber The quorum number to set the ratelimit parameters for - * @param _quorumEjectionParams The quorum ratelimit parameters to set for the given quorum - */ + /// @inheritdoc IEjectionManager function setQuorumEjectionParams( - uint8 _quorumNumber, + uint8 quorumNumber, QuorumEjectionParams memory _quorumEjectionParams ) external onlyOwner { - _setQuorumEjectionParams(_quorumNumber, _quorumEjectionParams); + _setQuorumEjectionParams(quorumNumber, _quorumEjectionParams); } - /** - * @notice Sets the address permissioned to eject operators under a ratelimit - * @param _ejector The address to permission - * @param _status The status to set for the given address - */ - function setEjector(address _ejector, bool _status) external onlyOwner { - _setEjector(_ejector, _status); + /// @inheritdoc IEjectionManager + function setEjector(address ejector, bool status) external onlyOwner { + _setEjector(ejector, status); } ///@dev internal function to set the quorum ejection params function _setQuorumEjectionParams( - uint8 _quorumNumber, + uint8 quorumNumber, QuorumEjectionParams memory _quorumEjectionParams ) internal { - require(_quorumNumber < MAX_QUORUM_COUNT, MaxQuorumCount()); - quorumEjectionParams[_quorumNumber] = _quorumEjectionParams; + require(quorumNumber < MAX_QUORUM_COUNT, MaxQuorumCount()); + quorumEjectionParams[quorumNumber] = _quorumEjectionParams; emit QuorumEjectionParamsSet( - _quorumNumber, + quorumNumber, _quorumEjectionParams.rateLimitWindow, _quorumEjectionParams.ejectableStakePercent ); } ///@dev internal function to set the ejector - function _setEjector(address _ejector, bool _status) internal { - isEjector[_ejector] = _status; - emit EjectorUpdated(_ejector, _status); + function _setEjector(address ejector, bool status) internal { + isEjector[ejector] = status; + emit EjectorUpdated(ejector, status); } - /** - * @notice Returns the amount of stake that can be ejected for a quorum at the current block.timestamp - * @param _quorumNumber The quorum number to view ejectable stake for - */ + /// @inheritdoc IEjectionManager function amountEjectableForQuorum( - uint8 _quorumNumber + uint8 quorumNumber ) public view returns (uint256) { - uint256 totalEjectable = uint256(quorumEjectionParams[_quorumNumber].ejectableStakePercent) - * uint256(stakeRegistry.getCurrentTotalStake(_quorumNumber)) / uint256(BIPS_DENOMINATOR); + uint256 totalEjectable = uint256(quorumEjectionParams[quorumNumber].ejectableStakePercent) + * uint256(stakeRegistry.getCurrentTotalStake(quorumNumber)) / uint256(BIPS_DENOMINATOR); - if (stakeEjectedForQuorum[_quorumNumber].length == 0) { + if (stakeEjectedForQuorum[quorumNumber].length == 0) { return totalEjectable; } - uint256 cutoffTime = block.timestamp - quorumEjectionParams[_quorumNumber].rateLimitWindow; + uint256 cutoffTime = block.timestamp - quorumEjectionParams[quorumNumber].rateLimitWindow; uint256 totalEjected = 0; - uint256 i = stakeEjectedForQuorum[_quorumNumber].length - 1; + uint256 i = stakeEjectedForQuorum[quorumNumber].length - 1; - while (stakeEjectedForQuorum[_quorumNumber][i].timestamp > cutoffTime) { - totalEjected += stakeEjectedForQuorum[_quorumNumber][i].stakeEjected; + while (stakeEjectedForQuorum[quorumNumber][i].timestamp > cutoffTime) { + totalEjected += stakeEjectedForQuorum[quorumNumber][i].stakeEjected; if (i == 0) { break; } else { diff --git a/src/EjectionManagerStorage.sol b/src/EjectionManagerStorage.sol new file mode 100644 index 00000000..e8996cd6 --- /dev/null +++ b/src/EjectionManagerStorage.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; +import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; +import {IEjectionManager} from "./interfaces/IEjectionManager.sol"; + +abstract contract EjectionManagerStorage is IEjectionManager { + /// @notice The basis point denominator for the ejectable stake percent + uint16 internal constant BIPS_DENOMINATOR = 10000; + /// @notice The max number of quorums + uint8 internal constant MAX_QUORUM_COUNT = 192; + + /// @inheritdoc IEjectionManager + IRegistryCoordinator public immutable registryCoordinator; + /// @inheritdoc IEjectionManager + IStakeRegistry public immutable stakeRegistry; + + /// @inheritdoc IEjectionManager + mapping(address => bool) public isEjector; + /// @inheritdoc IEjectionManager + mapping(uint8 => StakeEjection[]) public stakeEjectedForQuorum; + /// @inheritdoc IEjectionManager + mapping(uint8 => QuorumEjectionParams) public quorumEjectionParams; + + constructor(IRegistryCoordinator _registryCoordinator, IStakeRegistry _stakeRegistry) { + registryCoordinator = _registryCoordinator; + stakeRegistry = _stakeRegistry; + } + + /// @dev This was missing before the slashing release, if your contract + /// was deployed pre-slashing, you should double check your storage layout. + uint256[47] private __gap; +} diff --git a/src/IndexRegistry.sol b/src/IndexRegistry.sol index ef9b0c49..032b1839 100644 --- a/src/IndexRegistry.sol +++ b/src/IndexRegistry.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IndexRegistryStorage} from "./IndexRegistryStorage.sol"; +import {IIndexRegistry, IndexRegistryStorage} from "./IndexRegistryStorage.sol"; import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; /** @@ -9,13 +9,11 @@ import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordi * @author Layr Labs, Inc. */ contract IndexRegistry is IndexRegistryStorage { - /// @notice when applied to a function, only allows the RegistryCoordinator to call it modifier onlyRegistryCoordinator() { _checkRegistryCoordinator(); _; } - /// @notice sets the (immutable) `registryCoordinator` address constructor( ISlashingRegistryCoordinator _slashingRegistryCoordinator ) IndexRegistryStorage(_slashingRegistryCoordinator) {} @@ -26,18 +24,7 @@ contract IndexRegistry is IndexRegistryStorage { * */ - /** - * @notice Registers the operator with the specified `operatorId` for the quorums specified by `quorumNumbers`. - * @param operatorId is the id of the operator that is being registered - * @param quorumNumbers is the quorum numbers the operator is registered for - * @return numOperatorsPerQuorum is a list of the number of operators (including the registering operator) in each of the quorums the operator is registered for - * @dev access restricted to the RegistryCoordinator - * @dev Preconditions (these are assumed, not validated in this contract): - * 1) `quorumNumbers` has no duplicates - * 2) `quorumNumbers.length` != 0 - * 3) `quorumNumbers` is ordered in ascending order - * 4) the operator is not already registered - */ + /// @inheritdoc IIndexRegistry function registerOperator( bytes32 operatorId, bytes calldata quorumNumbers @@ -68,18 +55,7 @@ contract IndexRegistry is IndexRegistryStorage { return numOperatorsPerQuorum; } - /** - * @notice Deregisters the operator with the specified `operatorId` for the quorums specified by `quorumNumbers`. - * @param operatorId is the id of the operator that is being deregistered - * @param quorumNumbers is the quorum numbers the operator is deregistered for - * @dev access restricted to the RegistryCoordinator - * @dev Preconditions (these are assumed, not validated in this contract): - * 1) `quorumNumbers` has no duplicates - * 2) `quorumNumbers.length` != 0 - * 3) `quorumNumbers` is ordered in ascending order - * 4) the operator is not already deregistered - * 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for - */ + /// @inheritdoc IIndexRegistry function deregisterOperator( bytes32 operatorId, bytes calldata quorumNumbers @@ -109,10 +85,7 @@ contract IndexRegistry is IndexRegistryStorage { } } - /** - * @notice Initialize a quorum by pushing its first quorum update - * @param quorumNumber The number of the new quorum - */ + /// @inheritdoc IIndexRegistry function initializeQuorum( uint8 quorumNumber ) public virtual onlyRegistryCoordinator { @@ -129,9 +102,7 @@ contract IndexRegistry is IndexRegistryStorage { * */ - /** - * @notice Increases the historical operator count by 1 and returns the new count - */ + /// @notice Increases the historical operator count by 1 and returns the new count. function _increaseOperatorCount( uint8 quorumNumber ) internal returns (uint32) { @@ -154,9 +125,7 @@ contract IndexRegistry is IndexRegistryStorage { return newOperatorCount; } - /** - * @notice Decreases the historical operator count by 1 and returns the new count - */ + /// @notice Decreases the historical operator count by 1 and returns the new count. function _decreaseOperatorCount( uint8 quorumNumber ) internal returns (uint32) { @@ -168,11 +137,9 @@ contract IndexRegistry is IndexRegistryStorage { return newOperatorCount; } - /** - * @notice Update `_operatorCountHistory` with a new operator count - * @dev If the lastUpdate was made in the this block, update the entry. - * Otherwise, push a new historical entry. - */ + /// @notice Updates `_operatorCountHistory` with a new operator count. + /// @dev If the lastUpdate was made in this block, update the entry. + /// Otherwise, push a new historical entry. function _updateOperatorCountHistory( uint8 quorumNumber, QuorumUpdate storage lastUpdate, @@ -187,11 +154,9 @@ contract IndexRegistry is IndexRegistryStorage { } } - /** - * @notice For a given quorum and operatorIndex, pop and return the last operatorId in the history - * @dev The last entry's operatorId is updated to OPERATOR_DOES_NOT_EXIST_ID - * @return The removed operatorId - */ + /// @notice For a given quorum and operatorIndex, pop and return the last operatorId in the history. + /// @dev The last entry's operatorId is updated to OPERATOR_DOES_NOT_EXIST_ID. + /// @return The removed operatorId. function _popLastOperator( uint8 quorumNumber, uint32 operatorIndex @@ -207,12 +172,10 @@ contract IndexRegistry is IndexRegistryStorage { return removedOperatorId; } - /** - * @notice Assign an operator to an index and update the index history - * @param operatorId operatorId of the operator to update - * @param quorumNumber quorumNumber of the operator to update - * @param operatorIndex the latest index of that operator in the list of operators registered for this quorum - */ + /// @notice Assigns an operator to an index and updates the index history. + /// @param operatorId operatorId of the operator to update. + /// @param quorumNumber quorumNumber of the operator to update. + /// @param operatorIndex the latest index of that operator in the list of operators registered for this quorum. function _assignOperatorToIndex( bytes32 operatorId, uint8 quorumNumber, @@ -227,11 +190,9 @@ contract IndexRegistry is IndexRegistryStorage { emit QuorumIndexUpdate(operatorId, quorumNumber, operatorIndex); } - /** - * @notice Update `_operatorIndexHistory` with a new operator id for the current block - * @dev If the lastUpdate was made in the this block, update the entry. - * Otherwise, push a new historical entry. - */ + /// @notice Updates `_operatorIndexHistory` with a new operator id for the current block. + /// @dev If the lastUpdate was made in this block, update the entry. + /// Otherwise, push a new historical entry. function _updateOperatorIndexHistory( uint8 quorumNumber, uint32 operatorIndex, @@ -247,8 +208,8 @@ contract IndexRegistry is IndexRegistryStorage { } } - /// @notice Returns the most recent operator count update for a quorum - /// @dev Reverts if the quorum does not exist (history length == 0) + /// @notice Returns the most recent operator count update for a quorum. + /// @dev Reverts if the quorum does not exist (history length == 0). function _latestQuorumUpdate( uint8 quorumNumber ) internal view returns (QuorumUpdate storage) { @@ -256,8 +217,8 @@ contract IndexRegistry is IndexRegistryStorage { return _operatorCountHistory[quorumNumber][historyLength - 1]; } - /// @notice Returns the most recent operator id update for an index - /// @dev Reverts if the index has never been used (history length == 0) + /// @notice Returns the most recent operator id update for an index. + /// @dev Reverts if the index has never been used (history length == 0). function _latestOperatorIndexUpdate( uint8 quorumNumber, uint32 operatorIndex @@ -266,10 +227,8 @@ contract IndexRegistry is IndexRegistryStorage { return _operatorIndexHistory[quorumNumber][operatorIndex][historyLength - 1]; } - /** - * @notice Returns the total number of operators of the service for the given `quorumNumber` at the given `blockNumber` - * @dev Reverts if the quorum does not exist, or if the blockNumber is from before the quorum existed - */ + /// @notice Returns the total number of operators of the service for the given `quorumNumber` at the given `blockNumber`. + /// @dev Reverts if the quorum does not exist, or if the blockNumber is from before the quorum existed. function _operatorCountAtBlockNumber( uint8 quorumNumber, uint32 blockNumber @@ -290,10 +249,8 @@ contract IndexRegistry is IndexRegistryStorage { ); } - /** - * @return operatorId at the given `operatorIndex` at the given `blockNumber` for the given `quorumNumber` - * Precondition: requires that the operatorIndex was used active at the given block number for quorum - */ + /// @notice Returns the operatorId at the given `operatorIndex` at the given `blockNumber` for the given `quorumNumber`. + /// @dev Requires that the operatorIndex was active at the given block number for quorum. function _operatorIdForIndexAtBlockNumber( uint8 quorumNumber, uint32 operatorIndex, @@ -322,8 +279,7 @@ contract IndexRegistry is IndexRegistryStorage { * */ - /// @notice Returns the _operatorIndexHistory entry for the specified `operatorIndex` and `quorumNumber` - /// at the specified `arrayIndex` + /// @inheritdoc IIndexRegistry function getOperatorUpdateAtIndex( uint8 quorumNumber, uint32 operatorIndex, @@ -332,7 +288,7 @@ contract IndexRegistry is IndexRegistryStorage { return _operatorIndexHistory[quorumNumber][operatorIndex][arrayIndex]; } - /// @notice Returns the _operatorCountHistory entry for the specified `quorumNumber` at the specified `quorumIndex` + /// @inheritdoc IIndexRegistry function getQuorumUpdateAtIndex( uint8 quorumNumber, uint32 quorumIndex @@ -340,16 +296,14 @@ contract IndexRegistry is IndexRegistryStorage { return _operatorCountHistory[quorumNumber][quorumIndex]; } - /// @notice Returns the most recent QuorumUpdate entry for the specified quorumNumber - /// @dev Reverts if the quorum does not exist + /// @inheritdoc IIndexRegistry function getLatestQuorumUpdate( uint8 quorumNumber ) external view returns (QuorumUpdate memory) { return _latestQuorumUpdate(quorumNumber); } - /// @notice Returns the most recent OperatorUpdate entry for the specified quorumNumber and operatorIndex - /// @dev Reverts if there is no update for the given operatorIndex + /// @inheritdoc IIndexRegistry function getLatestOperatorUpdate( uint8 quorumNumber, uint32 operatorIndex @@ -357,7 +311,7 @@ contract IndexRegistry is IndexRegistryStorage { return _latestOperatorIndexUpdate(quorumNumber, operatorIndex); } - /// @notice Returns an ordered list of operators of the services for the given `quorumNumber` at the given `blockNumber` + /// @inheritdoc IIndexRegistry function getOperatorListAtBlockNumber( uint8 quorumNumber, uint32 blockNumber @@ -371,8 +325,7 @@ contract IndexRegistry is IndexRegistryStorage { return operatorList; } - /// @notice Returns the total number of operators for a given `quorumNumber` - /// @dev This will revert if the quorum does not exist + /// @inheritdoc IIndexRegistry function totalOperatorsForQuorum( uint8 quorumNumber ) external view returns (uint32) { diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 5dade2dd..590b8386 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.27; import {IPauserRegistry} from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; +import {IBLSApkRegistry, IBLSApkRegistryTypes} from "./interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry} from "./interfaces/IStakeRegistry.sol"; import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; import {IServiceManager} from "./interfaces/IServiceManager.sol"; @@ -12,6 +12,8 @@ import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; import {BitmapUtils} from "./libraries/BitmapUtils.sol"; import {SlashingRegistryCoordinator} from "./SlashingRegistryCoordinator.sol"; +import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; +import {OwnableUpgradeable} from "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol"; /** * @title A `RegistryCoordinator` that has three registries: @@ -21,7 +23,7 @@ import {SlashingRegistryCoordinator} from "./SlashingRegistryCoordinator.sol"; * * @author Layr Labs, Inc. */ -contract RegistryCoordinator is SlashingRegistryCoordinator, IRegistryCoordinator { +contract RegistryCoordinator is IRegistryCoordinator, SlashingRegistryCoordinator { using BitmapUtils for *; /// @notice the ServiceManager for this AVS, which forwards calls onto EigenLayer's core contracts @@ -56,7 +58,7 @@ contract RegistryCoordinator is SlashingRegistryCoordinator, IRegistryCoordinato function registerOperator( bytes memory quorumNumbers, string memory socket, - IBLSApkRegistry.PubkeyRegistrationParams memory params, + IBLSApkRegistryTypes.PubkeyRegistrationParams memory params, SignatureWithSaltAndExpiry memory operatorSignature ) external onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { require(!m2QuorumsDisabled, M2QuorumsAlreadyDisabled()); @@ -104,7 +106,7 @@ contract RegistryCoordinator is SlashingRegistryCoordinator, IRegistryCoordinato function registerOperatorWithChurn( bytes calldata quorumNumbers, string memory socket, - IBLSApkRegistry.PubkeyRegistrationParams memory params, + IBLSApkRegistryTypes.PubkeyRegistrationParams memory params, OperatorKickParam[] memory operatorKickParams, SignatureWithSaltAndExpiry memory churnApproverSignature, SignatureWithSaltAndExpiry memory operatorSignature @@ -143,12 +145,11 @@ contract RegistryCoordinator is SlashingRegistryCoordinator, IRegistryCoordinato /// @inheritdoc IRegistryCoordinator function deregisterOperator( bytes memory quorumNumbers - ) external onlyWhenNotPaused(PAUSED_DEREGISTER_OPERATOR) { + ) external override onlyWhenNotPaused(PAUSED_DEREGISTER_OPERATOR) { // Check that the quorum numbers are M2 quorums for (uint256 i = 0; i < quorumNumbers.length; i++) { require( - !operatorSetsEnabled || _isM2Quorum(uint8(quorumNumbers[i])), - OperatorSetsAlreadyEnabled() + !operatorSetsEnabled || _isM2Quorum(uint8(quorumNumbers[i])), OperatorSetQuorum() ); } _deregisterOperator({operator: msg.sender, quorumNumbers: quorumNumbers}); @@ -203,4 +204,14 @@ contract RegistryCoordinator is SlashingRegistryCoordinator, IRegistryCoordinato // This is a safe operation since we limit MAX_QUORUM_COUNT to 192 return (1 << quorumCount) - 1; } + + /// @dev need to override function here since its defined in both these contracts + function owner() + public + view + override(SlashingRegistryCoordinator, ISlashingRegistryCoordinator) + returns (address) + { + return OwnableUpgradeable.owner(); + } } diff --git a/src/SlashingRegistryCoordinator.sol b/src/SlashingRegistryCoordinator.sol index 605c4285..111a6d48 100644 --- a/src/SlashingRegistryCoordinator.sol +++ b/src/SlashingRegistryCoordinator.sol @@ -9,9 +9,9 @@ import { OperatorSet, IAllocationManagerTypes } from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -import {ISocketUpdater} from "./interfaces/ISocketUpdater.sol"; -import {IBLSApkRegistry} from "./interfaces/IBLSApkRegistry.sol"; -import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; + +import {IBLSApkRegistry, IBLSApkRegistryTypes} from "./interfaces/IBLSApkRegistry.sol"; +import {IStakeRegistry, IStakeRegistryTypes} from "./interfaces/IStakeRegistry.sol"; import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; @@ -26,7 +26,6 @@ import {EIP712} from "@openzeppelin/contracts/utils/cryptography/draft-EIP712.so import {Pausable} from "eigenlayer-contracts/src/contracts/permissions/Pausable.sol"; import {SlashingRegistryCoordinatorStorage} from "./SlashingRegistryCoordinatorStorage.sol"; -import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; /** * @title A `RegistryCoordinator` that has three registries: @@ -42,8 +41,6 @@ contract SlashingRegistryCoordinator is Pausable, OwnableUpgradeable, SlashingRegistryCoordinatorStorage, - IAVSRegistrar, - ISocketUpdater, ISignatureUtils { using BitmapUtils for *; @@ -130,15 +127,21 @@ contract SlashingRegistryCoordinator is function createTotalDelegatedStakeQuorum( OperatorSetParam memory operatorSetParams, uint96 minimumStake, - IStakeRegistry.StrategyParams[] memory strategyParams + IStakeRegistryTypes.StrategyParams[] memory strategyParams ) external virtual onlyOwner { - _createQuorum(operatorSetParams, minimumStake, strategyParams, StakeType.TOTAL_DELEGATED, 0); + _createQuorum( + operatorSetParams, + minimumStake, + strategyParams, + IStakeRegistryTypes.StakeType.TOTAL_DELEGATED, + 0 + ); } function createSlashableStakeQuorum( OperatorSetParam memory operatorSetParams, uint96 minimumStake, - IStakeRegistry.StrategyParams[] memory strategyParams, + IStakeRegistryTypes.StrategyParams[] memory strategyParams, uint32 lookAheadPeriod ) external virtual onlyOwner { require(operatorSetsEnabled, OperatorSetsNotEnabled()); @@ -146,7 +149,7 @@ contract SlashingRegistryCoordinator is operatorSetParams, minimumStake, strategyParams, - StakeType.TOTAL_SLASHABLE, + IStakeRegistryTypes.StakeType.TOTAL_SLASHABLE, lookAheadPeriod ); } @@ -162,8 +165,10 @@ contract SlashingRegistryCoordinator is ( RegistrationType registrationType, string memory socket, - IBLSApkRegistry.PubkeyRegistrationParams memory params - ) = abi.decode(data, (RegistrationType, string, IBLSApkRegistry.PubkeyRegistrationParams)); + IBLSApkRegistryTypes.PubkeyRegistrationParams memory params + ) = abi.decode( + data, (RegistrationType, string, IBLSApkRegistryTypes.PubkeyRegistrationParams) + ); /** * If the operator has NEVER registered a pubkey before, use `params` to register @@ -205,7 +210,7 @@ contract SlashingRegistryCoordinator is ( RegistrationType, string, - IBLSApkRegistry.PubkeyRegistrationParams, + IBLSApkRegistryTypes.PubkeyRegistrationParams, OperatorKickParam[], SignatureWithSaltAndExpiry ) @@ -666,7 +671,7 @@ contract SlashingRegistryCoordinator is */ function _getOrCreateOperatorId( address operator, - IBLSApkRegistry.PubkeyRegistrationParams memory params + IBLSApkRegistryTypes.PubkeyRegistrationParams memory params ) internal returns (bytes32 operatorId) { operatorId = blsApkRegistry.getOperatorId(operator); if (operatorId == 0) { @@ -807,8 +812,8 @@ contract SlashingRegistryCoordinator is function _createQuorum( OperatorSetParam memory operatorSetParams, uint96 minimumStake, - IStakeRegistry.StrategyParams[] memory strategyParams, - StakeType stakeType, + IStakeRegistryTypes.StrategyParams[] memory strategyParams, + IStakeRegistryTypes.StakeType stakeType, uint32 lookAheadPeriod ) internal { // Increment the total quorum count. Fails if we're already at the max @@ -842,9 +847,9 @@ contract SlashingRegistryCoordinator is allocationManager.createOperatorSets({avs: accountIdentifier, params: createSetParams}); } // Initialize stake registry based on stake type - if (stakeType == StakeType.TOTAL_DELEGATED) { + if (stakeType == IStakeRegistryTypes.StakeType.TOTAL_DELEGATED) { stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); - } else if (stakeType == StakeType.TOTAL_SLASHABLE) { + } else if (stakeType == IStakeRegistryTypes.StakeType.TOTAL_SLASHABLE) { stakeRegistry.initializeSlashableStakeQuorum( quorumNumber, minimumStake, lookAheadPeriod, strategyParams ); @@ -1114,6 +1119,7 @@ contract SlashingRegistryCoordinator is function owner() public view + virtual override(OwnableUpgradeable, ISlashingRegistryCoordinator) returns (address) { diff --git a/src/SlashingRegistryCoordinatorStorage.sol b/src/SlashingRegistryCoordinatorStorage.sol index e8c9eb9b..421d1fbc 100644 --- a/src/SlashingRegistryCoordinatorStorage.sol +++ b/src/SlashingRegistryCoordinatorStorage.sol @@ -30,7 +30,7 @@ abstract contract SlashingRegistryCoordinatorStorage is ISlashingRegistryCoordin /// @notice The maximum value of a quorum bitmap uint256 internal constant MAX_QUORUM_BITMAP = type(uint192).max; /// @notice The basis point denominator - uint16 internal constant BIPS_DENOMINATOR = 10_000; + uint16 internal constant BIPS_DENOMINATOR = 10000; /// @notice Index for flag that pauses operator registration uint8 internal constant PAUSED_REGISTER_OPERATOR = 0; /// @notice Index for flag that pauses operator deregistration diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index a75625a0..4cf3a286 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -11,7 +11,7 @@ import {IAllocationManager} from import {StakeRegistryStorage, IStrategy} from "./StakeRegistryStorage.sol"; import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; -import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; +import {IStakeRegistry, IStakeRegistryTypes} from "./interfaces/IStakeRegistry.sol"; import {BitmapUtils} from "./libraries/BitmapUtils.sol"; @@ -64,19 +64,7 @@ contract StakeRegistry is StakeRegistryStorage { * */ - /** - * @notice Registers the `operator` with `operatorId` for the specified `quorumNumbers`. - * @param operator The address of the operator to register. - * @param operatorId The id of the operator to register. - * @param quorumNumbers The quorum numbers the operator is registering for, where each byte is an 8 bit integer quorumNumber. - * @return The operator's current stake for each quorum, and the total stake for each quorum - * @dev access restricted to the RegistryCoordinator - * @dev Preconditions (these are assumed, not validated in this contract): - * 1) `quorumNumbers` has no duplicates - * 2) `quorumNumbers.length` != 0 - * 3) `quorumNumbers` is ordered in ascending order - * 4) the operator is not already registered - */ + /// @inheritdoc IStakeRegistry function registerOperator( address operator, bytes32 operatorId, @@ -109,18 +97,7 @@ contract StakeRegistry is StakeRegistryStorage { return (currentStakes, totalStakes); } - /** - * @notice Deregisters the operator with `operatorId` for the specified `quorumNumbers`. - * @param operatorId The id of the operator to deregister. - * @param quorumNumbers The quorum numbers the operator is deregistering from, where each byte is an 8 bit integer quorumNumber. - * @dev access restricted to the RegistryCoordinator - * @dev Preconditions (these are assumed, not validated in this contract): - * 1) `quorumNumbers` has no duplicates - * 2) `quorumNumbers.length` != 0 - * 3) `quorumNumbers` is ordered in ascending order - * 4) the operator is not already deregistered - * 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for - */ + /// @inheritdoc IStakeRegistry function deregisterOperator( bytes32 operatorId, bytes calldata quorumNumbers @@ -145,15 +122,7 @@ contract StakeRegistry is StakeRegistryStorage { } } - /** - * @notice Called by the registry coordinator to update an operator's stake for one - * or more quorums. - * - * If the operator no longer has the minimum stake required for a quorum, they are - * added to the `quorumsToRemove`, which is returned to the registry coordinator - * @return A bitmap of quorums where the operator no longer meets the minimum stake - * and should be deregistered. - */ + /// @inheritdoc IStakeRegistry function updateOperatorStake( address operator, bytes32 operatorId, @@ -199,7 +168,7 @@ contract StakeRegistry is StakeRegistryStorage { return quorumsToRemove; } - /// @notice Initialize a new quorum and push its first history update + /// @inheritdoc IStakeRegistry function initializeDelegatedStakeQuorum( uint8 quorumNumber, uint96 minimumStake, @@ -208,7 +177,7 @@ contract StakeRegistry is StakeRegistryStorage { require(!_quorumExists(quorumNumber), QuorumAlreadyExists()); _addStrategyParams(quorumNumber, _strategyParams); _setMinimumStakeForQuorum(quorumNumber, minimumStake); - _setStakeType(quorumNumber, StakeType.TOTAL_DELEGATED); + _setStakeType(quorumNumber, IStakeRegistryTypes.StakeType.TOTAL_DELEGATED); _totalStakeHistory[quorumNumber].push( StakeUpdate({ @@ -219,7 +188,7 @@ contract StakeRegistry is StakeRegistryStorage { ); } - /// @notice Initialize a new quorum and push its first history update + /// @inheritdoc IStakeRegistry function initializeSlashableStakeQuorum( uint8 quorumNumber, uint96 minimumStake, @@ -229,7 +198,7 @@ contract StakeRegistry is StakeRegistryStorage { require(!_quorumExists(quorumNumber), QuorumAlreadyExists()); _addStrategyParams(quorumNumber, _strategyParams); _setMinimumStakeForQuorum(quorumNumber, minimumStake); - _setStakeType(quorumNumber, StakeType.TOTAL_SLASHABLE); + _setStakeType(quorumNumber, IStakeRegistryTypes.StakeType.TOTAL_SLASHABLE); _setLookAheadPeriod(quorumNumber, lookAheadPeriod); _totalStakeHistory[quorumNumber].push( @@ -241,6 +210,7 @@ contract StakeRegistry is StakeRegistryStorage { ); } + /// @inheritdoc IStakeRegistry function setMinimumStakeForQuorum( uint8 quorumNumber, uint96 minimumStake @@ -248,11 +218,7 @@ contract StakeRegistry is StakeRegistryStorage { _setMinimumStakeForQuorum(quorumNumber, minimumStake); } - /** - * @notice Sets the look ahead time for checking operator shares for a specific quorum - * @param quorumNumber The quorum number to set the look ahead period for - * @param _lookAheadBlocks The number of blocks to look ahead when checking shares - */ + /// @inheritdoc IStakeRegistry function setSlashableStakeLookahead( uint8 quorumNumber, uint32 _lookAheadBlocks @@ -260,12 +226,7 @@ contract StakeRegistry is StakeRegistryStorage { _setLookAheadPeriod(quorumNumber, _lookAheadBlocks); } - /** - * @notice Adds strategies and weights to the quorum - * @dev Checks to make sure that the *same* strategy cannot be added multiple times (checks against both against existing and new strategies). - * @dev This function has no check to make sure that the strategies for a single quorum have the same underlying asset. This is a concious choice, - * since a middleware may want, e.g., a stablecoin quorum that accepts USDC, USDT, DAI, etc. as underlying assets and trades them as "equivalent". - */ + /// @inheritdoc IStakeRegistry function addStrategies( uint8 quorumNumber, StrategyParams[] memory _strategyParams @@ -287,11 +248,7 @@ contract StakeRegistry is StakeRegistryStorage { } } - /** - * @notice Remove strategies and their associated weights from the quorum's considered strategies - * @dev higher indices should be *first* in the list of @param indicesToRemove, since otherwise - * the removal of lower index entries will cause a shift in the indices of the other strategies to remove - */ + /// @inheritdoc IStakeRegistry function removeStrategies( uint8 quorumNumber, uint256[] memory indicesToRemove @@ -329,12 +286,7 @@ contract StakeRegistry is StakeRegistryStorage { } } - /** - * @notice Modifies the weights of existing strategies for a specific quorum - * @param quorumNumber is the quorum number to which the strategies belong - * @param strategyIndices are the indices of the strategies to change - * @param newMultipliers are the new multipliers for the strategies - */ + /// @inheritdoc IStakeRegistry function modifyStrategyParams( uint8 quorumNumber, uint256[] calldata strategyIndices, @@ -585,7 +537,7 @@ contract StakeRegistry is StakeRegistryStorage { StrategyParams memory strategyAndMultiplier; uint256[] memory strategyShares; - if (stakeTypePerQuorum[quorumNumber] == StakeType.TOTAL_SLASHABLE) { + if (stakeTypePerQuorum[quorumNumber] == IStakeRegistryTypes.StakeType.TOTAL_SLASHABLE) { strategyShares = _getSlashableStakePerStrategy(quorumNumber, operator); for (uint256 i = 0; i < stratsLength; i++) { strategyAndMultiplier = strategyParams[quorumNumber][i]; @@ -630,13 +582,7 @@ contract StakeRegistry is StakeRegistryStorage { * */ - /** - * @notice Returns whether a quorum is an operator set quorum based on its stake type - * @dev A quorum is an operator set quorum if it has TOTAL_SLASHABLE stake type - * and is not an M2 quorum - * @param quorumNumber The quorum number to check - * @return True if the quorum is an operator set quorum - */ + /// @inheritdoc IStakeRegistry function isOperatorSetQuorum( uint8 quorumNumber ) public view returns (bool) { @@ -645,10 +591,7 @@ contract StakeRegistry is StakeRegistryStorage { return isOperatorSet && !isM2; } - /** - * @notice This function computes the total weight of the @param operator in the quorum @param quorumNumber. - * @dev reverts if the quorum does not exist - */ + /// @inheritdoc IStakeRegistry function weightOfOperatorForQuorum( uint8 quorumNumber, address operator @@ -657,14 +600,14 @@ contract StakeRegistry is StakeRegistryStorage { return stake; } - /// @notice Returns the length of the dynamic array stored in `strategyParams[quorumNumber]`. + /// @inheritdoc IStakeRegistry function strategyParamsLength( uint8 quorumNumber ) public view returns (uint256) { return strategyParams[quorumNumber].length; } - /// @notice Returns the strategy and weight multiplier for the `index`'th strategy in the quorum `quorumNumber` + /// @inheritdoc IStakeRegistry function strategyParamsByIndex( uint8 quorumNumber, uint256 index @@ -678,9 +621,7 @@ contract StakeRegistry is StakeRegistryStorage { * */ - /** - * @notice Returns the length of an operator's stake history for the given quorum - */ + /// @inheritdoc IStakeRegistry function getStakeHistoryLength( bytes32 operatorId, uint8 quorumNumber @@ -688,11 +629,7 @@ contract StakeRegistry is StakeRegistryStorage { return operatorStakeHistory[operatorId][quorumNumber].length; } - /** - * @notice Returns the entire `operatorStakeHistory[operatorId][quorumNumber]` array. - * @param operatorId The id of the operator of interest. - * @param quorumNumber The quorum number to get the stake for. - */ + /// @inheritdoc IStakeRegistry function getStakeHistory( bytes32 operatorId, uint8 quorumNumber @@ -700,10 +637,7 @@ contract StakeRegistry is StakeRegistryStorage { return operatorStakeHistory[operatorId][quorumNumber]; } - /** - * @notice Returns the most recent stake weight for the `operatorId` for quorum `quorumNumber` - * @dev Function returns weight of **0** in the event that the operator has no stake history - */ + /// @inheritdoc IStakeRegistry function getCurrentStake( bytes32 operatorId, uint8 quorumNumber @@ -712,10 +646,7 @@ contract StakeRegistry is StakeRegistryStorage { return operatorStakeUpdate.stake; } - /** - * @notice Returns the most recent stake weight for the `operatorId` for a certain quorum - * @dev Function returns an StakeUpdate struct with **every entry equal to 0** in the event that the operator has no stake history - */ + /// @inheritdoc IStakeRegistry function getLatestStakeUpdate( bytes32 operatorId, uint8 quorumNumber @@ -730,13 +661,7 @@ contract StakeRegistry is StakeRegistryStorage { } } - /** - * @notice Returns the `index`-th entry in the `operatorStakeHistory[operatorId][quorumNumber]` array. - * @param quorumNumber The quorum number to get the stake for. - * @param operatorId The id of the operator of interest. - * @param index Array index for lookup, within the dynamic array `operatorStakeHistory[operatorId][quorumNumber]`. - * @dev Function will revert if `index` is out-of-bounds. - */ + /// @inheritdoc IStakeRegistry function getStakeUpdateAtIndex( uint8 quorumNumber, bytes32 operatorId, @@ -745,7 +670,7 @@ contract StakeRegistry is StakeRegistryStorage { return operatorStakeHistory[operatorId][quorumNumber][index]; } - /// @notice Returns the stake of the operator for the provided `quorumNumber` at the given `blockNumber` + /// @inheritdoc IStakeRegistry function getStakeAtBlockNumber( bytes32 operatorId, uint8 quorumNumber, @@ -756,7 +681,7 @@ contract StakeRegistry is StakeRegistryStorage { )].stake; } - /// @notice Returns the indices of the operator stakes for the provided `quorumNumber` at the given `blockNumber` + /// @inheritdoc IStakeRegistry function getStakeUpdateIndexAtBlockNumber( bytes32 operatorId, uint8 quorumNumber, @@ -765,16 +690,7 @@ contract StakeRegistry is StakeRegistryStorage { return _getStakeUpdateIndexForOperatorAtBlockNumber(operatorId, quorumNumber, blockNumber); } - /** - * @notice Returns the stake weight corresponding to `operatorId` for quorum `quorumNumber`, at the - * `index`-th entry in the `operatorStakeHistory[operatorId][quorumNumber]` array if it was the operator's - * stake at `blockNumber`. Reverts otherwise. - * @param quorumNumber The quorum number to get the stake for. - * @param operatorId The id of the operator of interest. - * @param index Array index for lookup, within the dynamic array `operatorStakeHistory[operatorId][quorumNumber]`. - * @param blockNumber Block number to make sure the stake is from. - * @dev Function will revert if `index` is out-of-bounds. - */ + /// @inheritdoc IStakeRegistry function getStakeAtBlockNumberAndIndex( uint8 quorumNumber, uint32 blockNumber, @@ -793,30 +709,21 @@ contract StakeRegistry is StakeRegistryStorage { * */ - /** - * @notice Returns the length of the total stake history for the given quorum - */ + /// @inheritdoc IStakeRegistry function getTotalStakeHistoryLength( uint8 quorumNumber ) external view returns (uint256) { return _totalStakeHistory[quorumNumber].length; } - /** - * @notice Returns the stake weight from the latest entry in `_totalStakeHistory` for quorum `quorumNumber`. - * @dev Will revert if `_totalStakeHistory[quorumNumber]` is empty. - */ + /// @inheritdoc IStakeRegistry function getCurrentTotalStake( uint8 quorumNumber ) external view returns (uint96) { return _totalStakeHistory[quorumNumber][_totalStakeHistory[quorumNumber].length - 1].stake; } - /** - * @notice Returns the `index`-th entry in the dynamic array of total stake, `_totalStakeHistory` for quorum `quorumNumber`. - * @param quorumNumber The quorum number to get the stake for. - * @param index Array index for lookup, within the dynamic array `_totalStakeHistory[quorumNumber]`. - */ + /// @inheritdoc IStakeRegistry function getTotalStakeUpdateAtIndex( uint8 quorumNumber, uint256 index @@ -824,14 +731,7 @@ contract StakeRegistry is StakeRegistryStorage { return _totalStakeHistory[quorumNumber][index]; } - /** - * @notice Returns the total stake weight for quorum `quorumNumber`, at the `index`-th entry in the - * `_totalStakeHistory[quorumNumber]` array if it was the stake at `blockNumber`. Reverts otherwise. - * @param quorumNumber The quorum number to get the stake for. - * @param index Array index for lookup, within the dynamic array `_totalStakeHistory[quorumNumber]`. - * @param blockNumber Block number to make sure the stake is from. - * @dev Function will revert if `index` is out-of-bounds. - */ + /// @inheritdoc IStakeRegistry function getTotalStakeAtBlockNumberFromIndex( uint8 quorumNumber, uint32 blockNumber, @@ -842,12 +742,7 @@ contract StakeRegistry is StakeRegistryStorage { return totalStakeUpdate.stake; } - /** - * @notice Returns the indices of the total stakes for the provided `quorumNumbers` at the given `blockNumber` - * @param blockNumber Block number to retrieve the stake indices from. - * @param quorumNumbers The quorum numbers to get the stake indices for. - * @dev Function will revert if there are no indices for the given `blockNumber` - */ + /// @inheritdoc IStakeRegistry function getTotalStakeIndicesAtBlockNumber( uint32 blockNumber, bytes calldata quorumNumbers @@ -879,7 +774,7 @@ contract StakeRegistry is StakeRegistryStorage { * @param quorumNumber The quorum number to set the stake type for * @param _stakeType The type of stake to track (TOTAL_DELEGATED, TOTAL_SLASHABLE, or BOTH) */ - function _setStakeType(uint8 quorumNumber, StakeType _stakeType) internal { + function _setStakeType(uint8 quorumNumber, IStakeRegistryTypes.StakeType _stakeType) internal { stakeTypePerQuorum[quorumNumber] = _stakeType; emit StakeTypeSet(_stakeType); } diff --git a/src/StakeRegistryStorage.sol b/src/StakeRegistryStorage.sol index e13835f3..2c00aec2 100644 --- a/src/StakeRegistryStorage.sol +++ b/src/StakeRegistryStorage.sol @@ -12,7 +12,7 @@ import { } from "eigenlayer-contracts/src/contracts/interfaces/IStrategyManager.sol"; import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; -import {IStakeRegistry, StakeType} from "./interfaces/IStakeRegistry.sol"; +import {IStakeRegistry, IStakeRegistryTypes} from "./interfaces/IStakeRegistry.sol"; /** * @title Storage variables for the `StakeRegistry` contract. @@ -25,7 +25,7 @@ abstract contract StakeRegistryStorage is IStakeRegistry { /// @notice Maximum length of dynamic arrays in the `strategyParams` mapping. uint8 public constant MAX_WEIGHING_FUNCTION_LENGTH = 32; /// @notice Constant used as a divisor in dealing with BIPS amounts. - uint256 internal constant MAX_BIPS = 10_000; + uint256 internal constant MAX_BIPS = 10000; /// @notice The address of the Delegation contract for EigenLayer. IDelegationManager public immutable delegation; @@ -58,8 +58,8 @@ abstract contract StakeRegistryStorage is IStakeRegistry { /// @notice mapping from quorum number to the list of strategies considered for that specific quorum mapping(uint8 quorumNumber => IStrategy[]) public strategiesPerQuorum; - /// @notice mapping from quorum number to the StakeType for that specific quorum - mapping(uint8 quorumNumber => StakeType) public stakeTypePerQuorum; + /// @notice mapping from quorum number to the IStakeRegistryTypes.StakeType for that specific quorum + mapping(uint8 quorumNumber => IStakeRegistryTypes.StakeType) public stakeTypePerQuorum; /// @notice mapping from quorum number to the slashable stake look ahead time (in blocks) mapping(uint8 quorumNumber => uint32) public slashableStakeLookAheadPerQuorum; diff --git a/src/interfaces/IBLSApkRegistry.sol b/src/interfaces/IBLSApkRegistry.sol index 0b1370b5..05a5c229 100644 --- a/src/interfaces/IBLSApkRegistry.sol +++ b/src/interfaces/IBLSApkRegistry.sol @@ -1,173 +1,245 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IRegistry} from "./IRegistry.sol"; - import {BN254} from "../libraries/BN254.sol"; interface IBLSApkRegistryErrors { - /// @dev Thrown when the caller is not the owner of the registry coordinator. + /// @notice Thrown when a non-RegistryCoordinator address calls a restricted function. error OnlyRegistryCoordinatorOwner(); - /// @dev Thrown when a quorum being created already exists. + /// @notice Thrown when attempting to initialize a quorum that already exists. error QuorumAlreadyExists(); - /// @dev Thrown when a quorum does not exist. + /// @notice Thrown when a quorum does not exist. error QuorumDoesNotExist(); - /// @dev Thrown when a BLS pubkey provided is zero pubkey + /// @notice Thrown when a BLS pubkey provided is zero pubkey error ZeroPubKey(); - /// @dev Thrown when an operator has already registered a BLS pubkey. + /// @notice Thrown when an operator has already registered a BLS pubkey. error OperatorAlreadyRegistered(); - /// @dev Thrown when the operator is not registered. + /// @notice Thrown when the operator is not registered. error OperatorNotRegistered(); - /// @dev Thrown when a BLS pubkey has already been registered for an operator. + /// @notice Thrown when a BLS pubkey has already been registered for an operator. error BLSPubkeyAlreadyRegistered(); - /// @dev Thrown when either the G1 signature is wrong, or G1 and G2 private key do not match. + /// @notice Thrown when either the G1 signature is wrong, or G1 and G2 private key do not match. error InvalidBLSSignatureOrPrivateKey(); - /// @dev Thrown when the quorum apk update block number is too recent. + /// @notice Thrown when the quorum apk update block number is too recent. error BlockNumberTooRecent(); - /// @dev Thrown when blocknumber and index provided is not the latest apk update. + /// @notice Thrown when blocknumber and index provided is not the latest apk update. error BlockNumberNotLatest(); } -/** - * @title Minimal interface for a registry that keeps track of aggregate operator public keys across many quorums. - * @author Layr Labs, Inc. - */ -interface IBLSApkRegistry is IRegistry, IBLSApkRegistryErrors { - // STRUCTS - /// @notice Data structure used to track the history of the Aggregate Public Key of all operators +interface IBLSApkRegistryTypes { + /// @notice Tracks the history of aggregate public key updates for a quorum. + /// @dev Each update contains a hash of the aggregate public key and block numbers for timing. + /// @param apkHash First 24 bytes of keccak256(apk_x0, apk_x1, apk_y0, apk_y1) representing the aggregate public key. + /// @param updateBlockNumber Block number when this update occurred (inclusive). + /// @param nextUpdateBlockNumber Block number when the next update occurred (exclusive), or 0 if this is the latest update. struct ApkUpdate { - // first 24 bytes of keccak256(apk_x0, apk_x1, apk_y0, apk_y1) bytes24 apkHash; - // block number at which the update occurred uint32 updateBlockNumber; - // block number at which the next update occurred uint32 nextUpdateBlockNumber; } - /** - * @notice Struct used when registering a new public key - * @param pubkeyRegistrationSignature is the registration message signed by the private key of the operator - * @param pubkeyG1 is the corresponding G1 public key of the operator - * @param pubkeyG2 is the corresponding G2 public key of the operator - */ + /// @notice Parameters required when registering a new BLS public key. + /// @dev Contains the registration signature and both G1/G2 public key components. + /// @param pubkeyRegistrationSignature Registration message signed by operator's private key to prove ownership. + /// @param pubkeyG1 The operator's public key in G1 group format. + /// @param pubkeyG2 The operator's public key in G2 group format, must correspond to the same private key as pubkeyG1. struct PubkeyRegistrationParams { BN254.G1Point pubkeyRegistrationSignature; BN254.G1Point pubkeyG1; BN254.G2Point pubkeyG2; } +} - // EVENTS - /// @notice Emitted when `operator` registers with the public keys `pubkeyG1` and `pubkeyG2`. +interface IBLSApkRegistryEvents is IBLSApkRegistryTypes { + /* + * @notice Emitted when `operator` registers their BLS public key pair (`pubkeyG1` and `pubkeyG2`). + * @param operator The address of the operator registering the keys. + * @param pubkeyG1 The operator's G1 public key. + * @param pubkeyG2 The operator's G2 public key. + */ event NewPubkeyRegistration( address indexed operator, BN254.G1Point pubkeyG1, BN254.G2Point pubkeyG2 ); - // @notice Emitted when a new operator pubkey is registered for a set of quorums + /* + * @notice Emitted when `operator`'s pubkey is registered for `quorumNumbers`. + * @param operator The address of the operator being registered. + * @param operatorId The unique identifier for this operator (pubkey hash). + * @param quorumNumbers The quorum numbers the operator is being registered for. + */ event OperatorAddedToQuorums(address operator, bytes32 operatorId, bytes quorumNumbers); - // @notice Emitted when an operator pubkey is removed from a set of quorums + /* + * @notice Emitted when `operator`'s pubkey is deregistered from `quorumNumbers`. + * @param operator The address of the operator being deregistered. + * @param operatorId The unique identifier for this operator (pubkey hash). + * @param quorumNumbers The quorum numbers the operator is being deregistered from. + */ event OperatorRemovedFromQuorums(address operator, bytes32 operatorId, bytes quorumNumbers); +} + +interface IBLSApkRegistry is IBLSApkRegistryErrors, IBLSApkRegistryEvents { + /* STORAGE */ + + /* + * @notice Returns the address of the registry coordinator contract. + * @return The address of the registry coordinator. + * @dev This value is immutable and set during contract construction. + */ + function registryCoordinator() external view returns (address); + + /* + * @notice Maps `operator` to their BLS public key hash (`operatorId`). + * @param operator The address of the operator. + * @return operatorId The hash of the operator's BLS public key. + */ + function operatorToPubkeyHash( + address operator + ) external view returns (bytes32 operatorId); + + /* + * @notice Maps `pubkeyHash` to their corresponding `operator` address. + * @param pubkeyHash The hash of a BLS public key. + * @return operator The address of the operator who registered this public key. + */ + function pubkeyHashToOperator( + bytes32 pubkeyHash + ) external view returns (address operator); + + /* + * @notice Maps `operator` to their BLS public key in G1. + * @dev Returns a non-encoded BN254.G1Point. + * @param operator The address of the operator. + * @return The operator's BLS public key in G1. + */ + function operatorToPubkey( + address operator + ) external view returns (uint256, uint256); - /** - * @notice Registers the `operator`'s pubkey for the specified `quorumNumbers`. + /* + * @notice Stores the history of aggregate public key updates for `quorumNumber` at `index`. + * @dev Returns a non-encoded IBLSApkRegistryTypes.ApkUpdate. + * @param quorumNumber The identifier of the quorum. + * @param index The index in the history array. + * @return The APK update entry at the specified index for the given quorum. + * @dev Each entry contains the APK hash, update block number, and next update block number. + */ + function apkHistory( + uint8 quorumNumber, + uint256 index + ) external view returns (bytes24, uint32, uint32); + + /* + * @notice Maps `quorumNumber` to their current aggregate public key. + * @dev Returns a non-encoded BN254.G1Point. + * @param quorumNumber The identifier of the quorum. + * @return The current APK as a G1 point. + */ + function currentApk( + uint8 quorumNumber + ) external view returns (uint256, uint256); + + /* ACTIONS */ + + /* + * @notice Registers `operator`'s pubkey for `quorumNumbers`. * @param operator The address of the operator to register. - * @param quorumNumbers The quorum numbers the operator is registering for, where each byte is an 8 bit integer quorumNumber. - * @dev access restricted to the RegistryCoordinator - * @dev Preconditions (these are assumed, not validated in this contract): - * 1) `quorumNumbers` has no duplicates - * 2) `quorumNumbers.length` != 0 - * 3) `quorumNumbers` is ordered in ascending order - * 4) the operator is not already registered + * @param quorumNumbers The quorum numbers to register for, where each byte is an 8-bit integer. + * @dev Access restricted to the RegistryCoordinator. + * @dev Preconditions (assumed, not validated): + * 1. `quorumNumbers` has no duplicatesd + * 2. `quorumNumbers.length` != 0 + * 3. `quorumNumbers` is ordered ascending + * 4. The operator is not already registered */ function registerOperator(address operator, bytes calldata quorumNumbers) external; - /** - * @notice Deregisters the `operator`'s pubkey for the specified `quorumNumbers`. + /* + * @notice Deregisters `operator`'s pubkey from `quorumNumbers`. * @param operator The address of the operator to deregister. - * @param quorumNumbers The quorum numbers the operator is deregistering from, where each byte is an 8 bit integer quorumNumber. - * @dev access restricted to the RegistryCoordinator - * @dev Preconditions (these are assumed, not validated in this contract): - * 1) `quorumNumbers` has no duplicates - * 2) `quorumNumbers.length` != 0 - * 3) `quorumNumbers` is ordered in ascending order - * 4) the operator is not already deregistered - * 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for + * @param quorumNumbers The quorum numbers to deregister from, where each byte is an 8-bit integer. + * @dev Access restricted to the RegistryCoordinator. + * @dev Preconditions (assumed, not validated): + * 1. `quorumNumbers` has no duplicates + * 2. `quorumNumbers.length` != 0 + * 3. `quorumNumbers` is ordered ascending + * 4. The operator is not already deregistered + * 5. `quorumNumbers` is a subset of the operator's registered quorums */ function deregisterOperator(address operator, bytes calldata quorumNumbers) external; - /** - * @notice Initializes a new quorum by pushing its first apk update - * @param quorumNumber The number of the new quorum + /* + * @notice Initializes `quorumNumber` by pushing its first APK update. + * @param quorumNumber The number of the new quorum. */ function initializeQuorum( uint8 quorumNumber ) external; - /** - * @notice mapping from operator address to pubkey hash. - * Returns *zero* if the `operator` has never registered, and otherwise returns the hash of the public key of the operator. - */ - function operatorToPubkeyHash( - address operator - ) external view returns (bytes32); - - /** - * @notice mapping from pubkey hash to operator address. - * Returns *zero* if no operator has ever registered the public key corresponding to `pubkeyHash`, - * and otherwise returns the (unique) registered operator who owns the BLS public key that is the preimage of `pubkeyHash`. - */ - function pubkeyHashToOperator( - bytes32 pubkeyHash - ) external view returns (address); - - /** - * @notice Called by the RegistryCoordinator register an operator as the owner of a BLS public key. - * @param operator is the operator for whom the key is being registered - * @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership - * @param pubkeyRegistrationMessageHash is a hash that the operator must sign to prove key ownership + /* + * @notice Registers `operator` as the owner of a BLS public key using `params` and `pubkeyRegistrationMessageHash`. + * @param operator The operator for whom the key is being registered. + * @param params Contains the G1 & G2 public keys and ownership proof signature. + * @param pubkeyRegistrationMessageHash The hash that must be signed to prove key ownership. + * @return operatorId The unique identifier (pubkey hash) for this operator. + * @dev Called by the RegistryCoordinator. */ function registerBLSPublicKey( address operator, - PubkeyRegistrationParams calldata params, + IBLSApkRegistryTypes.PubkeyRegistrationParams calldata params, BN254.G1Point calldata pubkeyRegistrationMessageHash ) external returns (bytes32 operatorId); - /** - * @notice Returns the pubkey and pubkey hash of an operator - * @dev Reverts if the operator has not registered a valid pubkey + /* VIEW */ + + /* + * @notice Returns the pubkey and pubkey hash of `operator`. + * @param operator The address of the operator. + * @return The operator's G1 public key and its hash. + * @dev Reverts if the operator has not registered a valid pubkey. */ function getRegisteredPubkey( address operator ) external view returns (BN254.G1Point memory, bytes32); - /// @notice Returns the current APK for the provided `quorumNumber ` - function getApk( - uint8 quorumNumber - ) external view returns (BN254.G1Point memory); - - /// @notice Returns the index of the quorumApk index at `blockNumber` for the provided `quorumNumber` + /* + * @notice Returns the APK indices at `blockNumber` for `quorumNumbers`. + * @param quorumNumbers The quorum numbers to get indices for. + * @param blockNumber The block number to query at. + * @return Array of indices corresponding to each quorum number. + */ function getApkIndicesAtBlockNumber( bytes calldata quorumNumbers, uint256 blockNumber ) external view returns (uint32[] memory); - /// @notice Returns the `ApkUpdate` struct at `index` in the list of APK updates for the `quorumNumber` + /* + * @notice Returns the current aggregate public key for `quorumNumber`. + * @param quorumNumber The quorum to query. + * @return The current APK as a G1 point. + */ + function getApk( + uint8 quorumNumber + ) external view returns (BN254.G1Point memory); + + /* + * @notice Returns an APK update entry for `quorumNumber` at `index`. + * @param quorumNumber The quorum to query. + * @param index The index in the APK history. + * @return The APK update entry. + */ function getApkUpdateAtIndex( uint8 quorumNumber, uint256 index - ) external view returns (ApkUpdate memory); + ) external view returns (IBLSApkRegistryTypes.ApkUpdate memory); - /// @notice Returns the operator address for the given `pubkeyHash` - function getOperatorFromPubkeyHash( - bytes32 pubkeyHash - ) external view returns (address); - - /** - * @notice get 24 byte hash of the apk of `quorumNumber` at `blockNumber` using the provided `index`; - * called by checkSignatures in BLSSignatureChecker.sol. - * @param quorumNumber is the quorum whose ApkHash is being retrieved - * @param blockNumber is the number of the block for which the latest ApkHash will be retrieved - * @param index is the index of the apkUpdate being retrieved from the list of quorum apkUpdates in storage + /* + * @notice Gets the 24-byte hash of `quorumNumber`'s APK at `blockNumber` and `index`. + * @param quorumNumber The quorum to query. + * @param blockNumber The block number to get the APK hash for. + * @param index The index in the APK history. + * @return The 24-byte APK hash. + * @dev Called by checkSignatures in BLSSignatureChecker.sol. */ function getApkHashAtBlockNumberAndIndex( uint8 quorumNumber, @@ -175,9 +247,32 @@ interface IBLSApkRegistry is IRegistry, IBLSApkRegistryErrors { uint256 index ) external view returns (bytes24); - /// @notice returns the ID used to identify the `operator` within this AVS. - /// @dev Returns zero in the event that the `operator` has never registered for the AVS + /* + * @notice Returns the number of APK updates for `quorumNumber`. + * @param quorumNumber The quorum to query. + * @return The length of the APK history. + */ + function getApkHistoryLength( + uint8 quorumNumber + ) external view returns (uint32); + + /* + * @notice Maps `operator` to their corresponding public key hash. + * @param operator The address of the operator. + * @return operatorId The hash of the operator's BLS public key. + * @dev Returns bytes32(0) if the operator hasn't registered a key. + */ function getOperatorId( address operator - ) external view returns (bytes32); + ) external view returns (bytes32 operatorId); + + /* + * @notice Maps `pubkeyHash` to their corresponding operator address. + * @param pubkeyHash The hash of a BLS public key. + * @return operator The address of the operator who registered this public key. + * @dev Returns address(0) if the public key hash hasn't been registered. + */ + function getOperatorFromPubkeyHash( + bytes32 pubkeyHash + ) external view returns (address operator); } diff --git a/src/interfaces/IBLSSignatureChecker.sol b/src/interfaces/IBLSSignatureChecker.sol index 87feab40..e7b78a04 100644 --- a/src/interfaces/IBLSSignatureChecker.sol +++ b/src/interfaces/IBLSSignatureChecker.sol @@ -8,86 +8,146 @@ import {IStakeRegistry, IDelegationManager} from "./IStakeRegistry.sol"; import {BN254} from "../libraries/BN254.sol"; interface IBLSSignatureCheckerErrors { - /// @dev Thrown when the caller is not the registry coordinator owner. + /// @notice Thrown when the caller is not the registry coordinator owner. error OnlyRegistryCoordinatorOwner(); - /// @dev Thrown when the quorum numbers input in is empty. + /// @notice Thrown when the quorum numbers input in is empty. error InputEmptyQuorumNumbers(); - /// @dev Thrown when two array parameters have mismatching lengths. + /// @notice Thrown when two array parameters have mismatching lengths. error InputArrayLengthMismatch(); - /// @dev Thrown when the non-signer pubkey length does not match non-signer bitmap indices length. + /// @notice Thrown when the non-signer pubkey length does not match non-signer bitmap indices length. error InputNonSignerLengthMismatch(); - /// @dev Thrown when the reference block number is invalid. + /// @notice Thrown when the reference block number is invalid. error InvalidReferenceBlocknumber(); - /// @dev Thrown when the non signer pubkeys are not sorted. + /// @notice Thrown when the non signer pubkeys are not sorted. error NonSignerPubkeysNotSorted(); - /// @dev Thrown when StakeRegistry updates have not been updated within withdrawalDelayBlocks window + /// @notice Thrown when StakeRegistry updates have not been updated within withdrawalDelayBlocks window error StaleStakesForbidden(); - /// @dev Thrown when the quorum apk hash in storage does not match provided quorum apk. + /// @notice Thrown when the quorum apk hash in storage does not match provided quorum apk. error InvalidQuorumApkHash(); - /// @dev Thrown when BLS pairing precompile call fails. + /// @notice Thrown when BLS pairing precompile call fails. error InvalidBLSPairingKey(); - /// @dev Thrown when BLS signature is invalid. + /// @notice Thrown when BLS signature is invalid. error InvalidBLSSignature(); } -/** - * @title Used for checking BLS aggregate signatures from the operators of a EigenLayer AVS with the RegistryCoordinator/BLSApkRegistry/StakeRegistry architechture. - * @author Layr Labs, Inc. - * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service - * @notice This is the contract for checking the validity of aggregate operator signatures. - */ -interface IBLSSignatureChecker is IBLSSignatureCheckerErrors { - // DATA STRUCTURES +interface IBLSSignatureCheckerTypes { + /// @notice Contains bitmap and pubkey hash information for non-signing operators. + /// @param quorumBitmaps Array of bitmaps indicating which quorums each non-signer was registered for. + /// @param pubkeyHashes Array of BLS public key hashes for each non-signer. + struct NonSignerInfo { + uint256[] quorumBitmaps; + bytes32[] pubkeyHashes; + } + /// @notice Contains non-signer information and aggregated signature data for BLS verification. + /// @param nonSignerQuorumBitmapIndices The indices of all non-signer quorum bitmaps. + /// @param nonSignerPubkeys The G1 public keys of all non-signers. + /// @param quorumApks The aggregate G1 public key of each quorum. + /// @param apkG2 The aggregate G2 public key of all signers. + /// @param sigma The aggregate G1 signature of all signers. + /// @param quorumApkIndices The indices of each quorum's aggregate public key in the APK registry. + /// @param totalStakeIndices The indices of each quorum's total stake in the stake registry. + /// @param nonSignerStakeIndices The indices of each non-signer's stake within each quorum. + /// @dev Used as input to checkSignatures() to verify BLS signatures. struct NonSignerStakesAndSignature { - uint32[] nonSignerQuorumBitmapIndices; // is the indices of all nonsigner quorum bitmaps - BN254.G1Point[] nonSignerPubkeys; // is the G1 pubkeys of all nonsigners - BN254.G1Point[] quorumApks; // is the aggregate G1 pubkey of each quorum - BN254.G2Point apkG2; // is the aggregate G2 pubkey of all signers - BN254.G1Point sigma; // is the aggregate G1 signature of all signers - uint32[] quorumApkIndices; // is the indices of each quorum aggregate pubkey - uint32[] totalStakeIndices; // is the indices of each quorums total stake - uint32[][] nonSignerStakeIndices; // is the indices of each non signers stake within a quorum + uint32[] nonSignerQuorumBitmapIndices; + BN254.G1Point[] nonSignerPubkeys; + BN254.G1Point[] quorumApks; + BN254.G2Point apkG2; + BN254.G1Point sigma; + uint32[] quorumApkIndices; + uint32[] totalStakeIndices; + uint32[][] nonSignerStakeIndices; } - /** - * @notice this data structure is used for recording the details on the total stake of the registered - * operators and those operators who are part of the quorum for a particular taskNumber - */ + /// @notice Records the total stake amounts for operators in each quorum. + /// @param signedStakeForQuorum Array of total stake amounts from operators who signed, per quorum. + /// @param totalStakeForQuorum Array of total stake amounts from all operators, per quorum. + /// @dev Used to track stake distribution and calculate quorum thresholds. Array indices correspond to quorum numbers. struct QuorumStakeTotals { - // total stake of the operators in each quorum uint96[] signedStakeForQuorum; - // total amount staked by all operators in each quorum uint96[] totalStakeForQuorum; } +} - // EVENTS - - /// @notice Emitted when `staleStakesForbiddenUpdate` is set +interface IBLSSignatureCheckerEvents is IBLSSignatureCheckerTypes { + /// @notice Emitted when `staleStakesForbiddenUpdate` is set. event StaleStakesForbiddenUpdate(bool value); +} - // CONSTANTS & IMMUTABLES +interface IBLSSignatureChecker is IBLSSignatureCheckerErrors, IBLSSignatureCheckerEvents { + /* STATE */ + /* + * @notice Returns the address of the registry coordinator contract. + * @return The address of the registry coordinator. + * @dev This value is immutable and set during contract construction. + */ function registryCoordinator() external view returns (ISlashingRegistryCoordinator); + + /* + * @notice Returns the address of the stake registry contract. + * @return The address of the stake registry. + * @dev This value is immutable and set during contract construction. + */ function stakeRegistry() external view returns (IStakeRegistry); + + /* + * @notice Returns the address of the BLS APK registry contract. + * @return The address of the BLS APK registry. + * @dev This value is immutable and set during contract construction. + */ function blsApkRegistry() external view returns (IBLSApkRegistry); + + /* + * @notice Returns the address of the delegation manager contract. + * @return The address of the delegation manager. + * @dev This value is immutable and set during contract construction. + */ function delegation() external view returns (IDelegationManager); - /** + /* + * @notice Returns whether stale stakes are forbidden in signature verification. + * @return True if stale stakes are forbidden, false otherwise. + */ + function staleStakesForbidden() external view returns (bool); + + /* ACTIONS */ + + /* + * @notice Sets `value` as the new staleStakesForbidden flag. + * @param value True to forbid stale stakes, false to allow them. + * @dev Access restricted to the registry coordinator owner. + */ + function setStaleStakesForbidden( + bool value + ) external; + + /* VIEW */ + + /* * @notice This function is called by disperser when it has aggregated all the signatures of the operators * that are part of the quorum for a particular taskNumber and is asserting them into onchain. The function * checks that the claim for aggregated signatures are valid. * * The thesis of this procedure entails: - * - getting the aggregated pubkey of all registered nodes at the time of pre-commit by the - * disperser (represented by apk in the parameters), - * - subtracting the pubkeys of all the signers not in the quorum (nonSignerPubkeys) and storing - * the output in apk to get aggregated pubkey of all operators that are part of quorum. - * - use this aggregated pubkey to verify the aggregated signature under BLS scheme. + * 1. Getting the aggregated pubkey of all registered nodes at the time of pre-commit by the + * disperser (represented by apk in the parameters) + * 2. Subtracting the pubkeys of all non-signers (nonSignerPubkeys) and storing + * the output in apk to get aggregated pubkey of all operators that are part of quorum + * 3. Using this aggregated pubkey to verify the aggregated signature under BLS scheme * - * @dev Before signature verification, the function verifies operator stake information. This includes ensuring that the provided `referenceBlockNumber` - * 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 - * for the total stake (or the operator) or latest before the referenceBlockNumber. + * @param msgHash The hash of the message that was signed. NOTE: Be careful to ensure msgHash is + * collision-resistant! This method does not hash msgHash in any way, so if an attacker is able + * to pass in an arbitrary value, they may be able to tamper with signature verification. + * @param quorumNumbers The quorum numbers to verify signatures for, where each byte is an 8-bit integer. + * @param referenceBlockNumber The block number at which the stake information is being verified + * @param nonSignerStakesAndSignature Contains non-signer information and aggregated signature data. + * @return quorumStakeTotals The struct containing the total and signed stake for each quorum + * @return signatoryRecordHash The hash of the signatory record, which is used for fraud proofs + * @dev Before signature verification, the function verifies operator stake information. This includes + * ensuring that the provided referenceBlockNumber is valid and recent enough, and that the stake is + * either the most recent update for the total stake (of the operator) or latest before the referenceBlockNumber. */ function checkSignatures( bytes32 msgHash, @@ -95,4 +155,20 @@ interface IBLSSignatureChecker is IBLSSignatureCheckerErrors { uint32 referenceBlockNumber, NonSignerStakesAndSignature memory nonSignerStakesAndSignature ) external view returns (QuorumStakeTotals memory, bytes32); + + /* + * @notice Attempts to verify signature `sigma` against message hash `msgHash` using aggregate public keys `apk` and `apkG2`. + * @param msgHash The hash of the message that was signed. + * @param apk The aggregate public key in G1. + * @param apkG2 The aggregate public key in G2. + * @param sigma The signature to verify. + * @return pairingSuccessful True if the pairing check succeeded. + * @return siganatureIsValid True if the signature is valid. + */ + function trySignatureAndApkVerification( + bytes32 msgHash, + BN254.G1Point memory apk, + BN254.G2Point memory apkG2, + BN254.G1Point memory sigma + ) external view returns (bool pairingSuccessful, bool siganatureIsValid); } diff --git a/src/interfaces/IECDSAStakeRegistry.sol b/src/interfaces/IECDSAStakeRegistry.sol new file mode 100644 index 00000000..e17086f8 --- /dev/null +++ b/src/interfaces/IECDSAStakeRegistry.sol @@ -0,0 +1,305 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {IERC1271Upgradeable} from + "@openzeppelin-upgrades/contracts/interfaces/IERC1271Upgradeable.sol"; +import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; +import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; +import {IDelegationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; + +// TODO: many of these errors do not have test coverage. + +interface IECDSAStakeRegistryErrors { + /// @notice Thrown when the lengths of the signers array and signatures array do not match. + error LengthMismatch(); + /// @notice Thrown when encountering an invalid length for the signers or signatures array. + error InvalidLength(); + /// @notice Thrown when encountering an invalid signature. + error InvalidSignature(); + /// @notice Thrown when the threshold update is greater than BPS. + error InvalidThreshold(); + /// @notice Thrown when missing operators in an update. + error MustUpdateAllOperators(); + /// @notice Thrown when reference blocks must be for blocks that have already been confirmed. + error InvalidReferenceBlock(); + /// @notice Thrown when operator weights were out of sync and the signed weight exceed the total. + error InvalidSignedWeight(); + /// @notice Thrown when the total signed stake fails to meet the required threshold. + error InsufficientSignedStake(); + /// @notice Thrown when an individual signer's weight fails to meet the required threshold. + error InsufficientWeight(); + /// @notice Thrown when the quorum is invalid. + error InvalidQuorum(); + /// @notice Thrown when the system finds a list of items unsorted. + error NotSorted(); + /// @notice Thrown when registering an already registered operator. + error OperatorAlreadyRegistered(); + /// @notice Thrown when de-registering or updating the stake for an unregisted operator. + error OperatorNotRegistered(); +} + +interface IECDSAStakeRegistryTypes { + /// @notice Parameters for a strategy and its weight multiplier. + /// @param strategy The strategy contract reference. + /// @param multiplier The multiplier applied to the strategy. + struct StrategyParams { + IStrategy strategy; + uint96 multiplier; + } + + /// @notice Configuration for a quorum's strategies. + /// @param strategies An array of strategy parameters defining the quorum. + struct Quorum { + StrategyParams[] strategies; + } +} + +interface IECDSAStakeRegistryEvents is IECDSAStakeRegistryTypes { + /* + * @notice Emitted when the system registers an operator. + * @param operator The address of the registered operator. + * @param avs The address of the associated AVS. + */ + event OperatorRegistered(address indexed operator, address indexed avs); + + /* + * @notice Emitted when the system deregisters an operator. + * @param operator The address of the deregistered operator. + * @param avs The address of the associated AVS. + */ + event OperatorDeregistered(address indexed operator, address indexed avs); + + /* + * @notice Emitted when the system updates the quorum. + * @param previous The previous quorum configuration. + * @param current The new quorum configuration. + */ + event QuorumUpdated(Quorum previous, Quorum current); + + /* + * @notice Emitted when the weight to join the operator set updates. + * @param previous The previous minimum weight. + * @param current The new minimumWeight. + */ + event MinimumWeightUpdated(uint256 previous, uint256 current); + + /* + * @notice Emitted when the weight required to be an operator changes. + * @param oldMinimumWeight The previous weight. + * @param newMinimumWeight The updated weight. + */ + event UpdateMinimumWeight(uint256 oldMinimumWeight, uint256 newMinimumWeight); + + /* + * @notice Emitted when the system updates an operator's weight. + * @param operator The address of the operator updated. + * @param oldWeight The operator's weight before the update. + * @param newWeight The operator's weight after the update. + */ + event OperatorWeightUpdated(address indexed operator, uint256 oldWeight, uint256 newWeight); + + /* + * @notice Emitted when the system updates the total weight. + * @param oldTotalWeight The total weight before the update. + * @param newTotalWeight The total weight after the update. + */ + event TotalWeightUpdated(uint256 oldTotalWeight, uint256 newTotalWeight); + + /* + * @notice Emits when setting a new threshold weight. + */ + event ThresholdWeightUpdated(uint256 thresholdWeight); + + /* + * @notice Emitted when an operator's signing key is updated. + * @param operator The address of the operator whose signing key was updated. + * @param updateBlock The block number at which the signing key was updated. + * @param newSigningKey The operator's signing key after the update. + * @param oldSigningKey The operator's signing key before the update. + */ + event SigningKeyUpdate( + address indexed operator, + uint256 indexed updateBlock, + address indexed newSigningKey, + address oldSigningKey + ); +} + +interface IECDSAStakeRegistry is + IECDSAStakeRegistryErrors, + IECDSAStakeRegistryEvents, + IERC1271Upgradeable +{ + /* ACTIONS */ + + /* + * @notice Registers a new operator using a provided operators signature and signing key. + * @param operatorSignature Contains the operator's signature, salt, and expiry. + * @param signingKey The signing key to add to the operator's history. + */ + function registerOperatorWithSignature( + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature, + address signingKey + ) external; + + /* + * @notice Deregisters an existing operator. + */ + function deregisterOperator() external; + + /* + * @notice Updates the signing key for an operator. + * @param newSigningKey The new signing key to set for the operator. + * @dev Only callable by the operator themselves. + */ + function updateOperatorSigningKey( + address newSigningKey + ) external; + + /* + * @notice Updates the StakeRegistry's view of operators' stakes. + * @param operators A list of operator addresses to update. + * @dev Queries stakes from the Eigenlayer core DelegationManager contract. + */ + function updateOperators( + address[] memory operators + ) external; + + /* + * @notice Updates the quorum configuration and the set of operators. + * @param quorum The new quorum configuration, including strategies and their new weights. + * @param operators The list of operator addresses to update stakes for. + */ + function updateQuorumConfig( + IECDSAStakeRegistryTypes.Quorum memory quorum, + address[] memory operators + ) external; + + /* + * @notice Updates the weight an operator must have to join the operator set. + * @param newMinimumWeight The new weight an operator must have to join the operator set. + * @param operators The list of operators to update after changing the minimum weight. + */ + function updateMinimumWeight(uint256 newMinimumWeight, address[] memory operators) external; + + /* + * @notice Sets a new cumulative threshold weight for message validation. + * @param thresholdWeight The updated threshold weight required to validate a message. + */ + function updateStakeThreshold( + uint256 thresholdWeight + ) external; + + /* VIEW */ + + /* + * @notice Retrieves the current stake quorum details. + * @return The current quorum of strategies and weights. + */ + function quorum() external view returns (IECDSAStakeRegistryTypes.Quorum memory); + + /* + * @notice Retrieves the latest signing key for a given operator. + * @param operator The address of the operator. + * @return The latest signing key of the operator. + */ + function getLatestOperatorSigningKey( + address operator + ) external view returns (address); + + /* + * @notice Retrieves the signing key for an operator at a specific block. + * @param operator The address of the operator. + * @param blockNumber The block number to query at. + * @return The signing key of the operator at the given block. + */ + function getOperatorSigningKeyAtBlock( + address operator, + uint256 blockNumber + ) external view returns (address); + + /* + * @notice Retrieves the last recorded weight for a given operator. + * @param operator The address of the operator. + * @return The latest weight of the operator. + */ + function getLastCheckpointOperatorWeight( + address operator + ) external view returns (uint256); + + /* + * @notice Retrieves the last recorded total weight across all operators. + * @return The latest total weight. + */ + function getLastCheckpointTotalWeight() external view returns (uint256); + + /* + * @notice Retrieves the last recorded threshold weight. + * @return The latest threshold weight. + */ + function getLastCheckpointThresholdWeight() external view returns (uint256); + + /* + * @notice Returns whether an operator is currently registered. + * @param operator The operator address to check. + * @return Whether the operator is registered. + */ + function operatorRegistered( + address operator + ) external view returns (bool); + + /* + * @notice Returns the minimum weight required for operator participation. + * @return The minimum weight threshold. + */ + function minimumWeight() external view returns (uint256); + + /* + * @notice Retrieves the operator's weight at a specific block number. + * @param operator The address of the operator. + * @param blockNumber The block number to query at. + * @return The weight of the operator at the given block. + */ + function getOperatorWeightAtBlock( + address operator, + uint32 blockNumber + ) external view returns (uint256); + + /* + * @notice Retrieves the operator's weight. + * @param operator The address of the operator. + * @return The current weight of the operator. + */ + function getOperatorWeight( + address operator + ) external view returns (uint256); + + /* + * @notice Updates operators for a specific quorum. + * @param operatorsPerQuorum Array of operator addresses per quorum. + * @param data Additional data (unused but kept for interface compatibility). + */ + function updateOperatorsForQuorum( + address[][] memory operatorsPerQuorum, + bytes memory data + ) external; + + /* + * @notice Retrieves the total weight at a specific block number. + * @param blockNumber The block number to query at. + * @return The total weight at the given block. + */ + function getLastCheckpointTotalWeightAtBlock( + uint32 blockNumber + ) external view returns (uint256); + + /* + * @notice Retrieves the threshold weight at a specific block number. + * @param blockNumber The block number to query at. + * @return The threshold weight at the given block. + */ + function getLastCheckpointThresholdWeightAtBlock( + uint32 blockNumber + ) external view returns (uint256); +} diff --git a/src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol b/src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol deleted file mode 100644 index 96bea50a..00000000 --- a/src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol +++ /dev/null @@ -1,105 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.27; - -import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; - -struct StrategyParams { - IStrategy strategy; // The strategy contract reference - uint96 multiplier; // The multiplier applied to the strategy -} - -struct Quorum { - StrategyParams[] strategies; // An array of strategy parameters to define the quorum -} - -interface ECDSAStakeRegistryEventsAndErrors { - /// @notice Emitted when the system registers an operator - /// @param _operator The address of the registered operator - /// @param _avs The address of the associated AVS - event OperatorRegistered(address indexed _operator, address indexed _avs); - - /// @notice Emitted when the system deregisters an operator - /// @param _operator The address of the deregistered operator - /// @param _avs The address of the associated AVS - event OperatorDeregistered(address indexed _operator, address indexed _avs); - - /// @notice Emitted when the system updates the quorum - /// @param _old The previous quorum configuration - /// @param _new The new quorum configuration - event QuorumUpdated(Quorum _old, Quorum _new); - - /// @notice Emitted when the weight to join the operator set updates - /// @param _old The previous minimum weight - /// @param _new The new minimumWeight - event MinimumWeightUpdated(uint256 _old, uint256 _new); - - /// @notice Emitted when the weight required to be an operator changes - /// @param oldMinimumWeight The previous weight - /// @param newMinimumWeight The updated weight - event UpdateMinimumWeight(uint256 oldMinimumWeight, uint256 newMinimumWeight); - - /// @notice Emitted when the system updates an operator's weight - /// @param _operator The address of the operator updated - /// @param oldWeight The operator's weight before the update - /// @param newWeight The operator's weight after the update - event OperatorWeightUpdated(address indexed _operator, uint256 oldWeight, uint256 newWeight); - - /// @notice Emitted when the system updates the total weight - /// @param oldTotalWeight The total weight before the update - /// @param newTotalWeight The total weight after the update - event TotalWeightUpdated(uint256 oldTotalWeight, uint256 newTotalWeight); - - /// @notice Emits when setting a new threshold weight. - event ThresholdWeightUpdated(uint256 _thresholdWeight); - - /// @notice Emitted when an operator's signing key is updated - /// @param operator The address of the operator whose signing key was updated - /// @param updateBlock The block number at which the signing key was updated - /// @param newSigningKey The operator's signing key after the update - /// @param oldSigningKey The operator's signing key before the update - event SigningKeyUpdate( - address indexed operator, - uint256 indexed updateBlock, - address indexed newSigningKey, - address oldSigningKey - ); - /// @notice Indicates when the lengths of the signers array and signatures array do not match. - - error LengthMismatch(); - - /// @notice Indicates encountering an invalid length for the signers or signatures array. - error InvalidLength(); - - /// @notice Indicates encountering an invalid signature. - error InvalidSignature(); - - /// @notice Thrown when the threshold update is greater than BPS - error InvalidThreshold(); - - /// @notice Thrown when missing operators in an update - error MustUpdateAllOperators(); - - /// @notice Reference blocks must be for blocks that have already been confirmed - error InvalidReferenceBlock(); - - /// @notice Indicates operator weights were out of sync and the signed weight exceed the total - error InvalidSignedWeight(); - - /// @notice Indicates the total signed stake fails to meet the required threshold. - error InsufficientSignedStake(); - - /// @notice Indicates an individual signer's weight fails to meet the required threshold. - error InsufficientWeight(); - - /// @notice Indicates the quorum is invalid - error InvalidQuorum(); - - /// @notice Indicates the system finds a list of items unsorted - error NotSorted(); - - /// @notice Thrown when registering an already registered operator - error OperatorAlreadyRegistered(); - - /// @notice Thrown when de-registering or updating the stake for an unregisted operator - error OperatorNotRegistered(); -} diff --git a/src/interfaces/IEjectionManager.sol b/src/interfaces/IEjectionManager.sol index a491a973..5ead07cb 100644 --- a/src/interfaces/IEjectionManager.sol +++ b/src/interfaces/IEjectionManager.sol @@ -1,70 +1,152 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; +import {IRegistryCoordinator} from "./IRegistryCoordinator.sol"; +import {IStakeRegistry} from "./IStakeRegistry.sol"; + interface IEjectionManagerErrors { - /// @dev Thrown when the caller is not the owner or ejector. + /// @notice Thrown when the caller is not the owner or ejector. error OnlyOwnerOrEjector(); - /// @dev Thrown when quorum number exceeds MAX_QUORUM_COUNT. + /// @notice Thrown when quorum number exceeds MAX_QUORUM_COUNT. error MaxQuorumCount(); } -/** - * @title Interface for a contract that ejects operators from an AVSs RegistryCoordinator - * @author Layr Labs, Inc. - */ -interface IEjectionManager is IEjectionManagerErrors { - /// @notice A quorum's ratelimit parameters +interface IEjectionManagerTypes { + /// @notice Parameters for controlling ejection rate limits per quorum. + /// @param rateLimitWindow Time window to track ejection rate (in seconds). + /// @param ejectableStakePercent Maximum percentage of stake that can be ejected per window (in BIPS). struct QuorumEjectionParams { - uint32 rateLimitWindow; // Time delta to track ejection over - uint16 ejectableStakePercent; // Max stake to be ejectable per time delta + uint32 rateLimitWindow; + uint16 ejectableStakePercent; } - /// @notice A stake ejection event + /// @notice Records a stake ejection event with timing and amount. + /// @param timestamp Time when the ejection occurred. + /// @param stakeEjected Amount of stake that was ejected. struct StakeEjection { - uint256 timestamp; // Timestamp of the ejection - uint256 stakeEjected; // Amount of stake ejected at the timestamp + uint256 timestamp; + uint256 stakeEjected; } +} - ///@notice Emitted when the ejector address is set +interface IEjectionManagerEvents is IEjectionManagerTypes { + /* + * @notice Emitted when the ejector address is set. + * @param ejector The address being configured as ejector. + * @param status The new status for the ejector address. + */ event EjectorUpdated(address ejector, bool status); - ///@notice Emitted when the ratelimit parameters for a quorum are set + + /* + * @notice Emitted when the rate limit parameters for a quorum are set. + * @param quorumNumber The quorum number being configured. + * @param rateLimitWindow The new time window for rate limiting. + * @param ejectableStakePercent The new percentage of stake that can be ejected. + */ event QuorumEjectionParamsSet( uint8 quorumNumber, uint32 rateLimitWindow, uint16 ejectableStakePercent ); - ///@notice Emitted when an operator is ejected + + /* + * @notice Emitted when an operator is ejected. + * @param operatorId The unique identifier of the ejected operator. + * @param quorumNumber The quorum number the operator was ejected from. + */ event OperatorEjected(bytes32 operatorId, uint8 quorumNumber); - ///@notice Emitted when operators are ejected for a quroum + + /* + * @notice Emitted when operators are ejected for a quorum. + * @param ejectedOperators Number of operators that were ejected. + * @param ratelimitHit Whether the ejection rate limit was reached. + */ event QuorumEjection(uint32 ejectedOperators, bool ratelimitHit); +} + +interface IEjectionManager is IEjectionManagerErrors, IEjectionManagerEvents { + /* STATE */ - /** - * @notice Ejects operators from the AVSs registryCoordinator under a ratelimit - * @param _operatorIds The ids of the operators to eject for each quorum + /* + * @notice Returns the address of the registry coordinator contract. + * @return The address of the registry coordinator. + * @dev This value is immutable and set during contract construction. + */ + function registryCoordinator() external view returns (IRegistryCoordinator); + + /* + * @notice Returns the address of the stake registry contract. + * @return The address of the stake registry. + * @dev This value is immutable and set during contract construction. + */ + function stakeRegistry() external view returns (IStakeRegistry); + + /* + * @notice Returns whether `ejector` is authorized to eject operators under a rate limit. + * @param ejector The address to check. + * @return Whether the address is authorized to eject operators. + */ + function isEjector( + address ejector + ) external view returns (bool); + + /* + * @notice Returns the stake ejected for a quorum `quorumNumber` at array offset `index`. + * @param quorumNumber The quorum number to query. + * @param index The index in the ejection history. + * @return timestamp The timestamp of the ejection. + * @return stakeEjected The amount of stake ejected. + */ + function stakeEjectedForQuorum( + uint8 quorumNumber, + uint256 index + ) external view returns (uint256 timestamp, uint256 stakeEjected); + + /* + * @notice Returns the rate limit parameters for quorum `quorumNumber`. + * @param quorumNumber The quorum number to query. + * @return rateLimitWindow The time window to track ejection rate (in seconds). + * @return ejectableStakePercent The maximum percentage of stake that can be ejected per window (in BIPS). + */ + function quorumEjectionParams( + uint8 quorumNumber + ) external view returns (uint32 rateLimitWindow, uint16 ejectableStakePercent); + + /* ACTIONS */ + + /* + * @notice Ejects operators specified in `operatorIds` from the AVS's RegistryCoordinator under a rate limit. + * @param operatorIds The ids of the operators to eject for each quorum. + * @dev This function will eject as many operators as possible prioritizing operators at the lower index. + * @dev The owner can eject operators without recording of stake ejection. */ function ejectOperators( - bytes32[][] memory _operatorIds + bytes32[][] memory operatorIds ) external; - /** - * @notice Sets the ratelimit parameters for a quorum - * @param _quorumNumber The quorum number to set the ratelimit parameters for - * @param _quorumEjectionParams The quorum ratelimit parameters to set for the given quorum + /* + * @notice Sets the rate limit parameters for quorum `quorumNumber` to `quorumEjectionParams`. + * @param quorumNumber The quorum number to set the rate limit parameters for. + * @param quorumEjectionParams The quorum rate limit parameters to set. */ function setQuorumEjectionParams( - uint8 _quorumNumber, - QuorumEjectionParams memory _quorumEjectionParams + uint8 quorumNumber, + QuorumEjectionParams memory quorumEjectionParams ) external; - /** - * @notice Sets the address permissioned to eject operators under a ratelimit - * @param _ejector The address to permission + /* + * @notice Sets whether address `ejector` is permissioned to eject operators under a rate limit to `status`. + * @param ejector The address to permission. + * @param status The status to set for the given address. */ - function setEjector(address _ejector, bool _status) external; + function setEjector(address ejector, bool status) external; + + /* VIEW */ - /** - * @notice Returns the amount of stake that can be ejected for a quorum at the current block.timestamp - * @param _quorumNumber The quorum number to view ejectable stake for + /* + * @notice Returns the amount of stake that can be ejected for quorum `quorumNumber` at the current block.timestamp. + * @param quorumNumber The quorum number to view ejectable stake for. + * @return The amount of stake that can be ejected. */ function amountEjectableForQuorum( - uint8 _quorumNumber + uint8 quorumNumber ) external view returns (uint256); } diff --git a/src/interfaces/IIndexRegistry.sol b/src/interfaces/IIndexRegistry.sol index 08b963ad..9cd26302 100644 --- a/src/interfaces/IIndexRegistry.sol +++ b/src/interfaces/IIndexRegistry.sol @@ -1,55 +1,83 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IRegistry} from "./IRegistry.sol"; - interface IIndexRegistryErrors { - /// @dev Thrown when a function is called by an address that is not the RegistryCoordinator + /// @notice Thrown when a function is called by an address that is not the RegistryCoordinator. error OnlyRegistryCoordinator(); - /// @dev Thrown when a quorum has 0 length history and thus does not exist + /// @notice Thrown when attempting to query a quorum that has no history. error QuorumDoesNotExist(); - /// @dev Thrown when an operatorId is not found in the registry at a given block number + /// @notice Thrown when attempting to look up an operator that does not exist at the specified block number. error OperatorIdDoesNotExist(); } -/** - * @title Interface for a `Registry`-type contract that keeps track of an ordered list of operators for up to 256 quorums. - * @author Layr Labs, Inc. - */ -interface IIndexRegistry is IRegistry, IIndexRegistryErrors { - // EVENTS - - // emitted when an operator's index in the ordered operator list for the quorum with number `quorumNumber` is updated - event QuorumIndexUpdate( - bytes32 indexed operatorId, uint8 quorumNumber, uint32 newOperatorIndex - ); - - // DATA STRUCTURES - - // struct used to give definitive ordering to operators at each blockNumber. +interface IIndexRegistryTypes { + /// @notice Represents an update to an operator's status at a specific index. + /// @param fromBlockNumber The block number from which this update takes effect. + /// @param operatorId The unique identifier of the operator. struct OperatorUpdate { - // blockNumber number from which `operatorIndex` was the operators index - // the operator's index is the first entry such that `blockNumber >= entry.fromBlockNumber` uint32 fromBlockNumber; - // the operator at this index bytes32 operatorId; } - // struct used to denote the number of operators in a quorum at a given blockNumber + /// @notice Represents an update to the total number of operators in a quorum. + /// @param fromBlockNumber The block number from which this update takes effect. + /// @param numOperators The total number of operators after the update. struct QuorumUpdate { - // The total number of operators at a `blockNumber` is the first entry such that `blockNumber >= entry.fromBlockNumber` uint32 fromBlockNumber; - // The number of operators at `fromBlockNumber` uint32 numOperators; } +} - /** +interface IIndexRegistryEvents is IIndexRegistryTypes { + /* + * @notice Emitted when an operator's index in a quorum is updated. + * @param operatorId The unique identifier of the operator. + * @param quorumNumber The identifier of the quorum. + * @param newOperatorIndex The new index assigned to the operator. + */ + event QuorumIndexUpdate( + bytes32 indexed operatorId, uint8 quorumNumber, uint32 newOperatorIndex + ); +} + +interface IIndexRegistry is IIndexRegistryErrors, IIndexRegistryEvents { + /* + * @notice Returns the special identifier used to indicate a non-existent operator. + * @return The bytes32 constant OPERATOR_DOES_NOT_EXIST_ID. + */ + function OPERATOR_DOES_NOT_EXIST_ID() external pure returns (bytes32); + + /* + * @notice Returns the address of the RegistryCoordinator contract. + * @return The address of the RegistryCoordinator. + */ + function registryCoordinator() external view returns (address); + + /* + * @notice Returns the current index of an operator with ID `operatorId` in quorum `quorumNumber`. + * @dev This mapping is NOT updated when an operator is deregistered, + * so it's possible that an index retrieved from this mapping is inaccurate. + * If you're querying for an operator that might be deregistered, ALWAYS + * check this index against the latest `_operatorIndexHistory` entry. + * @param quorumNumber The identifier of the quorum. + * @param operatorId The unique identifier of the operator. + * @return The current index of the operator. + */ + function currentOperatorIndex( + uint8 quorumNumber, + bytes32 operatorId + ) external view returns (uint32); + + // ACTIONS + + /* * @notice Registers the operator with the specified `operatorId` for the quorums specified by `quorumNumbers`. - * @param operatorId is the id of the operator that is being registered - * @param quorumNumbers is the quorum numbers the operator is registered for - * @return numOperatorsPerQuorum is a list of the number of operators (including the registering operator) in each of the quorums the operator is registered for - * @dev access restricted to the RegistryCoordinator - * @dev Preconditions (these are assumed, not validated in this contract): + * @param operatorId The unique identifier of the operator. + * @param quorumNumbers The quorum numbers to register for. + * @return An array containing a list of the number of operators (including the registering operator) + * in each of the quorums the operator is registered for. + * @dev Access restricted to the RegistryCoordinator. + * @dev Preconditions: * 1) `quorumNumbers` has no duplicates * 2) `quorumNumbers.length` != 0 * 3) `quorumNumbers` is ordered in ascending order @@ -60,12 +88,12 @@ interface IIndexRegistry is IRegistry, IIndexRegistryErrors { bytes calldata quorumNumbers ) external returns (uint32[] memory); - /** + /* * @notice Deregisters the operator with the specified `operatorId` for the quorums specified by `quorumNumbers`. - * @param operatorId is the id of the operator that is being deregistered - * @param quorumNumbers is the quorum numbers the operator is deregistered for - * @dev access restricted to the RegistryCoordinator - * @dev Preconditions (these are assumed, not validated in this contract): + * @param operatorId The unique identifier of the operator. + * @param quorumNumbers The quorum numbers to deregister from. + * @dev Access restricted to the RegistryCoordinator. + * @dev Preconditions: * 1) `quorumNumbers` has no duplicates * 2) `quorumNumbers.length` != 0 * 3) `quorumNumbers` is ordered in ascending order @@ -74,46 +102,77 @@ interface IIndexRegistry is IRegistry, IIndexRegistryErrors { */ function deregisterOperator(bytes32 operatorId, bytes calldata quorumNumbers) external; - /** - * @notice Initialize a quorum by pushing its first quorum update - * @param quorumNumber The number of the new quorum + /* + * @notice Initializes a new quorum `quorumNumber`. + * @param quorumNumber The identifier of the quorum to initialize. */ function initializeQuorum( uint8 quorumNumber ) external; - /// @notice Returns the OperatorUpdate entry for the specified `operatorIndex` and `quorumNumber` at the specified `arrayIndex` + // VIEW + + /* + * @notice Returns the operator update at index `arrayIndex` for operator at index `operatorIndex` in quorum `quorumNumber`. + * @param quorumNumber The identifier of the quorum. + * @param operatorIndex The index of the operator. + * @param arrayIndex The index in the update history. + * @return The operator update entry. + */ function getOperatorUpdateAtIndex( uint8 quorumNumber, uint32 operatorIndex, uint32 arrayIndex ) external view returns (OperatorUpdate memory); - /// @notice Returns the QuorumUpdate entry for the specified `quorumNumber` at the specified `quorumIndex` + /* + * @notice Returns the quorum update at index `quorumIndex` for quorum `quorumNumber`. + * @param quorumNumber The identifier of the quorum. + * @param quorumIndex The index in the quorum's update history. + * @return The quorum update entry. + */ function getQuorumUpdateAtIndex( uint8 quorumNumber, uint32 quorumIndex ) external view returns (QuorumUpdate memory); - /// @notice Returns the most recent OperatorUpdate entry for the specified quorumNumber and operatorIndex - function getLatestOperatorUpdate( - uint8 quorumNumber, - uint32 operatorIndex - ) external view returns (OperatorUpdate memory); - - /// @notice Returns the most recent QuorumUpdate entry for the specified quorumNumber + /* + * @notice Returns the latest quorum update for quorum `quorumNumber`. + * @param quorumNumber The identifier of the quorum. + * @return The most recent quorum update. + */ function getLatestQuorumUpdate( uint8 quorumNumber ) external view returns (QuorumUpdate memory); - /// @notice Returns the current number of operators of this service for `quorumNumber`. - function totalOperatorsForQuorum( - uint8 quorumNumber - ) external view returns (uint32); + /* + * @notice Returns the latest operator update for operator at index `operatorIndex` in quorum `quorumNumber`. + * @param quorumNumber The identifier of the quorum. + * @param operatorIndex The index of the operator. + * @return The most recent operator update. + */ + function getLatestOperatorUpdate( + uint8 quorumNumber, + uint32 operatorIndex + ) external view returns (OperatorUpdate memory); - /// @notice Returns an ordered list of operators of the services for the given `quorumNumber` at the given `blockNumber` + /* + * @notice Returns the list of operators in quorum `quorumNumber` at block `blockNumber`. + * @param quorumNumber The identifier of the quorum. + * @param blockNumber The block number to query. + * @return An array of operator IDs. + */ function getOperatorListAtBlockNumber( uint8 quorumNumber, uint32 blockNumber ) external view returns (bytes32[] memory); + + /* + * @notice Returns the total number of operators in quorum `quorumNumber`. + * @param quorumNumber The identifier of the quorum. + * @return The total number of operators. + */ + function totalOperatorsForQuorum( + uint8 quorumNumber + ) external view returns (uint32); } diff --git a/src/interfaces/IRegistry.sol b/src/interfaces/IRegistry.sol deleted file mode 100644 index 8a483cba..00000000 --- a/src/interfaces/IRegistry.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity >=0.5.0; - -/** - * @title Minimal interface for a `Registry`-type contract. - * @author Layr Labs, Inc. - * @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service - * @notice Functions related to the registration process itself have been intentionally excluded - * because their function signatures may vary significantly. - */ -interface IRegistry { - function registryCoordinator() external view returns (address); -} diff --git a/src/interfaces/IRegistryCoordinator.sol b/src/interfaces/IRegistryCoordinator.sol index 2f6fe5fe..4c9397dc 100644 --- a/src/interfaces/IRegistryCoordinator.sol +++ b/src/interfaces/IRegistryCoordinator.sol @@ -1,73 +1,121 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; +import { + ISlashingRegistryCoordinator, + ISlashingRegistryCoordinatorErrors, + ISlashingRegistryCoordinatorEvents, + ISlashingRegistryCoordinatorTypes +} from "./ISlashingRegistryCoordinator.sol"; import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISignatureUtils.sol"; -import {IBLSApkRegistry} from "./IBLSApkRegistry.sol"; -import {ISlashingRegistryCoordinator} from "./ISlashingRegistryCoordinator.sol"; +import {IBLSApkRegistryTypes} from "./IBLSApkRegistry.sol"; +import {IServiceManager} from "./IServiceManager.sol"; -interface IRegistryCoordinator { - /// Emits when operator sets mode is enabled +interface IRegistryCoordinatorErrors is ISlashingRegistryCoordinatorErrors { + /// @notice Thrown when operator sets mode is already enabled. + error OperatorSetsAlreadyEnabled(); + /// @notice Thrown when a quorum is an operator set quorum. + error OperatorSetQuorum(); + /// @notice Thrown when M2 quorums are already disabled. + error M2QuorumsAlreadyDisabled(); +} + +interface IRegistryCoordinatorTypes is ISlashingRegistryCoordinatorTypes {} + +interface IRegistryCoordinatorEvents is + ISlashingRegistryCoordinatorEvents, + IRegistryCoordinatorTypes +{ + /** + * @notice Emitted when operator sets mode is enabled. + * @dev Emitted in enableOperatorSets(). + */ event OperatorSetsEnabled(); - /// Emits when M2 quorums are disabled + + /** + * @notice Emitted when M2 quorums are disabled. + * @dev Emitted in disableM2QuorumRegistration(). + */ event M2QuorumsDisabled(); +} + +interface IRegistryCoordinator is + IRegistryCoordinatorErrors, + IRegistryCoordinatorEvents, + ISlashingRegistryCoordinator +{ + /** + * @notice Reference to the ServiceManager contract. + * @return The ServiceManager contract interface. + * @dev This is only relevant for Pre-Slashing AVSs + */ + function serviceManager() external view returns (IServiceManager); + + /// ACTIONS /** - * @notice Registers msg.sender as an operator for one or more quorums. If any quorum exceeds its maximum + * @notice Registers an operator for service in specified quorums. If any quorum exceeds its maximum * operator capacity after the operator is registered, this method will fail. - * @param quorumNumbers is an ordered byte array containing the quorum numbers being registered for - * @param socket is the socket of the operator (typically an IP address) - * @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership - * @param operatorSignature is the signature of the operator used by the AVS to register the operator in the delegation manager - * @dev `params` is ignored if the caller has previously registered a public key - * @dev `operatorSignature` is ignored if the operator's status is already REGISTERED + * @param quorumNumbers is an ordered byte array containing the quorum numbers being registered for AVSDirectory. + * @param socket is the socket of the operator (typically an IP address). + * @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership. + * @param operatorSignature is the signature of the operator used by the AVS to register the operator in the delegation manager. + * @dev `params` is ignored if the caller has previously registered a public key. + * @dev `operatorSignature` is ignored if the operator's status is already REGISTERED. + * @dev This function registers operators to the AVSDirectory using the M2-registration pathway. */ function registerOperator( bytes memory quorumNumbers, string memory socket, - IBLSApkRegistry.PubkeyRegistrationParams memory params, + IBLSApkRegistryTypes.PubkeyRegistrationParams memory params, ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature ) external; /** - * @notice Registers msg.sender as an operator for one or more quorums. If any quorum reaches its maximum operator + * @notice Registers an operator while replacing existing operators in full quorums. If any quorum reaches its maximum operator * capacity, `operatorKickParams` is used to replace an old operator with the new one. - * @param quorumNumbers is an ordered byte array containing the quorum numbers being registered for - * @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership + * @param quorumNumbers is an ordered byte array containing the quorum numbers being registered for AVSDirectory. + * @param socket is the socket of the operator (typically an IP address). + * @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership. * @param operatorKickParams used to determine which operator is removed to maintain quorum capacity as the - * operator registers for quorums - * @param churnApproverSignature is the signature of the churnApprover over the `operatorKickParams` - * @param operatorSignature is the signature of the operator used by the AVS to register the operator in the delegation manager - * @dev `params` is ignored if the caller has previously registered a public key - * @dev `operatorSignature` is ignored if the operator's status is already REGISTERED + * operator registers for quorums. + * @param churnApproverSignature is the signature of the churnApprover over the `operatorKickParams`. + * @param operatorSignature is the signature of the operator used by the AVS to register the operator in the delegation manager. + * @dev `params` is ignored if the caller has previously registered a public key. + * @dev `operatorSignature` is ignored if the operator's status is already REGISTERED. + * @dev This function registers operators to the AVSDirectory using the M2-registration pathway. */ function registerOperatorWithChurn( bytes calldata quorumNumbers, string memory socket, - IBLSApkRegistry.PubkeyRegistrationParams memory params, - ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams, + IBLSApkRegistryTypes.PubkeyRegistrationParams memory params, + OperatorKickParam[] memory operatorKickParams, ISignatureUtils.SignatureWithSaltAndExpiry memory churnApproverSignature, ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature ) external; /** - * @notice Deregisters the caller from one or more quorums - * @param quorumNumbers is an ordered byte array containing the quorum numbers being deregistered from + * @notice Deregisters the caller from one or more quorums. The operator will be removed from all registry contracts + * and their quorum bitmap will be updated accordingly. If the operator is deregistered from all quorums, their status + * will be updated to DEREGISTERED. + * @param quorumNumbers is an ordered byte array containing the quorum numbers being deregistered from. + * @dev Will revert if operator is not currently registered for any of the specified quorums. + * @dev This function deregisters operators from the AVSDirectory using the M2-registration pathway. */ function deregisterOperator( bytes memory quorumNumbers ) external; /** - * @notice Enables operator sets mode. This is by default initialized to set `operatorSetsEnabled` to True. - * So this is only meant to be called for existing AVSs that have a existing quorums and a previously deployed - * version of middleware contracts. - * @dev This is only callable by the owner of the RegistryCoordinator + * @notice Enables operator sets mode for the AVS. Once enabled, this cannot be disabled. + * @dev When enabled, all existing quorums are marked as M2 quorums and future quorums must be explicitly + * created as either M2 or operator set quorums. */ function enableOperatorSets() external; /** - * @notice Disables registration to M2 quorums. This is only callable by the owner of the RegistryCoordinator. - * @dev This is only callable if `operatorSetsEnabled` is True. + * @notice Disables M2 quorum registration for the AVS. Once disabled, this cannot be enabled. + * @dev When disabled, all registrations to M2 quorums will revert. Deregistrations are still possible. */ function disableM2QuorumRegistration() external; } diff --git a/src/interfaces/IServiceManager.sol b/src/interfaces/IServiceManager.sol index bfb522af..a93f03f0 100644 --- a/src/interfaces/IServiceManager.sol +++ b/src/interfaces/IServiceManager.sol @@ -13,93 +13,89 @@ import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; interface IServiceManagerErrors { - /// @dev Thrown when a function is called by an address that is not the RegistryCoordinator + /// @notice Thrown when a function is called by an address that is not the RegistryCoordinator. error OnlyRegistryCoordinator(); - /// @dev Thrown when a function is called by an address that is not the RewardsInitiator + /// @notice Thrown when a function is called by an address that is not the RewardsInitiator. error OnlyRewardsInitiator(); - /// @dev Thrown when a function is called by an address that is not the Slasher + /// @notice Thrown when a function is called by an address that is not the StakeRegistry. error OnlyStakeRegistry(); - /// @dev Thrown when a function is called by an address that is not the Slasher + /// @notice Thrown when a function is called by an address that is not the Slasher. error OnlySlasher(); - /// @dev Thrown when a slashing proposal delay has not been met yet. + /// @notice Thrown when a slashing proposal delay has not been met yet. error DelayPeriodNotPassed(); } -/** - * @title Minimal interface for a ServiceManager-type contract that forms the single point for an AVS to push updates to EigenLayer - * @author Layr Labs, Inc. - */ -interface IServiceManager is IServiceManagerUI, IServiceManagerErrors { - // EVENTS +interface IServiceManagerEvents { + /** + * @notice Emitted when the rewards initiator address is updated. + * @param prevRewardsInitiator The previous rewards initiator address. + * @param newRewardsInitiator The new rewards initiator address. + */ event RewardsInitiatorUpdated(address prevRewardsInitiator, address newRewardsInitiator); +} +interface IServiceManager is IServiceManagerUI, IServiceManagerErrors, IServiceManagerEvents { /** - * @notice Creates a new rewards submission to the EigenLayer RewardsCoordinator contract, to be split amongst the - * set of stakers delegated to operators who are registered to this `avs` - * @param rewardsSubmissions The rewards submissions being created - * @dev Only callable by the permissioned rewardsInitiator address - * @dev The duration of the `rewardsSubmission` cannot exceed `MAX_REWARDS_DURATION` - * @dev The tokens are sent to the `RewardsCoordinator` contract - * @dev Strategies must be in ascending order of addresses to check for duplicates + * @notice Creates a new rewards submission to the EigenLayer RewardsCoordinator contract. + * @dev Only callable by the permissioned rewardsInitiator address. + * @dev The duration of the `rewardsSubmission` cannot exceed `MAX_REWARDS_DURATION`. + * @dev The tokens are sent to the `RewardsCoordinator` contract. + * @dev Strategies must be in ascending order of addresses to check for duplicates. * @dev This function will revert if the `rewardsSubmission` is malformed, - * e.g. if the `strategies` and `weights` arrays are of non-equal lengths + * e.g. if the `strategies` and `weights` arrays are of non-equal lengths. + * @param rewardsSubmissions The rewards submissions to be split amongst the set of stakers + * delegated to operators who are registered to this `avs`. */ function createAVSRewardsSubmission( IRewardsCoordinator.RewardsSubmission[] calldata rewardsSubmissions ) external; /** - * - * PERMISSIONCONTROLLER FUNCTIONS - * + * @notice PERMISSIONCONTROLLER FUNCTIONS */ + /** - * @notice Calls `addPendingAdmin` on the `PermissionController` contract - * with `account` being the address of this contract. - * @param admin The address of the admin to add - * @dev Only callable by the owner of the contract + * @notice Calls `addPendingAdmin` on the `PermissionController` contract. + * @dev Only callable by the owner of the contract. + * @param admin The address of the admin to add. */ function addPendingAdmin( address admin ) external; /** - * @notice Calls `removePendingAdmin` on the `PermissionController` contract - * with `account` being the address of this contract. - * @param pendingAdmin The address of the pending admin to remove - * @dev Only callable by the owner of the contract + * @notice Calls `removePendingAdmin` on the `PermissionController` contract. + * @dev Only callable by the owner of the contract. + * @param pendingAdmin The address of the pending admin to remove. */ function removePendingAdmin( address pendingAdmin ) external; /** - * @notice Calls `removeAdmin` on the `PermissionController` contract - * with `account` being the address of this contract. - * @param admin The address of the admin to remove - * @dev Only callable by the owner of the contract + * @notice Calls `removeAdmin` on the `PermissionController` contract. + * @dev Only callable by the owner of the contract. + * @param admin The address of the admin to remove. */ function removeAdmin( address admin ) external; /** - * @notice Calls `setAppointee` on the `PermissionController` contract - * with `account` being the address of this contract. - * @param appointee The address of the appointee to set - * @param target The address of the target to set the appointee for - * @param selector The function selector to set the appointee for - * @dev Only callable by the owner of the contract + * @notice Calls `setAppointee` on the `PermissionController` contract. + * @dev Only callable by the owner of the contract. + * @param appointee The address of the appointee to set. + * @param target The address of the target to set the appointee for. + * @param selector The function selector to set the appointee for. */ function setAppointee(address appointee, address target, bytes4 selector) external; /** - * @notice Calls `removeAppointee` on the `PermissionController` contract - * with `account` being the address of this contract. - * @param appointee The address of the appointee to remove - * @param target The address of the target to remove the appointee for - * @param selector The function selector to remove the appointee for - * @dev Only callable by the owner of the contract + * @notice Calls `removeAppointee` on the `PermissionController` contract. + * @dev Only callable by the owner of the contract. + * @param appointee The address of the appointee to remove. + * @param target The address of the target to remove the appointee for. + * @param selector The function selector to remove the appointee for. */ function removeAppointee(address appointee, address target, bytes4 selector) external; diff --git a/src/interfaces/IServiceManagerUI.sol b/src/interfaces/IServiceManagerUI.sol index 558dca85..a506256b 100644 --- a/src/interfaces/IServiceManagerUI.sol +++ b/src/interfaces/IServiceManagerUI.sol @@ -10,7 +10,9 @@ import {ISignatureUtils} from "eigenlayer-contracts/src/contracts/interfaces/ISi */ interface IServiceManagerUI { /** - * Metadata should follow the format outlined by this example. + * @notice Updates the metadata URI for the AVS, + * @param metadataURI is the metadata URI for the AVS. + * @dev Metadata should follow the format outlined by this example. * { * "name": "EigenLabs AVS 1", * "website": "https://www.eigenlayer.xyz/", @@ -18,15 +20,13 @@ interface IServiceManagerUI { * "logo": "https://holesky-operator-metadata.s3.amazonaws.com/eigenlayer.png", * "twitter": "https://twitter.com/eigenlayer" * } - * @notice Updates the metadata URI for the AVS - * @param _metadataURI is the metadata URI for the AVS */ function updateAVSMetadataURI( - string memory _metadataURI + string memory metadataURI ) external; /** - * @notice Forwards a call to EigenLayer's AVSDirectory contract to confirm operator registration with the AVS + * @notice Forwards a call to EigenLayer's AVSDirectory contract to confirm operator registration with the AVS. * @param operator The address of the operator to register. * @param operatorSignature The signature, salt, and expiry of the operator's signature. */ @@ -36,7 +36,7 @@ interface IServiceManagerUI { ) external; /** - * @notice Forwards a call to EigenLayer's AVSDirectory contract to confirm operator deregistration from the AVS + * @notice Forwards a call to EigenLayer's AVSDirectory contract to confirm operator deregistration from the AVS. * @param operator The address of the operator to deregister. */ function deregisterOperatorFromAVS( @@ -44,24 +44,26 @@ interface IServiceManagerUI { ) external; /** - * @notice Returns the list of strategies that the operator has potentially restaked on the AVS - * @param operator The address of the operator to get restaked strategies for - * @dev This function is intended to be called off-chain + * @notice Returns the list of strategies that the operator has potentially restaked on the AVS. + * @param operator The address of the operator to get restaked strategies for. + * @dev This function is intended to be called off-chain. * @dev No guarantee is made on whether the operator has shares for a strategy in a quorum or uniqueness - * of each element in the returned array. The off-chain service should do that validation separately + * of each element in the returned array. The off-chain service should do that validation separately. */ function getOperatorRestakedStrategies( address operator ) external view returns (address[] memory); /** - * @notice Returns the list of strategies that the AVS supports for restaking - * @dev This function is intended to be called off-chain + * @notice Returns the list of strategies that the AVS supports for restaking. + * @dev This function is intended to be called off-chain. * @dev No guarantee is made on uniqueness of each element in the returned array. - * The off-chain service should do that validation separately + * The off-chain service should do that validation separately. */ function getRestakeableStrategies() external view returns (address[] memory); - /// @notice Returns the EigenLayer AVSDirectory contract. + /** + * @notice Returns the EigenLayer AVSDirectory contract. + */ function avsDirectory() external view returns (address); } diff --git a/src/interfaces/ISlasher.sol b/src/interfaces/ISlasher.sol index b00fd65a..fe388afb 100644 --- a/src/interfaces/ISlasher.sol +++ b/src/interfaces/ISlasher.sol @@ -5,42 +5,30 @@ import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -interface ISlasherEvents { - event SlashingRequested( - uint256 indexed requestId, - address indexed operator, - uint32 indexed operatorSetId, - uint256[] wadsToSlash, - string description - ); - - event SlashingRequestCancelled(uint256 indexed requestId); - - event OperatorSlashed( - uint256 indexed slashingRequestId, - address indexed operator, - uint32 indexed operatorSetId, - uint256[] wadsToSlash, - string description - ); -} - interface ISlasherErrors { - /// @dev Thrown when the caller is not the veto committee + /// @notice Thrown when a caller without veto committee privileges attempts a restricted operation. error OnlyVetoCommittee(); - /// @dev Thrown when the caller is not the slasher + /// @notice Thrown when a caller without slasher privileges attempts a restricted operation. error OnlySlasher(); - /// @dev Thrown when the veto period has passed + /// @notice Thrown when attempting to veto a slashing request after the veto period has expired. error VetoPeriodPassed(); - /// @dev Thrown when the veto period has not passed + /// @notice Thrown when attempting to execute a slashing request before the veto period has ended. error VetoPeriodNotPassed(); - /// @dev Thrown when the slashing request is cancelled + /// @notice Thrown when attempting to interact with a slashing request that has been cancelled. error SlashingRequestIsCancelled(); - /// @dev Thrown when the slashing request was not already requested + /// @notice Thrown when attempting to modify a slashing request that does not exist. error SlashingRequestNotRequested(); } interface ISlasherTypes { + /** + * @notice Represents the current status of a slashing request. + * @dev The status of a slashing request can be one of the following: + * - Null: Default state, no request exists. + * - Requested: Slashing has been requested but not yet executed. + * - Completed: Slashing has been successfully executed. + * - Cancelled: Slashing request was cancelled by veto committee. + */ enum SlashingStatus { Null, Requested, @@ -48,6 +36,12 @@ interface ISlasherTypes { Cancelled } + /** + * @notice Contains all information related to a slashing request. + * @param params The slashing parameters from the allocation manager. + * @param requestTimestamp The timestamp when the slashing request was created. + * @param status The current status of the slashing request. + */ struct SlashingRequest { IAllocationManager.SlashingParams params; uint256 requestTimestamp; @@ -55,4 +49,44 @@ interface ISlasherTypes { } } -interface ISlasher is ISlasherEvents, ISlasherTypes, ISlasherErrors {} +interface ISlasherEvents is ISlasherTypes { + /** + * @notice Emitted when a new slashing request is created. + * @param requestId The unique identifier for the slashing request (indexed). + * @param operator The address of the operator to be slashed (indexed). + * @param operatorSetId The ID of the operator set involved (indexed). + * @param wadsToSlash The amounts to slash from each strategy. + * @param description A human-readable description of the slashing reason. + */ + event SlashingRequested( + uint256 indexed requestId, + address indexed operator, + uint32 indexed operatorSetId, + uint256[] wadsToSlash, + string description + ); + + /** + * @notice Emitted when a slashing request is cancelled by the veto committee. + * @param requestId The unique identifier of the cancelled request (indexed). + */ + event SlashingRequestCancelled(uint256 indexed requestId); + + /** + * @notice Emitted when an operator is successfully slashed. + * @param slashingRequestId The ID of the executed slashing request (indexed). + * @param operator The address of the slashed operator (indexed). + * @param operatorSetId The ID of the operator set involved (indexed). + * @param wadsToSlash The amounts slashed from each strategy. + * @param description A human-readable description of why the operator was slashed. + */ + event OperatorSlashed( + uint256 indexed slashingRequestId, + address indexed operator, + uint32 indexed operatorSetId, + uint256[] wadsToSlash, + string description + ); +} + +interface ISlasher is ISlasherErrors, ISlasherEvents {} diff --git a/src/interfaces/ISlashingRegistryCoordinator.sol b/src/interfaces/ISlashingRegistryCoordinator.sol index 2a8dd58d..70b74af8 100644 --- a/src/interfaces/ISlashingRegistryCoordinator.sol +++ b/src/interfaces/ISlashingRegistryCoordinator.sol @@ -1,178 +1,526 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {IServiceManager} from "./IServiceManager.sol"; import {IBLSApkRegistry} from "./IBLSApkRegistry.sol"; import {IStakeRegistry} from "./IStakeRegistry.sol"; import {IIndexRegistry} from "./IIndexRegistry.sol"; import {BN254} from "../libraries/BN254.sol"; +import {IAllocationManager} from + "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import {IBLSApkRegistry} from "./IBLSApkRegistry.sol"; +import {IStakeRegistry, IStakeRegistryTypes} from "./IStakeRegistry.sol"; +import {IIndexRegistry} from "./IIndexRegistry.sol"; +import {BN254} from "../libraries/BN254.sol"; +import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; -interface IRegistryCoordinatorErrors { +interface ISlashingRegistryCoordinatorErrors { + /// @notice Thrown when array lengths in input parameters don't match. error InputLengthMismatch(); - error OperatorSetsAlreadyEnabled(); - error OperatorSetsNotEnabled(); - error M2QuorumsAlreadyDisabled(); + /// @notice Thrown when an invalid registration type is provided. + error InvalidRegistrationType(); + /// @notice Thrown when non-allocation manager calls restricted function. error OnlyAllocationManager(); + /// @notice Thrown when non-ejector calls restricted function. error OnlyEjector(); + /// @notice Thrown when operating on a non-existent quorum. error QuorumDoesNotExist(); + /// @notice Thrown when registering/deregistering with empty bitmap. error BitmapEmpty(); + /// @notice Thrown when registering for already registered quorums. error AlreadyRegisteredForQuorums(); + /// @notice Thrown when registering before ejection cooldown expires. error CannotReregisterYet(); + /// @notice Thrown when unregistered operator attempts restricted operation. error NotRegistered(); + /// @notice Thrown when operator attempts self-churn. error CannotChurnSelf(); + /// @notice Thrown when operator count doesn't match quorum requirements. error QuorumOperatorCountMismatch(); + /// @notice Thrown when operator has insufficient stake for churn. error InsufficientStakeForChurn(); + /// @notice Thrown when attempting to kick operator above stake threshold. error CannotKickOperatorAboveThreshold(); + /// @notice Thrown when updating to zero bitmap. error BitmapCannotBeZero(); + /// @notice Thrown when deregistering from unregistered quorum. error NotRegisteredForQuorum(); - error MaxQuorumsReached(); - error SaltAlreadyUsed(); - error RegistryCoordinatorSignatureExpired(); + /// @notice Thrown when churn approver salt is already used. error ChurnApproverSaltUsed(); + /// @notice Thrown when operators or quorums list is not sorted ascending. error NotSorted(); - error InvalidRegistrationType(); + /// @notice Thrown when maximum quorum count is reached. + error MaxQuorumsReached(); + /// @notice Thrown when operator set operations are attempted while not enabled. + error OperatorSetsNotEnabled(); } -/** - * @title Interface for a contract that coordinates between various registries for an AVS. - * @author Layr Labs, Inc. - */ -interface ISlashingRegistryCoordinator is IRegistryCoordinatorErrors { - // EVENTS - - /// Emits when an operator is registered - event OperatorRegistered(address indexed operator, bytes32 indexed operatorId); - /// Emits when an operator is deregistered - event OperatorDeregistered(address indexed operator, bytes32 indexed operatorId); - - event OperatorSetParamsUpdated(uint8 indexed quorumNumber, OperatorSetParam operatorSetParams); +interface ISlashingRegistryCoordinatorTypes { + /// @notice Core data structure for tracking operator information. + /// @dev Links an operator's unique identifier with their current registration status. + /// @param operatorId Unique identifier for the operator, typically derived from their BLS public key. + /// @param status Current registration state of the operator in the system. + struct OperatorInfo { + bytes32 operatorId; + OperatorStatus status; + } - event ChurnApproverUpdated(address prevChurnApprover, address newChurnApprover); + /// @notice Records historical changes to an operator's quorum registrations. + /// @dev Used for querying an operator's quorum memberships at specific block numbers. + /// @param updateBlockNumber Block number when this update occurred (inclusive). + /// @param nextUpdateBlockNumber Block number when the next update occurred (exclusive), or 0 if this is the latest update. + /// @param quorumBitmap Bitmap where each bit represents registration in a specific quorum (1 = registered, 0 = not registered). + struct QuorumBitmapUpdate { + uint32 updateBlockNumber; + uint32 nextUpdateBlockNumber; + uint192 quorumBitmap; + } - event EjectorUpdated(address prevEjector, address newEjector); + /// @notice Configuration parameters for operator management within a quorum. + /// @dev All BIPs (Basis Points) values are in relation to BIPS_DENOMINATOR (10000). + /// @param maxOperatorCount Maximum number of operators allowed in the quorum. + /// @param kickBIPsOfOperatorStake Required stake ratio (in BIPs) between new and existing operator for churn. + /// Example: 10500 means new operator needs 105% of existing operator's stake. + /// @param kickBIPsOfTotalStake Minimum stake ratio (in BIPs) of total quorum stake an operator must maintain. + /// Example: 100 means operator needs 1% of total quorum stake to avoid being churned. + struct OperatorSetParam { + uint32 maxOperatorCount; + uint16 kickBIPsOfOperatorStake; + uint16 kickBIPsOfTotalStake; + } - /// @notice emitted when all the operators for a quorum are updated at once - event QuorumBlockNumberUpdated(uint8 indexed quorumNumber, uint256 blocknumber); + /// @notice Parameters for removing an operator during churn. + /// @dev Used in registerOperatorWithChurn to specify which operator to replace. + /// @param quorumNumber The quorum from which to remove the operator. + /// @param operator Address of the operator to be removed. + struct OperatorKickParam { + uint8 quorumNumber; + address operator; + } - // DATA STRUCTURES + /// @notice Represents the registration state of an operator. + /// @dev Used to track an operator's lifecycle in the system. + /// @custom:enum NEVER_REGISTERED The operator has never registered with the system. + /// @custom:enum REGISTERED The operator is currently registered and active. + /// @custom:enum DEREGISTERED The operator was previously registered but has since deregistered. enum OperatorStatus { - // default is NEVER_REGISTERED NEVER_REGISTERED, REGISTERED, DEREGISTERED } + /** + * @notice Enum representing the type of operator registration. + * @custom:enum NORMAL Represents a normal operator registration. + * @custom:enum CHURN Represents an operator registration during a churn event. + */ enum RegistrationType { NORMAL, CHURN } - // STRUCTS - /** - * @notice Data structure for storing info on operators + * @notice Data structure for storing the results of a registerOperator call. + * @dev Contains arrays storing per-quorum information about operator counts and stakes. + * @param numOperatorsPerQuorum For each quorum the operator registered for, stores the number of operators registered. + * @param operatorStakes For each quorum the operator registered for, stores the stake of the operator in the quorum. + * @param totalStakes For each quorum the operator registered for, stores the total stake of the quorum. */ - struct OperatorInfo { - // the id of the operator, which is likely the keccak256 hash of the operator's public key if using BLSRegistry - bytes32 operatorId; - // indicates whether the operator is actively registered for serving the middleware or not - OperatorStatus status; + struct RegisterResults { + uint32[] numOperatorsPerQuorum; + uint96[] operatorStakes; + uint96[] totalStakes; } +} +interface ISlashingRegistryCoordinatorEvents is ISlashingRegistryCoordinatorTypes { /** - * @notice Data structure for storing info on quorum bitmap updates where the `quorumBitmap` is the bitmap of the - * quorums the operator is registered for starting at (inclusive)`updateBlockNumber` and ending at (exclusive) `nextUpdateBlockNumber` - * @dev nextUpdateBlockNumber is initialized to 0 for the latest update + * @notice Emitted when an operator registers for service in one or more quorums. + * @dev Emitted in _registerOperator() and _registerOperatorToOperatorSet(). + * @param operator The address of the registered operator. + * @param operatorId The unique identifier of the operator (BLS public key hash). */ - struct QuorumBitmapUpdate { - uint32 updateBlockNumber; - uint32 nextUpdateBlockNumber; - uint192 quorumBitmap; - } + event OperatorRegistered(address indexed operator, bytes32 indexed operatorId); /** - * @notice Data structure for storing the results of a registerOperator call - * @dev For each quorum the operator registered for, numOperatorsPerQuorum is the number of operators registered - * @dev For each quorum the operator registered for, operatorStakes is the stake of the operator in the quorum - * @dev For each quorum the operator registered for, totalStakes is the total stake of the quorum + * @notice Emitted when an operator deregisters from service in one or more quorums. + * @dev Emitted in _deregisterOperator(). + * @param operator The address of the deregistered operator. + * @param operatorId The unique identifier of the operator (BLS public key hash). */ - struct RegisterResults { - uint32[] numOperatorsPerQuorum; - uint96[] operatorStakes; - uint96[] totalStakes; - } + event OperatorDeregistered(address indexed operator, bytes32 indexed operatorId); /** - * @notice Data structure for storing operator set params for a given quorum. Specifically the - * `maxOperatorCount` is the maximum number of operators that can be registered for the quorum, - * `kickBIPsOfOperatorStake` is the basis points of a new operator needs to have of an operator they are trying to kick from the quorum, - * and `kickBIPsOfTotalStake` is the basis points of the total stake of the quorum that an operator needs to be below to be kicked. + * @notice Emitted when a quorum's operator set parameters are updated. + * @dev Emitted in _setOperatorSetParams(). + * @param quorumNumber The identifier of the quorum being updated. + * @param operatorSetParams The new operator set parameters for the quorum. */ - struct OperatorSetParam { - uint32 maxOperatorCount; - uint16 kickBIPsOfOperatorStake; - uint16 kickBIPsOfTotalStake; - } + event OperatorSetParamsUpdated(uint8 indexed quorumNumber, OperatorSetParam operatorSetParams); /** - * @notice Data structure for the parameters needed to kick an operator from a quorum with number `quorumNumber`, used during registration churn. - * `operator` is the address of the operator to kick + * @notice Emitted when the churn approver address is updated. + * @dev Emitted in _setChurnApprover(). + * @param prevChurnApprover The previous churn approver address. + * @param newChurnApprover The new churn approver address. */ - struct OperatorKickParam { - uint8 quorumNumber; - address operator; - } + event ChurnApproverUpdated(address prevChurnApprover, address newChurnApprover); - /// @notice Returns the operator set params for the given `quorumNumber` - function getOperatorSetParams( - uint8 quorumNumber - ) external view returns (OperatorSetParam memory); - /// @notice the Stake registry contract that will keep track of operators' stakes - function stakeRegistry() external view returns (IStakeRegistry); - /// @notice the BLS Aggregate Pubkey Registry contract that will keep track of operators' BLS aggregate pubkeys per quorum + /** + * @notice Emitted when the ejector address is updated. + * @dev Emitted in _setEjector(). + * @param prevEjector The previous ejector address. + * @param newEjector The new ejector address. + */ + event EjectorUpdated(address prevEjector, address newEjector); + + /** + * @notice Emitted when all operators in a quorum are updated simultaneously. + * @dev Emitted in updateOperatorsForQuorum(). + * @param quorumNumber The identifier of the quorum being updated. + * @param blocknumber The block number at which the quorum update occurred. + */ + event QuorumBlockNumberUpdated(uint8 indexed quorumNumber, uint256 blocknumber); + + /** + * @notice Emitted when an operator's socket is updated. + * @dev Emitted in updateSocket(). + * @param operatorId The unique identifier of the operator (BLS public key hash). + * @param socket The new socket address for the operator (typically an IP address). + */ + event OperatorSocketUpdate(bytes32 indexed operatorId, string socket); +} + +interface ISlashingRegistryCoordinator is + IAVSRegistrar, + ISlashingRegistryCoordinatorErrors, + ISlashingRegistryCoordinatorEvents +{ + /// IMMUTABLES & CONSTANTS + + /** + * @notice EIP-712 typehash for operator churn approval signatures. + * @return The typehash constant. + */ + function OPERATOR_CHURN_APPROVAL_TYPEHASH() external view returns (bytes32); + + /** + * @notice EIP-712 typehash for pubkey registration signatures. + * @return The typehash constant. + */ + function PUBKEY_REGISTRATION_TYPEHASH() external view returns (bytes32); + + /** + * @notice Reference to the BLSApkRegistry contract. + * @return The BLSApkRegistry contract interface. + */ function blsApkRegistry() external view returns (IBLSApkRegistry); - /// @notice the index Registry contract that will keep track of operators' indexes + + /** + * @notice Reference to the StakeRegistry contract. + * @return The StakeRegistry contract interface. + */ + function stakeRegistry() external view returns (IStakeRegistry); + + /** + * @notice Reference to the IndexRegistry contract. + * @return The IndexRegistry contract interface. + */ function indexRegistry() external view returns (IIndexRegistry); /** - * @notice Ejects the provided operator from the provided quorums from the AVS - * @param operator is the operator to eject - * @param quorumNumbers are the quorum numbers to eject the operator from + * @notice Reference to the AllocationManager contract. + * @return The AllocationManager contract interface. + * @dev This is only relevant for Slashing AVSs */ - function ejectOperator(address operator, bytes calldata quorumNumbers) external; + function allocationManager() external view returns (IAllocationManager); + + /// STORAGE - /// @notice Returns the number of quorums the registry coordinator has created + /** + * @notice The total number of quorums that have been created. + * @return The count of quorums. + */ function quorumCount() external view returns (uint8); - /// @notice Returns the operator struct for the given `operator` + /** + * @notice Checks if a churn approver salt has been used. + * @param salt The salt to check. + * @return True if the salt has been used, false otherwise. + */ + function isChurnApproverSaltUsed( + bytes32 salt + ) external view returns (bool); + + /** + * @notice Gets the last block number when all operators in a quorum were updated. + * @param quorumNumber The quorum identifier. + * @return The block number of the last update. + */ + function quorumUpdateBlockNumber( + uint8 quorumNumber + ) external view returns (uint256); + + /** + * @notice Gets the registry contract address at a specific index. + * @param index The index in the registries array. + * @return The registry contract address. + */ + function registries( + uint256 index + ) external view returns (address); + + /** + * @notice The address authorized to approve operator churn operations. + * @return The churn approver address. + */ + function churnApprover() external view returns (address); + + /** + * @notice The address authorized to forcibly eject operators. + * @return The ejector address. + */ + function ejector() external view returns (address); + + /** + * @notice Gets the timestamp of an operator's last ejection. + * @param operator The operator address. + * @return The timestamp of the last ejection. + */ + function lastEjectionTimestamp( + address operator + ) external view returns (uint256); + + /** + * @notice The cooldown period after ejection before an operator can re-register. + * @return The cooldown duration in seconds. + */ + function ejectionCooldown() external view returns (uint256); + + /** + * @notice Checks if a quorum is an M2 quorum. + * @param quorumNumber The quorum identifier. + * @return True if the quorum is M2, false otherwise. + */ + function isM2Quorum( + uint8 quorumNumber + ) external view returns (bool); + + /** + * @notice Whether operator sets mode is enabled. + * @return True if operator sets mode is enabled, false otherwise. + */ + function operatorSetsEnabled() external view returns (bool); + + /// ACTIONS + + /** + * @notice Registers an operator through the allocation manager for operator set quorums. + * @param operator The operator address to register. + * @param operatorSetIds The operator set IDs to register for (corresponds to quorum numbers). + * @param data Additional registration data containing the operator's socket and BLS public key parameters. + * @dev Can only be called by the allocation manager. + * @dev Will revert if operator sets are not enabled or if registering for M2 quorums. + * @dev This function implements the Slashing registration pathway specified by the IAVSRegistrar interface. + */ + function registerOperator( + address operator, + uint32[] memory operatorSetIds, + bytes memory data + ) external; + + /** + * @notice Deregisters an operator through the allocation manager from operator set quorums. + * @param operator The operator address to deregister. + * @param operatorSetIds The operator set IDs to deregister from (corresponds to quorum numbers). + * @dev Can only be called by the allocation manager. + * @dev Will revert if operator sets are not enabled or if deregistering from M2 quorums. + * @dev This function implements the Slashing deregistration pathway specified by the IAVSRegistrar interface. + */ + function deregisterOperator(address operator, uint32[] memory operatorSetIds) external; + + /** + * @notice Updates stake weights for specified operators. If any operator is found to be below + * the minimum stake for their registered quorums, they are deregistered from those quorums. + * @param operators The operators whose stakes should be updated. + * @dev Stakes are queried from the Eigenlayer core DelegationManager contract. + */ + function updateOperators( + address[] memory operators + ) external; + + /** + * @notice For each quorum in `quorumNumbers`, updates the StakeRegistry's view of ALL its registered operators' stakes. + * Each quorum's `quorumUpdateBlockNumber` is also updated, which tracks the most recent block number when ALL registered + * operators were updated. + * @param operatorsPerQuorum for each quorum in `quorumNumbers`, this has a corresponding list of operators to update. + * @param quorumNumbers is an ordered byte array containing the quorum numbers being updated. + * @dev Each list of operator addresses MUST be sorted in ascending order. + * @dev Each list of operator addresses MUST represent the entire list of registered operators for the corresponding quorum. + * @dev Stakes are queried from the Eigenlayer core DelegationManager contract. + * @dev Will revert if an operator registers/deregisters for any quorum in `quorumNumbers` after transaction broadcast but before execution. + */ + function updateOperatorsForQuorum( + address[][] memory operatorsPerQuorum, + bytes calldata quorumNumbers + ) external; + + /** + * @notice Updates the socket of the msg.sender given they are a registered operator. + * @param socket The new socket address for the operator (typically an IP address). + * @dev Will revert if msg.sender is not a registered operator. + */ + function updateSocket( + string memory socket + ) external; + + /** + * @notice Forcibly removes an operator from specified quorums and sets their ejection timestamp. + * @param operator The operator address to eject. + * @param quorumNumbers The quorum numbers to eject the operator from. + * @dev Can only be called by the ejector address. + * @dev The operator cannot re-register until ejectionCooldown period has passed. + */ + function ejectOperator(address operator, bytes memory quorumNumbers) external; + + /** + * @notice Creates a new quorum that tracks total delegated stake for operators. + * @param operatorSetParams Configures the quorum's max operator count and churn parameters. + * @param minimumStake Sets the minimum stake required for an operator to register or remain registered. + * @param strategyParams A list of strategies and multipliers used by the StakeRegistry to calculate + * an operator's stake weight for the quorum. + * @dev For m2 AVS this function has the same behavior as createQuorum before. + * @dev For migrated AVS that enable operator sets this will create a quorum that measures total delegated stake for operator set. + */ + function createTotalDelegatedStakeQuorum( + OperatorSetParam memory operatorSetParams, + uint96 minimumStake, + IStakeRegistryTypes.StrategyParams[] memory strategyParams + ) external; + + /** + * @notice Creates a new quorum that tracks slashable stake for operators. + * @param operatorSetParams Configures the quorum's max operator count and churn parameters. + * @param minimumStake Sets the minimum stake required for an operator to register or remain registered. + * @param strategyParams A list of strategies and multipliers used by the StakeRegistry to calculate + * an operator's stake weight for the quorum. + * @param lookAheadPeriod The number of blocks to look ahead when calculating slashable stake. + * @dev Can only be called when operator sets are enabled. + */ + function createSlashableStakeQuorum( + OperatorSetParam memory operatorSetParams, + uint96 minimumStake, + IStakeRegistryTypes.StrategyParams[] memory strategyParams, + uint32 lookAheadPeriod + ) external; + + /** + * @notice Updates the configuration parameters for an existing operator set quorum. + * @param quorumNumber The identifier of the quorum to update. + * @param operatorSetParams The new operator set parameters to apply. + * @dev Can only be called by the contract owner. + */ + function setOperatorSetParams( + uint8 quorumNumber, + OperatorSetParam memory operatorSetParams + ) external; + + /** + * @notice Updates the address authorized to approve operator churn operations. + * @param _churnApprover The new churn approver address. + * @dev Can only be called by the contract owner. + * @dev The churn approver is responsible for signing off on operator replacements in full quorums. + */ + function setChurnApprover( + address _churnApprover + ) external; + + /** + * @notice Updates the address authorized to forcibly eject operators. + * @param _ejector The new ejector address. + * @dev Can only be called by the contract owner. + * @dev The ejector can force-remove operators from quorums regardless of their stake. + */ + function setEjector( + address _ejector + ) external; + + /** + * @notice Updates the duration operators must wait after ejection before re-registering. + * @param _ejectionCooldown The new cooldown duration in seconds. + * @dev Can only be called by the contract owner. + */ + function setEjectionCooldown( + uint256 _ejectionCooldown + ) external; + + /// VIEW + + /** + * @notice Returns the operator set parameters for a given quorum. + * @param quorumNumber The identifier of the quorum to query. + * @return The OperatorSetParam struct containing max operator count and churn thresholds. + */ + function getOperatorSetParams( + uint8 quorumNumber + ) external view returns (OperatorSetParam memory); + + /** + * @notice Returns the complete operator information for a given address. + * @param operator The operator address to query. + * @return An OperatorInfo struct containing the operator's ID and registration status. + */ function getOperator( address operator ) external view returns (OperatorInfo memory); - /// @notice Returns the operatorId for the given `operator` + /** + * @notice Returns the unique identifier for a given operator address. + * @param operator The operator address to query. + * @return The operator's ID (derived from their BLS public key hash). + */ function getOperatorId( address operator ) external view returns (bytes32); - /// @notice Returns the operator address for the given `operatorId` + /** + * @notice Returns the operator address associated with a given operator ID. + * @param operatorId The unique identifier to look up. + * @return The operator's address. + * @dev Returns address(0) if the ID is not registered. + */ function getOperatorFromId( bytes32 operatorId - ) external view returns (address operator); + ) external view returns (address); - /// @notice Returns the status for the given `operator` + /** + * @notice Returns the current registration status for a given operator. + * @param operator The operator address to query. + * @return The operator's status (NEVER_REGISTERED, REGISTERED, or DEREGISTERED). + */ function getOperatorStatus( address operator ) external view returns (OperatorStatus); - /// @notice Returns the indices of the quorumBitmaps for the provided `operatorIds` at the given `blockNumber` + /** + * @notice Returns the indices needed to look up quorum bitmaps for operators at a specific block. + * @param blockNumber The historical block number to query. + * @param operatorIds Array of operator IDs to get indices for. + * @return Array of indices corresponding to each operator ID. + * @dev Reverts if any operator had not yet registered at the specified block. + * @dev This function is designed to find proper inputs for getQuorumBitmapAtBlockNumberByIndex. + */ function getQuorumBitmapIndicesAtBlockNumber( uint32 blockNumber, bytes32[] memory operatorIds ) external view returns (uint32[] memory); /** - * @notice Returns the quorum bitmap for the given `operatorId` at the given `blockNumber` via the `index` - * @dev reverts if `index` is incorrect + * @notice Returns the quorum bitmap for an operator at a specific historical block. + * @param operatorId The operator's unique identifier. + * @param blockNumber The historical block number to query. + * @param index The index in the operator's bitmap history (from getQuorumBitmapIndicesAtBlockNumber). + * @return The quorum bitmap showing which quorums the operator was registered for. + * @dev Reverts if the index is incorrect for the specified block number. */ function getQuorumBitmapAtBlockNumberByIndex( bytes32 operatorId, @@ -180,60 +528,79 @@ interface ISlashingRegistryCoordinator is IRegistryCoordinatorErrors { uint256 index ) external view returns (uint192); - /// @notice Returns the `index`th entry in the operator with `operatorId`'s bitmap history + /** + * @notice Returns a specific update from an operator's quorum bitmap history. + * @param operatorId The operator's unique identifier. + * @param index The index in the bitmap history to query. + * @return The QuorumBitmapUpdate struct at that index. + */ function getQuorumBitmapUpdateByIndex( bytes32 operatorId, uint256 index ) external view returns (QuorumBitmapUpdate memory); - /// @notice Returns the current quorum bitmap for the given `operatorId` + /** + * @notice Returns the current quorum bitmap for an operator. + * @param operatorId The operator's unique identifier. + * @return A bitmap where each bit represents registration in a specific quorum. + * @dev Returns 0 if the operator is not registered for any quorums. + */ function getCurrentQuorumBitmap( bytes32 operatorId ) external view returns (uint192); - /// @notice Returns the length of the quorum bitmap history for the given `operatorId` + /** + * @notice Returns the number of updates in an operator's bitmap history. + * @param operatorId The operator's unique identifier. + * @return The length of the bitmap history array. + */ function getQuorumBitmapHistoryLength( bytes32 operatorId ) external view returns (uint256); - /// @notice Returns the registry at the desired index - function registries( - uint256 - ) external view returns (address); - - /// @notice Returns the number of registries + /** + * @notice Returns the number of registry contracts managed by this coordinator. + * @return The count of registry contracts (typically 3: stake, BLS, and index). + */ function numRegistries() external view returns (uint256); - /// @notice Returns whether a quorum is an M2 quorum - /// @param quorumNumber The quorum number to check - /// @return True if the quorum is an M2 quorum - function isM2Quorum( - uint8 quorumNumber - ) external view returns (bool); - - /// @notice Returns whether operator sets mode is enabled - function operatorSetsEnabled() external view returns (bool); + /** + * @notice Calculates the digest hash that must be signed by the churn approver. + * @param registeringOperator The address of the operator attempting to register. + * @param registeringOperatorId The unique ID of the registering operator. + * @param operatorKickParams Parameters specifying which operators to replace in full quorums. + * @param salt Random value to ensure signature uniqueness. + * @param expiry Timestamp after which the signature becomes invalid. + * @return The EIP-712 typed data hash to be signed. + */ + function calculateOperatorChurnApprovalDigestHash( + address registeringOperator, + bytes32 registeringOperatorId, + OperatorKickParam[] memory operatorKickParams, + bytes32 salt, + uint256 expiry + ) external view returns (bytes32); /** * @notice Returns the message hash that an operator must sign to register their BLS public key. - * @param operator is the address of the operator registering their BLS public key + * @param operator The address of the operator registering their key. + * @return A point on the G1 curve representing the message hash. */ function pubkeyRegistrationMessageHash( address operator ) external view returns (BN254.G1Point memory); - /// @notice returns the blocknumber the quorum was last updated all at once for all operators - function quorumUpdateBlockNumber( - uint8 quorumNumber - ) external view returns (uint256); - - /// @notice The owner of the registry coordinator + /** + * @notice Returns the address of the contract owner. + * @return The owner's address. + * @dev The owner can update contract configuration and create new quorums. + */ function owner() external view returns (address); /** - * @notice The account identifier for this AVS (used for UAM integration in EigenLayer) - * @dev NOTE: Updating this value will break existing OperatorSets and UAM integration. - * This value should only be set once. + * @notice Returns the account identifier for this AVS (used for UAM integration in EigenLayer) + * @dev NOTE: Updating this value will break existing OperatorSets and UAM integration. This value should only be set once. + * @return The account identifier address */ function accountIdentifier() external view returns (address); } diff --git a/src/interfaces/ISocketUpdater.sol b/src/interfaces/ISocketUpdater.sol deleted file mode 100644 index 921b1a46..00000000 --- a/src/interfaces/ISocketUpdater.sol +++ /dev/null @@ -1,22 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity ^0.8.27; - -/** - * @title Interface for an `ISocketUpdater` where operators can update their sockets. - * @author Layr Labs, Inc. - */ -interface ISocketUpdater { - // EVENTS - - event OperatorSocketUpdate(bytes32 indexed operatorId, string socket); - - // FUNCTIONS - - /** - * @notice Updates the socket of the msg.sender given they are a registered operator - * @param socket is the new socket of the operator - */ - function updateSocket( - string memory socket - ) external; -} diff --git a/src/interfaces/IStakeRegistry.sol b/src/interfaces/IStakeRegistry.sol index 66108a75..b7e74644 100644 --- a/src/interfaces/IStakeRegistry.sol +++ b/src/interfaces/IStakeRegistry.sol @@ -5,13 +5,7 @@ import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; -import {IRegistry} from "./IRegistry.sol"; - -enum StakeType { - TOTAL_DELEGATED, - TOTAL_SLASHABLE -} - +/// @notice Interface containing all error definitions for the StakeRegistry contract. interface IStakeRegistryErrors { /// @dev Thrown when the caller is not the registry coordinator error OnlySlashingRegistryCoordinator(); @@ -19,143 +13,233 @@ interface IStakeRegistryErrors { error OnlySlashingRegistryCoordinatorOwner(); /// @dev Thrown when the stake is below the minimum required for a quorum error BelowMinimumStakeRequirement(); - /// @dev Thrown when a quorum being created already exists. + /// @notice Thrown when attempting to create a quorum that already exists. error QuorumAlreadyExists(); - /// @dev Thrown when a quorum does not exist. + /// @notice Thrown when attempting to interact with a quorum that does not exist. error QuorumDoesNotExist(); - /// @dev Thrown when two array parameters have mismatching lengths. + /// @notice Thrown when two array parameters have mismatching lengths. error InputArrayLengthMismatch(); - /// @dev Thrown when input arrays length is zero. + /// @notice Thrown when an input array has zero length. error InputArrayLengthZero(); - /// @dev Thrown when a duplicate strategy is provided in input array. + /// @notice Thrown when a duplicate strategy is provided in an input array. error InputDuplicateStrategy(); - /// @dev Thrown when multiplier input is zero. + /// @notice Thrown when a multiplier input is zero. error InputMultiplierZero(); - /// @dev Thrown when the blocknumber provided is not >= the provided StakeUpdate's updateBlockNumber - /// or if the blocknumber provided is not the nextUpdateBlockNumber + /// @notice Thrown when the provided block number is invalid for the stake update. error InvalidBlockNumber(); - /// @dev Thrown when the quorum has no stake history at block number provided. + /// @notice Thrown when attempting to access stake history that doesn't exist for a quorum. error EmptyStakeHistory(); } -/** - * @title Interface for a `Registry` that keeps track of stakes of operators for up to 256 quorums. - * @author Layr Labs, Inc. - */ -interface IStakeRegistry is IRegistry, IStakeRegistryErrors { - // DATA STRUCTURES +interface IStakeRegistryTypes { + /// @notice Defines the type of stake being tracked. + /// @param TOTAL_DELEGATED Represents the total delegated stake. + /// @param TOTAL_SLASHABLE Represents the total slashable stake. + enum StakeType { + TOTAL_DELEGATED, + TOTAL_SLASHABLE + } - /// @notice struct used to store the stakes of an individual operator or the sum of all operators' stakes, for storage + /// @notice Stores stake information for an operator or total stakes at a specific block. + /// @param updateBlockNumber The block number at which the stake amounts were updated. + /// @param nextUpdateBlockNumber The block number at which the next update occurred (0 if no next update). + /// @param stake The stake weight for the quorum. struct StakeUpdate { - // the block number at which the stake amounts were updated and stored uint32 updateBlockNumber; - // the block number at which the *next update* occurred. - /// @notice This entry has the value **0** until another update takes place. uint32 nextUpdateBlockNumber; - // stake weight for the quorum uint96 stake; } - /** - * @notice In weighing a particular strategy, the amount of underlying asset for that strategy is - * multiplied by its multiplier, then divided by WEIGHTING_DIVISOR - */ + /// @notice Parameters for weighing a particular strategy's stake. + /// @param strategy The strategy contract address. + /// @param multiplier The weight multiplier applied to the strategy's stake. struct StrategyParams { IStrategy strategy; uint96 multiplier; } +} - // EVENTS - - /// @notice emitted whenever the stake of `operator` is updated +interface IStakeRegistryEvents is IStakeRegistryTypes { + /** + * @notice Emitted when an operator's stake is updated. + * @param operatorId The unique identifier of the operator (indexed). + * @param quorumNumber The quorum number for which the stake was updated. + * @param stake The new stake amount. + */ event OperatorStakeUpdate(bytes32 indexed operatorId, uint8 quorumNumber, uint96 stake); - /// @notice emitted when the look ahead time(in blocks) for checking operator shares is updated + /** + * @notice Emitted when the look ahead period for checking operator shares is updated. + * @param oldLookAheadBlocks The previous look ahead period. + * @param newLookAheadBlocks The new look ahead period. + */ event LookAheadPeriodChanged(uint32 oldLookAheadBlocks, uint32 newLookAheadBlocks); - /// @notice emitted when the stake type is updated + /** + * @notice Emitted when the stake type is updated. + * @param newStakeType The new stake type being set. + */ event StakeTypeSet(StakeType newStakeType); - /// @notice emitted when the minimum stake for a quorum is updated + + /** + * @notice Emitted when the minimum stake for a quorum is updated. + * @param quorumNumber The quorum number being updated (indexed). + * @param minimumStake The new minimum stake requirement. + */ event MinimumStakeForQuorumUpdated(uint8 indexed quorumNumber, uint96 minimumStake); - /// @notice emitted when a new quorum is created + + /** + * @notice Emitted when a new quorum is created. + * @param quorumNumber The number of the newly created quorum (indexed). + */ event QuorumCreated(uint8 indexed quorumNumber); - /// @notice emitted when `strategy` has been added to the array at `strategyParams[quorumNumber]` + + /** + * @notice Emitted when a strategy is added to a quorum. + * @param quorumNumber The quorum number the strategy was added to (indexed). + * @param strategy The strategy contract that was added. + */ event StrategyAddedToQuorum(uint8 indexed quorumNumber, IStrategy strategy); - /// @notice emitted when `strategy` has removed from the array at `strategyParams[quorumNumber]` + + /** + * @notice Emitted when a strategy is removed from a quorum. + * @param quorumNumber The quorum number the strategy was removed from (indexed). + * @param strategy The strategy contract that was removed. + */ event StrategyRemovedFromQuorum(uint8 indexed quorumNumber, IStrategy strategy); - /// @notice emitted when `strategy` has its `multiplier` updated in the array at `strategyParams[quorumNumber]` + + /** + * @notice Emitted when a strategy's multiplier is updated. + * @param quorumNumber The quorum number for the strategy update (indexed). + * @param strategy The strategy contract being updated. + * @param multiplier The new multiplier value. + */ event StrategyMultiplierUpdated( uint8 indexed quorumNumber, IStrategy strategy, uint256 multiplier ); +} + +interface IStakeRegistry is IStakeRegistryErrors, IStakeRegistryEvents { + /// STATE + + /** + * @notice Returns the EigenLayer delegation manager contract. + */ + function delegation() external view returns (IDelegationManager); + + /// ACTIONS /** * @notice Registers the `operator` with `operatorId` for the specified `quorumNumbers`. * @param operator The address of the operator to register. * @param operatorId The id of the operator to register. * @param quorumNumbers The quorum numbers the operator is registering for, where each byte is an 8 bit integer quorumNumber. - * @return The operator's current stake for each quorum, and the total stake for each quorum - * @dev access restricted to the RegistryCoordinator + * @return operatorStakes The operator's current stake for each quorum. + * @return totalStakes The total stake for each quorum. + * @dev Access restricted to the RegistryCoordinator. * @dev Preconditions (these are assumed, not validated in this contract): - * 1) `quorumNumbers` has no duplicates - * 2) `quorumNumbers.length` != 0 - * 3) `quorumNumbers` is ordered in ascending order - * 4) the operator is not already registered + * 1) `quorumNumbers` has no duplicates. + * 2) `quorumNumbers.length` != 0. + * 3) `quorumNumbers` is ordered in ascending order. + * 4) The operator is not already registered. */ function registerOperator( address operator, bytes32 operatorId, bytes memory quorumNumbers - ) external returns (uint96[] memory, uint96[] memory); + ) external returns (uint96[] memory operatorStakes, uint96[] memory totalStakes); /** * @notice Deregisters the operator with `operatorId` for the specified `quorumNumbers`. * @param operatorId The id of the operator to deregister. * @param quorumNumbers The quorum numbers the operator is deregistering from, where each byte is an 8 bit integer quorumNumber. - * @dev access restricted to the RegistryCoordinator + * @dev Access restricted to the RegistryCoordinator. * @dev Preconditions (these are assumed, not validated in this contract): - * 1) `quorumNumbers` has no duplicates - * 2) `quorumNumbers.length` != 0 - * 3) `quorumNumbers` is ordered in ascending order - * 4) the operator is not already deregistered - * 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for + * 1) `quorumNumbers` has no duplicates. + * 2) `quorumNumbers.length` != 0. + * 3) `quorumNumbers` is ordered in ascending order. + * 4) The operator is not already deregistered. + * 5) `quorumNumbers` is a subset of the quorumNumbers that the operator is registered for. */ function deregisterOperator(bytes32 operatorId, bytes memory quorumNumbers) external; /** - * @notice Initialize a new quorum created by the registry coordinator by setting strategies, weights, and minimum stake + * @notice Called by the registry coordinator to update an operator's stake for one or more quorums. + * @param operator The address of the operator to update. + * @param operatorId The id of the operator to update. + * @param quorumNumbers The quorum numbers to update the stake for. + * @return A bitmap of quorums where the operator no longer meets the minimum stake and should be deregistered. + */ + function updateOperatorStake( + address operator, + bytes32 operatorId, + bytes calldata quorumNumbers + ) external returns (uint192); + + /** + * @notice Initialize a new quorum created by the registry coordinator by setting strategies, weights, and minimum stake. + * @param quorumNumber The number of the quorum to initialize. + * @param minimumStake The minimum stake required for the quorum. + * @param strategyParams The initial strategy parameters for the quorum. */ - /// @notice Initialize a new quorum and push its first history update function initializeDelegatedStakeQuorum( uint8 quorumNumber, uint96 minimumStake, - StrategyParams[] memory _strategyParams + StrategyParams[] memory strategyParams ) external; - /// @notice Initialize a new quorum and push its first history update + /** + * @notice Initialize a new quorum and push its first history update. + * @param quorumNumber The number of the quorum to initialize. + * @param minimumStake The minimum stake required for the quorum. + * @param lookAheadPeriod The look ahead period for checking operator shares. + * @param strategyParams The initial strategy parameters for the quorum. + */ function initializeSlashableStakeQuorum( uint8 quorumNumber, uint96 minimumStake, uint32 lookAheadPeriod, - StrategyParams[] memory _strategyParams + StrategyParams[] memory strategyParams ) external; - /// @notice Adds new strategies and the associated multipliers to the @param quorumNumber. + /** + * @notice Sets the minimum stake requirement for a quorum `quorumNumber`. + * @param quorumNumber The quorum number to set the minimum stake for. + * @param minimumStake The new minimum stake requirement. + */ + function setMinimumStakeForQuorum(uint8 quorumNumber, uint96 minimumStake) external; + + /** + * @notice Sets the look ahead time to `lookAheadBlocks` for checking operator shares for a specific quorum. + * @param quorumNumber The quorum number to set the look ahead period for. + * @param lookAheadBlocks The number of blocks to look ahead when checking shares. + */ + function setSlashableStakeLookahead(uint8 quorumNumber, uint32 lookAheadBlocks) external; + + /** + * @notice Adds new strategies and their associated multipliers to the specified quorum. + * @dev Checks to make sure that the *same* strategy cannot be added multiple times (checks against both against existing and new strategies). + * @dev This function has no check to make sure that the strategies for a single quorum have the same underlying asset. This is a concious choice, + * since a middleware may want, e.g., a stablecoin quorum that accepts USDC, USDT, DAI, etc. as underlying assets and trades them as "equivalent". + * @param quorumNumber The quorum number to add strategies to. + * @param strategyParams The strategy parameters to add. + */ function addStrategies(uint8 quorumNumber, StrategyParams[] memory strategyParams) external; /** - * @notice This function is used for removing strategies and their associated weights from the - * mapping strategyParams for a specific @param quorumNumber. - * @dev higher indices should be *first* in the list of @param indicesToRemove, since otherwise - * the removal of lower index entries will cause a shift in the indices of the other strategiesToRemove + * @notice Removes strategies and their associated weights from the specified quorum. + * @param quorumNumber The quorum number to remove strategies from. + * @param indicesToRemove The indices of strategies to remove. + * @dev Higher indices should be *first* in the list of `indicesToRemove`, since otherwise + * the removal of lower index entries will cause a shift in the indices of the other strategiesToRemove. */ function removeStrategies(uint8 quorumNumber, uint256[] calldata indicesToRemove) external; /** - * @notice This function is used for modifying the weights of strategies that are already in the - * mapping strategyParams for a specific - * @param quorumNumber is the quorum number to change the strategy for - * @param strategyIndices are the indices of the strategies to change - * @param newMultipliers are the new multipliers for the strategies + * @notice Modifies the weights of strategies that are already in the mapping strategyParams. + * @param quorumNumber The quorum number to change the strategy for. + * @param strategyIndices The indices of the strategies to change. + * @param newMultipliers The new multipliers for the strategies. */ function modifyStrategyParams( uint8 quorumNumber, @@ -163,31 +247,64 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { uint96[] calldata newMultipliers ) external; - /// @notice Constant used as a divisor in calculating weights. - function WEIGHTING_DIVISOR() external pure returns (uint256); + /// VIEW - /// @notice Returns the EigenLayer delegation manager contract. - function delegation() external view returns (IDelegationManager); + /** + * @notice Returns whether a quorum is an operator set quorum. + * @param quorumNumber The quorum number to query. + * @return Whether the quorum is an operator set quorum. + */ + function isOperatorSetQuorum( + uint8 quorumNumber + ) external view returns (bool); - /// @notice In order to register for a quorum i, an operator must have at least `minimumStakeForQuorum[i]` + /** + * @notice Returns the minimum stake requirement for a quorum `quorumNumber`. + * @dev In order to register for a quorum i, an operator must have at least `minimumStakeForQuorum[i]`. + * @param quorumNumber The quorum number to query. + * @return The minimum stake requirement. + */ function minimumStakeForQuorum( uint8 quorumNumber ) external view returns (uint96); - /// @notice Returns the length of the dynamic array stored in `strategyParams[quorumNumber]`. + /** + * @notice Returns the length of the dynamic array stored in `strategyParams[quorumNumber]`. + * @param quorumNumber The quorum number to query. + * @return The number of strategies for the quorum. + */ function strategyParamsLength( uint8 quorumNumber ) external view returns (uint256); - /// @notice Returns the strategy and weight multiplier for the `index`'th strategy in the quorum `quorumNumber` + /** + * @notice Returns the strategy and weight multiplier for the `index`'th strategy in the quorum. + * @param quorumNumber The quorum number to query. + * @param index The index of the strategy to query. + * @return The strategy parameters. + */ function strategyParamsByIndex( uint8 quorumNumber, uint256 index ) external view returns (StrategyParams memory); /** - * @notice This function computes the total weight of the @param operator in the quorum @param quorumNumber. - * @dev reverts in the case that `quorumNumber` is greater than or equal to `quorumCount` + * @notice Returns the length of the stake history for an operator in a quorum. + * @param operatorId The id of the operator to query. + * @param quorumNumber The quorum number to query. + * @return The length of the stake history array. + */ + function getStakeHistoryLength( + bytes32 operatorId, + uint8 quorumNumber + ) external view returns (uint256); + + /** + * @notice Computes the total weight of the operator in the specified quorum. + * @param quorumNumber The quorum number to query. + * @param operator The operator address to query. + * @return The total weight of the operator. + * @dev Reverts if `quorumNumber` is greater than or equal to `quorumCount`. */ function weightOfOperatorForQuorum( uint8 quorumNumber, @@ -195,47 +312,66 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { ) external view returns (uint96); /** - * @notice Returns the entire `operatorIdToStakeHistory[operatorId][quorumNumber]` array. + * @notice Returns the entire stake history array for an operator in a quorum. * @param operatorId The id of the operator of interest. * @param quorumNumber The quorum number to get the stake for. + * @return The array of stake updates. */ function getStakeHistory( bytes32 operatorId, uint8 quorumNumber ) external view returns (StakeUpdate[] memory); + /** + * @notice Returns the length of the total stake history for a quorum. + * @param quorumNumber The quorum number to query. + * @return The length of the total stake history array. + */ function getTotalStakeHistoryLength( uint8 quorumNumber ) external view returns (uint256); /** - * @notice Returns the `index`-th entry in the dynamic array of total stake, `totalStakeHistory` for quorum `quorumNumber`. - * @param quorumNumber The quorum number to get the stake for. - * @param index Array index for lookup, within the dynamic array `totalStakeHistory[quorumNumber]`. + * @notice Returns the stake update at the specified index in the total stake history. + * @param quorumNumber The quorum number to query. + * @param index The index to query. + * @return The stake update at the specified index. */ function getTotalStakeUpdateAtIndex( uint8 quorumNumber, uint256 index ) external view returns (StakeUpdate memory); - /// @notice Returns the indices of the operator stakes for the provided `quorumNumber` at the given `blockNumber` + /** + * @notice Returns the index of the operator's stake update at the specified block number. + * @param operatorId The id of the operator to query. + * @param quorumNumber The quorum number to query. + * @param blockNumber The block number to query. + * @return The index of the stake update. + */ function getStakeUpdateIndexAtBlockNumber( bytes32 operatorId, uint8 quorumNumber, uint32 blockNumber ) external view returns (uint32); - /// @notice Returns the indices of the total stakes for the provided `quorumNumbers` at the given `blockNumber` + /** + * @notice Returns the indices of total stakes for the provided quorums at the given block number. + * @param blockNumber The block number to query. + * @param quorumNumbers The quorum numbers to query. + * @return The array of stake update indices. + */ function getTotalStakeIndicesAtBlockNumber( uint32 blockNumber, bytes calldata quorumNumbers ) external view returns (uint32[] memory); /** - * @notice Returns the `index`-th entry in the `operatorIdToStakeHistory[operatorId][quorumNumber]` array. - * @param quorumNumber The quorum number to get the stake for. - * @param operatorId The id of the operator of interest. - * @param index Array index for lookup, within the dynamic array `operatorIdToStakeHistory[operatorId][quorumNumber]`. + * @notice Returns the stake update at the specified index for an operator in a quorum. + * @param quorumNumber The quorum number to query. + * @param operatorId The id of the operator to query. + * @param index The index to query. + * @return The stake update at the specified index. * @dev Function will revert if `index` is out-of-bounds. */ function getStakeUpdateAtIndex( @@ -245,8 +381,11 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { ) external view returns (StakeUpdate memory); /** - * @notice Returns the most recent stake weight for the `operatorId` for a certain quorum - * @dev Function returns an StakeUpdate struct with **every entry equal to 0** in the event that the operator has no stake history + * @notice Returns the most recent stake update for an operator in a quorum. + * @param operatorId The id of the operator to query. + * @param quorumNumber The quorum number to query. + * @return The most recent stake update. + * @dev Returns a StakeUpdate struct with all entries equal to 0 if the operator has no stake history. */ function getLatestStakeUpdate( bytes32 operatorId, @@ -254,15 +393,14 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { ) external view returns (StakeUpdate memory); /** - * @notice Returns the stake weight corresponding to `operatorId` for quorum `quorumNumber`, at the - * `index`-th entry in the `operatorIdToStakeHistory[operatorId][quorumNumber]` array if the entry - * corresponds to the operator's stake at `blockNumber`. Reverts otherwise. - * @param quorumNumber The quorum number to get the stake for. - * @param operatorId The id of the operator of interest. - * @param index Array index for lookup, within the dynamic array `operatorIdToStakeHistory[operatorId][quorumNumber]`. - * @param blockNumber Block number to make sure the stake is from. + * @notice Returns the stake at the specified block number and index for an operator in a quorum. + * @param quorumNumber The quorum number to query. + * @param blockNumber The block number to query. + * @param operatorId The id of the operator to query. + * @param index The index to query. + * @return The stake amount. * @dev Function will revert if `index` is out-of-bounds. - * @dev used the BLSSignatureChecker to get past stakes of signing operators + * @dev Used by the BLSSignatureChecker to get past stakes of signing operators. */ function getStakeAtBlockNumberAndIndex( uint8 quorumNumber, @@ -272,14 +410,13 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { ) external view returns (uint96); /** - * @notice Returns the total stake weight for quorum `quorumNumber`, at the `index`-th entry in the - * `totalStakeHistory[quorumNumber]` array if the entry corresponds to the total stake at `blockNumber`. - * Reverts otherwise. - * @param quorumNumber The quorum number to get the stake for. - * @param index Array index for lookup, within the dynamic array `totalStakeHistory[quorumNumber]`. - * @param blockNumber Block number to make sure the stake is from. + * @notice Returns the total stake at the specified block number and index for a quorum. + * @param quorumNumber The quorum number to query. + * @param blockNumber The block number to query. + * @param index The index to query. + * @return The total stake amount. * @dev Function will revert if `index` is out-of-bounds. - * @dev used the BLSSignatureChecker to get past stakes of signing operators + * @dev Used by the BLSSignatureChecker to get past stakes of signing operators. */ function getTotalStakeAtBlockNumberFromIndex( uint8 quorumNumber, @@ -288,15 +425,24 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { ) external view returns (uint96); /** - * @notice Returns the most recent stake weight for the `operatorId` for quorum `quorumNumber` - * @dev Function returns weight of **0** in the event that the operator has no stake history + * @notice Returns the current stake for an operator in a quorum. + * @param operatorId The id of the operator to query. + * @param quorumNumber The quorum number to query. + * @return The current stake amount. + * @dev Returns 0 if the operator has no stake history. */ function getCurrentStake( bytes32 operatorId, uint8 quorumNumber ) external view returns (uint96); - /// @notice Returns the stake of the operator for the provided `quorumNumber` at the given `blockNumber` + /** + * @notice Returns the stake of an operator at a specific block number. + * @param operatorId The id of the operator to query. + * @param quorumNumber The quorum number to query. + * @param blockNumber The block number to query. + * @return The stake amount at the specified block. + */ function getStakeAtBlockNumber( bytes32 operatorId, uint8 quorumNumber, @@ -304,25 +450,12 @@ interface IStakeRegistry is IRegistry, IStakeRegistryErrors { ) external view returns (uint96); /** - * @notice Returns the stake weight from the latest entry in `_totalStakeHistory` for quorum `quorumNumber`. + * @notice Returns the current total stake for a quorum. + * @param quorumNumber The quorum number to query. + * @return The current total stake amount. * @dev Will revert if `_totalStakeHistory[quorumNumber]` is empty. */ function getCurrentTotalStake( uint8 quorumNumber ) external view returns (uint96); - - /** - * @notice Called by the registry coordinator to update an operator's stake for one - * or more quorums. - * - * If the operator no longer has the minimum stake required for a quorum, they are - * added to the - * @return A bitmap of quorums where the operator no longer meets the minimum stake - * and should be deregistered. - */ - function updateOperatorStake( - address operator, - bytes32 operatorId, - bytes calldata quorumNumbers - ) external returns (uint192); } diff --git a/src/libraries/BN254.sol b/src/libraries/BN254.sol index 7a167efc..df4b8248 100644 --- a/src/libraries/BN254.sol +++ b/src/libraries/BN254.sol @@ -30,10 +30,10 @@ pragma solidity ^0.8.27; library BN254 { // modulus for the underlying field F_p of the elliptic curve uint256 internal constant FP_MODULUS = - 21_888_242_871_839_275_222_246_405_745_257_275_088_696_311_157_297_823_662_689_037_894_645_226_208_583; + 21888242871839275222246405745257275088696311157297823662689037894645226208583; // modulus for the underlying field F_r of the elliptic curve uint256 internal constant FR_MODULUS = - 21_888_242_871_839_275_222_246_405_745_257_275_088_548_364_400_416_034_343_698_204_186_575_808_495_617; + 21888242871839275222246405745257275088548364400416034343698204186575808495617; struct G1Point { uint256 X; @@ -64,13 +64,13 @@ library BN254 { // generator of group G2 /// @dev Generator point in F_q2 is of the form: (x0 + ix1, y0 + iy1). uint256 internal constant G2x1 = - 11_559_732_032_986_387_107_991_004_021_392_285_783_925_812_861_821_192_530_917_403_151_452_391_805_634; + 11559732032986387107991004021392285783925812861821192530917403151452391805634; uint256 internal constant G2x0 = - 10_857_046_999_023_057_135_944_570_762_232_829_481_370_756_359_578_518_086_990_519_993_285_655_852_781; + 10857046999023057135944570762232829481370756359578518086990519993285655852781; uint256 internal constant G2y1 = - 4_082_367_875_863_433_681_332_203_403_145_435_568_316_851_327_593_401_208_105_741_076_214_120_093_531; + 4082367875863433681332203403145435568316851327593401208105741076214120093531; uint256 internal constant G2y0 = - 8_495_653_923_123_431_417_604_973_247_489_272_438_418_190_587_263_600_148_770_280_649_306_958_101_930; + 8495653923123431417604973247489272438418190587263600148770280649306958101930; /// @notice returns the G2 generator /// @dev mind the ordering of the 1s and 0s! @@ -84,13 +84,13 @@ library BN254 { // negation of the generator of group G2 /// @dev Generator point in F_q2 is of the form: (x0 + ix1, y0 + iy1). uint256 internal constant nG2x1 = - 11_559_732_032_986_387_107_991_004_021_392_285_783_925_812_861_821_192_530_917_403_151_452_391_805_634; + 11559732032986387107991004021392285783925812861821192530917403151452391805634; uint256 internal constant nG2x0 = - 10_857_046_999_023_057_135_944_570_762_232_829_481_370_756_359_578_518_086_990_519_993_285_655_852_781; + 10857046999023057135944570762232829481370756359578518086990519993285655852781; uint256 internal constant nG2y1 = - 17_805_874_995_975_841_540_914_202_342_111_839_520_379_459_829_704_422_454_583_296_818_431_106_115_052; + 17805874995975841540914202342111839520379459829704422454583296818431106115052; uint256 internal constant nG2y0 = - 13_392_588_948_715_843_804_641_432_497_768_002_650_278_120_570_034_223_513_918_757_245_338_268_106_653; + 13392588948715843804641432497768002650278120570034223513918757245338268106653; function negGeneratorG2() internal pure returns (G2Point memory) { return G2Point([nG2x1, nG2x0], [nG2y1, nG2y0]); diff --git a/src/libraries/QuorumBitmapHistoryLib.sol b/src/libraries/QuorumBitmapHistoryLib.sol index 677c8678..d709b035 100644 --- a/src/libraries/QuorumBitmapHistoryLib.sol +++ b/src/libraries/QuorumBitmapHistoryLib.sol @@ -1,7 +1,10 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.27; -import {ISlashingRegistryCoordinator} from "../interfaces/ISlashingRegistryCoordinator.sol"; +import { + ISlashingRegistryCoordinator, + ISlashingRegistryCoordinatorTypes +} from "../interfaces/ISlashingRegistryCoordinator.sol"; /// @title QuorumBitmapHistoryLib /// @notice This library operates on the _operatorBitmapHistory in the RegistryCoordinator @@ -119,7 +122,7 @@ library QuorumBitmapHistoryLib { if (historyLength == 0) { // No prior bitmap history - push our first entry self[operatorId].push( - ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ updateBlockNumber: uint32(block.number), nextUpdateBlockNumber: 0, quorumBitmap: newBitmap @@ -139,7 +142,7 @@ library QuorumBitmapHistoryLib { } else { lastUpdate.nextUpdateBlockNumber = uint32(block.number); self[operatorId].push( - ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ updateBlockNumber: uint32(block.number), nextUpdateBlockNumber: 0, quorumBitmap: newBitmap diff --git a/src/unaudited/ECDSAServiceManagerBase.sol b/src/unaudited/ECDSAServiceManagerBase.sol index 57a4067e..2a978b0b 100644 --- a/src/unaudited/ECDSAServiceManagerBase.sol +++ b/src/unaudited/ECDSAServiceManagerBase.sol @@ -12,7 +12,7 @@ import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy import {IStakeRegistry} from "../interfaces/IStakeRegistry.sol"; import {IRewardsCoordinator} from "eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; -import {Quorum} from "../interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; +import {IECDSAStakeRegistryTypes} from "../interfaces/IECDSAStakeRegistry.sol"; import {ECDSAStakeRegistry} from "../unaudited/ECDSAStakeRegistry.sol"; import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; import {IAllocationManager} from @@ -197,7 +197,7 @@ abstract contract ECDSAServiceManagerBase is IServiceManager, OwnableUpgradeable * @return strategies An array of addresses representing the strategies in the current quorum. */ function _getRestakeableStrategies() internal view virtual returns (address[] memory) { - Quorum memory quorum = ECDSAStakeRegistry(stakeRegistry).quorum(); + IECDSAStakeRegistryTypes.Quorum memory quorum = ECDSAStakeRegistry(stakeRegistry).quorum(); address[] memory strategies = new address[](quorum.strategies.length); for (uint256 i = 0; i < quorum.strategies.length; i++) { strategies[i] = address(quorum.strategies[i].strategy); @@ -226,7 +226,7 @@ abstract contract ECDSAServiceManagerBase is IServiceManager, OwnableUpgradeable function _getOperatorRestakedStrategies( address _operator ) internal view virtual returns (address[] memory) { - Quorum memory quorum = ECDSAStakeRegistry(stakeRegistry).quorum(); + IECDSAStakeRegistryTypes.Quorum memory quorum = ECDSAStakeRegistry(stakeRegistry).quorum(); uint256 count = quorum.strategies.length; IStrategy[] memory strategies = new IStrategy[](count); for (uint256 i; i < count; i++) { diff --git a/src/unaudited/ECDSAStakeRegistry.sol b/src/unaudited/ECDSAStakeRegistry.sol index edbb6778..c961c83e 100644 --- a/src/unaudited/ECDSAStakeRegistry.sol +++ b/src/unaudited/ECDSAStakeRegistry.sol @@ -1,7 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.27; -import {ECDSAStakeRegistryStorage, Quorum, StrategyParams} from "./ECDSAStakeRegistryStorage.sol"; +import { + IECDSAStakeRegistry, + ECDSAStakeRegistryStorage, + IECDSAStakeRegistryTypes +} from "./ECDSAStakeRegistryStorage.sol"; import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import {IDelegationManager} from "eigenlayer-contracts/src/contracts/interfaces/IDelegationManager.sol"; @@ -37,206 +41,168 @@ contract ECDSAStakeRegistry is /// @notice Initializes the contract with the given parameters. /// @param _serviceManager The address of the service manager. - /// @param _thresholdWeight The threshold weight in basis points. - /// @param _quorum The quorum struct containing the details of the quorum thresholds. + /// @param thresholdWeight The threshold weight in basis points. + /// @param quorum The quorum struct containing the details of the quorum thresholds. function initialize( address _serviceManager, - uint256 _thresholdWeight, - Quorum memory _quorum + uint256 thresholdWeight, + IECDSAStakeRegistryTypes.Quorum memory quorum ) external initializer { - __ECDSAStakeRegistry_init(_serviceManager, _thresholdWeight, _quorum); + __ECDSAStakeRegistry_init(_serviceManager, thresholdWeight, quorum); } - /// @notice Registers a new operator using a provided signature and signing key - /// @param _operatorSignature Contains the operator's signature, salt, and expiry - /// @param _signingKey The signing key to add to the operator's history + /// @notice Initializes state for the StakeRegistry + /// @param _serviceManagerAddr The AVS' ServiceManager contract's address + function __ECDSAStakeRegistry_init( + address _serviceManagerAddr, + uint256 thresholdWeight, + IECDSAStakeRegistryTypes.Quorum memory quorum + ) internal onlyInitializing { + _serviceManager = _serviceManagerAddr; + _updateStakeThreshold(thresholdWeight); + _updateQuorumConfig(quorum); + __Ownable_init(); + } + + /// @inheritdoc IECDSAStakeRegistry function registerOperatorWithSignature( - ISignatureUtils.SignatureWithSaltAndExpiry memory _operatorSignature, - address _signingKey + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature, + address signingKey ) external { - _registerOperatorWithSig(msg.sender, _operatorSignature, _signingKey); + _registerOperatorWithSig(msg.sender, operatorSignature, signingKey); } - /// @notice Deregisters an existing operator + /// @inheritdoc IECDSAStakeRegistry function deregisterOperator() external { _deregisterOperator(msg.sender); } - /** - * @notice Updates the signing key for an operator - * @dev Only callable by the operator themselves - * @param _newSigningKey The new signing key to set for the operator - */ + /// @inheritdoc IECDSAStakeRegistry function updateOperatorSigningKey( - address _newSigningKey + address newSigningKey ) external { if (!_operatorRegistered[msg.sender]) { revert OperatorNotRegistered(); } - _updateOperatorSigningKey(msg.sender, _newSigningKey); + _updateOperatorSigningKey(msg.sender, newSigningKey); } - /** - * @notice Updates the StakeRegistry's view of one or more operators' stakes adding a new entry in their history of stake checkpoints, - * @dev Queries stakes from the Eigenlayer core DelegationManager contract - * @param _operators A list of operator addresses to update - */ + /// @inheritdoc IECDSAStakeRegistry function updateOperators( - address[] memory _operators + address[] memory operators ) external { - _updateOperators(_operators); + _updateOperators(operators); } - /** - * @notice Updates the quorum configuration and the set of operators - * @dev Only callable by the contract owner. - * It first updates the quorum configuration and then updates the list of operators. - * @param _quorum The new quorum configuration, including strategies and their new weights - * @param _operators The list of operator addresses to update stakes for - */ + /// @inheritdoc IECDSAStakeRegistry function updateQuorumConfig( - Quorum memory _quorum, - address[] memory _operators + IECDSAStakeRegistryTypes.Quorum memory quorum, + address[] memory operators ) external onlyOwner { - _updateQuorumConfig(_quorum); - _updateOperators(_operators); + _updateQuorumConfig(quorum); + _updateOperators(operators); } - /// @notice Updates the weight an operator must have to join the operator set - /// @dev Access controlled to the contract owner - /// @param _newMinimumWeight The new weight an operator must have to join the operator set + /// @inheritdoc IECDSAStakeRegistry function updateMinimumWeight( - uint256 _newMinimumWeight, - address[] memory _operators + uint256 newMinimumWeight, + address[] memory operators ) external onlyOwner { - _updateMinimumWeight(_newMinimumWeight); - _updateOperators(_operators); + _updateMinimumWeight(newMinimumWeight); + _updateOperators(operators); } - /** - * @notice Sets a new cumulative threshold weight for message validation by operator set signatures. - * @dev This function can only be invoked by the owner of the contract. It delegates the update to - * an internal function `_updateStakeThreshold`. - * @param _thresholdWeight The updated threshold weight required to validate a message. This is the - * cumulative weight that must be met or exceeded by the sum of the stakes of the signatories for - * a message to be deemed valid. - */ + /// @inheritdoc IECDSAStakeRegistry function updateStakeThreshold( - uint256 _thresholdWeight + uint256 thresholdWeight ) external onlyOwner { - _updateStakeThreshold(_thresholdWeight); + _updateStakeThreshold(thresholdWeight); } - /// @notice Verifies if the provided signature data is valid for the given data hash. - /// @param _dataHash The hash of the data that was signed. - /// @param _signatureData Encoded signature data consisting of an array of operators, an array of signatures, and a reference block number. - /// @return The function selector that indicates the signature is valid according to ERC1271 standard. function isValidSignature( - bytes32 _dataHash, + bytes32 digest, bytes memory _signatureData ) external view returns (bytes4) { (address[] memory operators, bytes[] memory signatures, uint32 referenceBlock) = abi.decode(_signatureData, (address[], bytes[], uint32)); - _checkSignatures(_dataHash, operators, signatures, referenceBlock); + _checkSignatures(digest, operators, signatures, referenceBlock); return IERC1271Upgradeable.isValidSignature.selector; } - /// @notice Retrieves the current stake quorum details. - /// @return Quorum - The current quorum of strategies and weights - function quorum() external view returns (Quorum memory) { + /// @inheritdoc IECDSAStakeRegistry + function quorum() external view returns (IECDSAStakeRegistryTypes.Quorum memory) { return _quorum; } - /** - * @notice Retrieves the latest signing key for a given operator. - * @param _operator The address of the operator. - * @return The latest signing key of the operator. - */ - function getLastestOperatorSigningKey( - address _operator + /// @inheritdoc IECDSAStakeRegistry + function getLatestOperatorSigningKey( + address operator ) external view returns (address) { - return address(uint160(_operatorSigningKeyHistory[_operator].latest())); + return address(uint160(_operatorSigningKeyHistory[operator].latest())); } - /** - * @notice Retrieves the latest signing key for a given operator at a specific block number. - * @param _operator The address of the operator. - * @param _blockNumber The block number to get the operator's signing key. - * @return The signing key of the operator at the given block. - */ + /// @inheritdoc IECDSAStakeRegistry function getOperatorSigningKeyAtBlock( - address _operator, - uint256 _blockNumber + address operator, + uint256 blockNumber ) external view returns (address) { - return address(uint160(_operatorSigningKeyHistory[_operator].getAtBlock(_blockNumber))); + return address(uint160(_operatorSigningKeyHistory[operator].getAtBlock(blockNumber))); } - /// @notice Retrieves the last recorded weight for a given operator. - /// @param _operator The address of the operator. - /// @return uint256 - The latest weight of the operator. + /// @inheritdoc IECDSAStakeRegistry function getLastCheckpointOperatorWeight( - address _operator + address operator ) external view returns (uint256) { - return _operatorWeightHistory[_operator].latest(); + return _operatorWeightHistory[operator].latest(); } - /// @notice Retrieves the last recorded total weight across all operators. - /// @return uint256 - The latest total weight. + /// @inheritdoc IECDSAStakeRegistry function getLastCheckpointTotalWeight() external view returns (uint256) { return _totalWeightHistory.latest(); } - /// @notice Retrieves the last recorded threshold weight - /// @return uint256 - The latest threshold weight. + /// @inheritdoc IECDSAStakeRegistry function getLastCheckpointThresholdWeight() external view returns (uint256) { return _thresholdWeightHistory.latest(); } - /// @notice Retrieves the operator's weight at a specific block number. - /// @param _operator The address of the operator. - /// @param _blockNumber The block number to get the operator weight for the quorum - /// @return uint256 - The weight of the operator at the given block. + /// @inheritdoc IECDSAStakeRegistry function getOperatorWeightAtBlock( - address _operator, - uint32 _blockNumber + address operator, + uint32 blockNumber ) external view returns (uint256) { - return _operatorWeightHistory[_operator].getAtBlock(_blockNumber); + return _operatorWeightHistory[operator].getAtBlock(blockNumber); } - /// @notice Retrieves the total weight at a specific block number. - /// @param _blockNumber The block number to get the total weight for the quorum - /// @return uint256 - The total weight at the given block. + /// @inheritdoc IECDSAStakeRegistry function getLastCheckpointTotalWeightAtBlock( - uint32 _blockNumber + uint32 blockNumber ) external view returns (uint256) { - return _totalWeightHistory.getAtBlock(_blockNumber); + return _totalWeightHistory.getAtBlock(blockNumber); } - /// @notice Retrieves the threshold weight at a specific block number. - /// @param _blockNumber The block number to get the threshold weight for the quorum - /// @return uint256 - The threshold weight the given block. + /// @inheritdoc IECDSAStakeRegistry function getLastCheckpointThresholdWeightAtBlock( - uint32 _blockNumber + uint32 blockNumber ) external view returns (uint256) { - return _thresholdWeightHistory.getAtBlock(_blockNumber); + return _thresholdWeightHistory.getAtBlock(blockNumber); } + /// @inheritdoc IECDSAStakeRegistry function operatorRegistered( - address _operator + address operator ) external view returns (bool) { - return _operatorRegistered[_operator]; + return _operatorRegistered[operator]; } - /// @notice Returns the weight an operator must have to contribute to validating an AVS + /// @inheritdoc IECDSAStakeRegistry function minimumWeight() external view returns (uint256) { return _minimumWeight; } - /// @notice Calculates the current weight of an operator based on their delegated stake in the strategies considered in the quorum - /// @param _operator The address of the operator. - /// @return uint256 - The current weight of the operator; returns 0 if below the threshold. + /// @inheritdoc IECDSAStakeRegistry function getOperatorWeight( - address _operator + address operator ) public view returns (uint256) { StrategyParams[] memory strategyParams = _quorum.strategies; uint256 weight; @@ -244,7 +210,7 @@ contract ECDSAStakeRegistry is for (uint256 i; i < strategyParams.length; i++) { strategies[i] = strategyParams[i].strategy; } - uint256[] memory shares = DELEGATION_MANAGER.getOperatorShares(_operator, strategies); + uint256[] memory shares = DELEGATION_MANAGER.getOperatorShares(operator, strategies); for (uint256 i; i < strategyParams.length; i++) { weight += shares[i] * strategyParams[i].multiplier; } @@ -257,22 +223,7 @@ contract ECDSAStakeRegistry is } } - /// @notice Initializes state for the StakeRegistry - /// @param _serviceManagerAddr The AVS' ServiceManager contract's address - function __ECDSAStakeRegistry_init( - address _serviceManagerAddr, - uint256 _thresholdWeight, - Quorum memory _quorum - ) internal onlyInitializing { - _serviceManager = _serviceManagerAddr; - _updateStakeThreshold(_thresholdWeight); - _updateQuorumConfig(_quorum); - __Ownable_init(); - } - - /// @notice Updates the set of operators for the first quorum. - /// @param operatorsPerQuorum An array of operator address arrays, one for each quorum. - /// @dev This interface maintains compatibility with avs-sync which handles multiquorums while this registry has a single quorum + /// @inheritdoc IECDSAStakeRegistry function updateOperatorsForQuorum( address[][] memory operatorsPerQuorum, bytes memory @@ -282,138 +233,138 @@ contract ECDSAStakeRegistry is /// @dev Updates the list of operators if the provided list has the correct number of operators. /// Reverts if the provided list of operators does not match the expected total count of operators. - /// @param _operators The list of operator addresses to update. + /// @param operators The list of operator addresses to update. function _updateAllOperators( - address[] memory _operators + address[] memory operators ) internal { - if (_operators.length != _totalOperators) { + if (operators.length != _totalOperators) { revert MustUpdateAllOperators(); } - _updateOperators(_operators); + _updateOperators(operators); } /// @dev Updates the weights for a given list of operator addresses. /// When passing an operator that isn't registered, then 0 is added to their history - /// @param _operators An array of addresses for which to update the weights. + /// @param operators An array of addresses for which to update the weights. function _updateOperators( - address[] memory _operators + address[] memory operators ) internal { int256 delta; - for (uint256 i; i < _operators.length; i++) { - delta += _updateOperatorWeight(_operators[i]); + for (uint256 i; i < operators.length; i++) { + delta += _updateOperatorWeight(operators[i]); } _updateTotalWeight(delta); } /// @dev Updates the stake threshold weight and records the history. - /// @param _thresholdWeight The new threshold weight to set and record in the history. + /// @param thresholdWeight The new threshold weight to set and record in the history. function _updateStakeThreshold( - uint256 _thresholdWeight + uint256 thresholdWeight ) internal { - _thresholdWeightHistory.push(_thresholdWeight); - emit ThresholdWeightUpdated(_thresholdWeight); + _thresholdWeightHistory.push(thresholdWeight); + emit ThresholdWeightUpdated(thresholdWeight); } /// @dev Updates the weight an operator must have to join the operator set - /// @param _newMinimumWeight The new weight an operator must have to join the operator set + /// @param newMinimumWeight The new weight an operator must have to join the operator set function _updateMinimumWeight( - uint256 _newMinimumWeight + uint256 newMinimumWeight ) internal { uint256 oldMinimumWeight = _minimumWeight; - _minimumWeight = _newMinimumWeight; - emit MinimumWeightUpdated(oldMinimumWeight, _newMinimumWeight); + _minimumWeight = newMinimumWeight; + emit MinimumWeightUpdated(oldMinimumWeight, newMinimumWeight); } /// @notice Updates the quorum configuration - /// @dev Replaces the current quorum configuration with `_newQuorum` if valid. + /// @dev Replaces the current quorum configuration with `newQuorum` if valid. /// Reverts with `InvalidQuorum` if the new quorum configuration is not valid. /// Emits `QuorumUpdated` event with the old and new quorum configurations. - /// @param _newQuorum The new quorum configuration to set. + /// @param newQuorum The new quorum configuration to set. function _updateQuorumConfig( - Quorum memory _newQuorum + IECDSAStakeRegistryTypes.Quorum memory newQuorum ) internal { - if (!_isValidQuorum(_newQuorum)) { + if (!_isValidQuorum(newQuorum)) { revert InvalidQuorum(); } - Quorum memory oldQuorum = _quorum; + IECDSAStakeRegistryTypes.Quorum memory oldQuorum = _quorum; delete _quorum; - for (uint256 i; i < _newQuorum.strategies.length; i++) { - _quorum.strategies.push(_newQuorum.strategies[i]); + for (uint256 i; i < newQuorum.strategies.length; i++) { + _quorum.strategies.push(newQuorum.strategies[i]); } - emit QuorumUpdated(oldQuorum, _newQuorum); + emit QuorumUpdated(oldQuorum, newQuorum); } /// @dev Internal function to deregister an operator - /// @param _operator The operator's address to deregister + /// @param operator The operator's address to deregister function _deregisterOperator( - address _operator + address operator ) internal { - if (!_operatorRegistered[_operator]) { + if (!_operatorRegistered[operator]) { revert OperatorNotRegistered(); } _totalOperators--; - delete _operatorRegistered[_operator]; - int256 delta = _updateOperatorWeight(_operator); + delete _operatorRegistered[operator]; + int256 delta = _updateOperatorWeight(operator); _updateTotalWeight(delta); - IServiceManager(_serviceManager).deregisterOperatorFromAVS(_operator); - emit OperatorDeregistered(_operator, address(_serviceManager)); + IServiceManager(_serviceManager).deregisterOperatorFromAVS(operator); + emit OperatorDeregistered(operator, address(_serviceManager)); } /// @dev registers an operator through a provided signature - /// @param _operatorSignature Contains the operator's signature, salt, and expiry - /// @param _signingKey The signing key to add to the operator's history + /// @param operatorSignature Contains the operator's signature, salt, and expiry + /// @param signingKey The signing key to add to the operator's history function _registerOperatorWithSig( - address _operator, - ISignatureUtils.SignatureWithSaltAndExpiry memory _operatorSignature, - address _signingKey + address operator, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature, + address signingKey ) internal virtual { - if (_operatorRegistered[_operator]) { + if (_operatorRegistered[operator]) { revert OperatorAlreadyRegistered(); } _totalOperators++; - _operatorRegistered[_operator] = true; - int256 delta = _updateOperatorWeight(_operator); + _operatorRegistered[operator] = true; + int256 delta = _updateOperatorWeight(operator); _updateTotalWeight(delta); - _updateOperatorSigningKey(_operator, _signingKey); - IServiceManager(_serviceManager).registerOperatorToAVS(_operator, _operatorSignature); - emit OperatorRegistered(_operator, _serviceManager); + _updateOperatorSigningKey(operator, signingKey); + IServiceManager(_serviceManager).registerOperatorToAVS(operator, operatorSignature); + emit OperatorRegistered(operator, _serviceManager); } /// @dev Internal function to update an operator's signing key - /// @param _operator The address of the operator to update the signing key for - /// @param _newSigningKey The new signing key to set for the operator - function _updateOperatorSigningKey(address _operator, address _newSigningKey) internal { - address oldSigningKey = address(uint160(_operatorSigningKeyHistory[_operator].latest())); - if (_newSigningKey == oldSigningKey) { + /// @param operator The address of the operator to update the signing key for + /// @param newSigningKey The new signing key to set for the operator + function _updateOperatorSigningKey(address operator, address newSigningKey) internal { + address oldSigningKey = address(uint160(_operatorSigningKeyHistory[operator].latest())); + if (newSigningKey == oldSigningKey) { return; } - _operatorSigningKeyHistory[_operator].push(uint160(_newSigningKey)); - emit SigningKeyUpdate(_operator, block.number, _newSigningKey, oldSigningKey); + _operatorSigningKeyHistory[operator].push(uint160(newSigningKey)); + emit SigningKeyUpdate(operator, block.number, newSigningKey, oldSigningKey); } /// @notice Updates the weight of an operator and returns the previous and current weights. - /// @param _operator The address of the operator to update the weight of. + /// @param operator The address of the operator to update the weight of. function _updateOperatorWeight( - address _operator + address operator ) internal virtual returns (int256) { int256 delta; uint256 newWeight; - uint256 oldWeight = _operatorWeightHistory[_operator].latest(); - if (!_operatorRegistered[_operator]) { + uint256 oldWeight = _operatorWeightHistory[operator].latest(); + if (!_operatorRegistered[operator]) { delta -= int256(oldWeight); if (delta == 0) { return delta; } - _operatorWeightHistory[_operator].push(0); + _operatorWeightHistory[operator].push(0); } else { - newWeight = getOperatorWeight(_operator); + newWeight = getOperatorWeight(operator); delta = int256(newWeight) - int256(oldWeight); if (delta == 0) { return delta; } - _operatorWeightHistory[_operator].push(newWeight); + _operatorWeightHistory[operator].push(newWeight); } - emit OperatorWeightUpdated(_operator, oldWeight, newWeight); + emit OperatorWeightUpdated(operator, oldWeight, newWeight); return delta; } @@ -435,13 +386,13 @@ contract ECDSAStakeRegistry is * @dev Verifies that a specified quorum configuration is valid. A valid quorum has: * 1. Weights that sum to exactly 10,000 basis points, ensuring proportional representation. * 2. Unique strategies without duplicates to maintain quorum integrity. - * @param _quorum The quorum configuration to be validated. + * @param quorum The quorum configuration to be validated. * @return bool True if the quorum configuration is valid, otherwise false. */ function _isValidQuorum( - Quorum memory _quorum + IECDSAStakeRegistryTypes.Quorum memory quorum ) internal pure returns (bool) { - StrategyParams[] memory strategies = _quorum.strategies; + StrategyParams[] memory strategies = quorum.strategies; address lastStrategy; address currentStrategy; uint256 totalMultiplier; @@ -460,141 +411,141 @@ contract ECDSAStakeRegistry is /** * @notice Common logic to verify a batch of ECDSA signatures against a hash, using either last stake weight or at a specific block. - * @param _dataHash The hash of the data the signers endorsed. - * @param _operators A collection of addresses that endorsed the data hash. - * @param _signatures A collection of signatures matching the signers. - * @param _referenceBlock The block number for evaluating stake weight; use max uint32 for latest weight. + * @param digest The hash of the data the signers endorsed. + * @param operators A collection of addresses that endorsed the data hash. + * @param signatures A collection of signatures matching the signers. + * @param referenceBlock The block number for evaluating stake weight; use max uint32 for latest weight. */ function _checkSignatures( - bytes32 _dataHash, - address[] memory _operators, - bytes[] memory _signatures, - uint32 _referenceBlock + bytes32 digest, + address[] memory operators, + bytes[] memory signatures, + uint32 referenceBlock ) internal view { - uint256 signersLength = _operators.length; + uint256 signersLength = operators.length; address currentOperator; address lastOperator; address signer; uint256 signedWeight; - _validateSignaturesLength(signersLength, _signatures.length); + _validateSignaturesLength(signersLength, signatures.length); for (uint256 i; i < signersLength; i++) { - currentOperator = _operators[i]; - signer = _getOperatorSigningKey(currentOperator, _referenceBlock); + currentOperator = operators[i]; + signer = _getOperatorSigningKey(currentOperator, referenceBlock); _validateSortedSigners(lastOperator, currentOperator); - _validateSignature(signer, _dataHash, _signatures[i]); + _validateSignature(signer, digest, signatures[i]); lastOperator = currentOperator; - uint256 operatorWeight = _getOperatorWeight(currentOperator, _referenceBlock); + uint256 operatorWeight = _getOperatorWeight(currentOperator, referenceBlock); signedWeight += operatorWeight; } - _validateThresholdStake(signedWeight, _referenceBlock); + _validateThresholdStake(signedWeight, referenceBlock); } /// @notice Validates that the number of signers equals the number of signatures, and neither is zero. - /// @param _signersLength The number of signers. - /// @param _signaturesLength The number of signatures. + /// @param signersLength The number of signers. + /// @param signaturesLength The number of signatures. function _validateSignaturesLength( - uint256 _signersLength, - uint256 _signaturesLength + uint256 signersLength, + uint256 signaturesLength ) internal pure { - if (_signersLength != _signaturesLength) { + if (signersLength != signaturesLength) { revert LengthMismatch(); } - if (_signersLength == 0) { + if (signersLength == 0) { revert InvalidLength(); } } /// @notice Ensures that signers are sorted in ascending order by address. - /// @param _lastSigner The address of the last signer. - /// @param _currentSigner The address of the current signer. - function _validateSortedSigners(address _lastSigner, address _currentSigner) internal pure { - if (_lastSigner >= _currentSigner) { + /// @param lastSigner The address of the last signer. + /// @param currentSigner The address of the current signer. + function _validateSortedSigners(address lastSigner, address currentSigner) internal pure { + if (lastSigner >= currentSigner) { revert NotSorted(); } } /// @notice Validates a given signature against the signer's address and data hash. - /// @param _signer The address of the signer to validate. - /// @param _dataHash The hash of the data that is signed. - /// @param _signature The signature to validate. + /// @param signer The address of the signer to validate. + /// @param digest The hash of the data that is signed. + /// @param signature The signature to validate. function _validateSignature( - address _signer, - bytes32 _dataHash, - bytes memory _signature + address signer, + bytes32 digest, + bytes memory signature ) internal view { - if (!_signer.isValidSignatureNow(_dataHash, _signature)) { + if (!signer.isValidSignatureNow(digest, signature)) { revert InvalidSignature(); } } /// @notice Retrieves the operator weight for a signer, either at the last checkpoint or a specified block. - /// @param _operator The operator to query their signing key history for - /// @param _referenceBlock The block number to query the operator's weight at, or the maximum uint32 value for the last checkpoint. + /// @param operator The operator to query their signing key history for + /// @param referenceBlock The block number to query the operator's weight at, or the maximum uint32 value for the last checkpoint. /// @return The weight of the operator. function _getOperatorSigningKey( - address _operator, - uint32 _referenceBlock + address operator, + uint32 referenceBlock ) internal view returns (address) { - if (_referenceBlock >= block.number) { + if (referenceBlock >= block.number) { revert InvalidReferenceBlock(); } - return address(uint160(_operatorSigningKeyHistory[_operator].getAtBlock(_referenceBlock))); + return address(uint160(_operatorSigningKeyHistory[operator].getAtBlock(referenceBlock))); } /// @notice Retrieves the operator weight for a signer, either at the last checkpoint or a specified block. - /// @param _signer The address of the signer whose weight is returned. - /// @param _referenceBlock The block number to query the operator's weight at, or the maximum uint32 value for the last checkpoint. + /// @param signer The address of the signer whose weight is returned. + /// @param referenceBlock The block number to query the operator's weight at, or the maximum uint32 value for the last checkpoint. /// @return The weight of the operator. function _getOperatorWeight( - address _signer, - uint32 _referenceBlock + address signer, + uint32 referenceBlock ) internal view returns (uint256) { - if (_referenceBlock >= block.number) { + if (referenceBlock >= block.number) { revert InvalidReferenceBlock(); } - return _operatorWeightHistory[_signer].getAtBlock(_referenceBlock); + return _operatorWeightHistory[signer].getAtBlock(referenceBlock); } /// @notice Retrieve the total stake weight at a specific block or the latest if not specified. - /// @dev If the `_referenceBlock` is the maximum value for uint32, the latest total weight is returned. - /// @param _referenceBlock The block number to retrieve the total stake weight from. + /// @dev If the `referenceBlock` is the maximum value for uint32, the latest total weight is returned. + /// @param referenceBlock The block number to retrieve the total stake weight from. /// @return The total stake weight at the given block or the latest if the given block is the max uint32 value. function _getTotalWeight( - uint32 _referenceBlock + uint32 referenceBlock ) internal view returns (uint256) { - if (_referenceBlock >= block.number) { + if (referenceBlock >= block.number) { revert InvalidReferenceBlock(); } - return _totalWeightHistory.getAtBlock(_referenceBlock); + return _totalWeightHistory.getAtBlock(referenceBlock); } /// @notice Retrieves the threshold stake for a given reference block. - /// @param _referenceBlock The block number to query the threshold stake for. + /// @param referenceBlock The block number to query the threshold stake for. /// If set to the maximum uint32 value, it retrieves the latest threshold stake. /// @return The threshold stake in basis points for the reference block. function _getThresholdStake( - uint32 _referenceBlock + uint32 referenceBlock ) internal view returns (uint256) { - if (_referenceBlock >= block.number) { + if (referenceBlock >= block.number) { revert InvalidReferenceBlock(); } - return _thresholdWeightHistory.getAtBlock(_referenceBlock); + return _thresholdWeightHistory.getAtBlock(referenceBlock); } /// @notice Validates that the cumulative stake of signed messages meets or exceeds the required threshold. - /// @param _signedWeight The cumulative weight of the signers that have signed the message. - /// @param _referenceBlock The block number to verify the stake threshold for - function _validateThresholdStake(uint256 _signedWeight, uint32 _referenceBlock) internal view { - uint256 totalWeight = _getTotalWeight(_referenceBlock); - if (_signedWeight > totalWeight) { + /// @param signedWeight The cumulative weight of the signers that have signed the message. + /// @param referenceBlock The block number to verify the stake threshold for + function _validateThresholdStake(uint256 signedWeight, uint32 referenceBlock) internal view { + uint256 totalWeight = _getTotalWeight(referenceBlock); + if (signedWeight > totalWeight) { revert InvalidSignedWeight(); } - uint256 thresholdStake = _getThresholdStake(_referenceBlock); - if (thresholdStake > _signedWeight) { + uint256 thresholdStake = _getThresholdStake(referenceBlock); + if (thresholdStake > signedWeight) { revert InsufficientSignedStake(); } } diff --git a/src/unaudited/ECDSAStakeRegistryStorage.sol b/src/unaudited/ECDSAStakeRegistryStorage.sol index a47701e3..8d9d69d8 100644 --- a/src/unaudited/ECDSAStakeRegistryStorage.sol +++ b/src/unaudited/ECDSAStakeRegistryStorage.sol @@ -6,23 +6,21 @@ import {IDelegationManager} from import {CheckpointsUpgradeable} from "@openzeppelin-upgrades/contracts/utils/CheckpointsUpgradeable.sol"; import { - ECDSAStakeRegistryEventsAndErrors, - Quorum, - StrategyParams -} from "../interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; + IECDSAStakeRegistry, IECDSAStakeRegistryTypes +} from "../interfaces/IECDSAStakeRegistry.sol"; -abstract contract ECDSAStakeRegistryStorage is ECDSAStakeRegistryEventsAndErrors { +abstract contract ECDSAStakeRegistryStorage is IECDSAStakeRegistry { /// @notice Manages staking delegations through the DelegationManager interface IDelegationManager internal immutable DELEGATION_MANAGER; /// @dev The total amount of multipliers to weigh stakes - uint256 internal constant BPS = 10_000; + uint256 internal constant BPS = 10000; /// @notice The size of the current operator set uint256 internal _totalOperators; /// @notice Stores the current quorum configuration - Quorum internal _quorum; + IECDSAStakeRegistryTypes.Quorum internal _quorum; /// @notice Specifies the weight required to become an operator uint256 internal _minimumWeight; diff --git a/test/ffi/BLSPubKeyCompendiumFFI.t.sol b/test/ffi/BLSPubKeyCompendiumFFI.t.sol index 78d3ca72..44283d9c 100644 --- a/test/ffi/BLSPubKeyCompendiumFFI.t.sol +++ b/test/ffi/BLSPubKeyCompendiumFFI.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.27; import "../../src/BLSApkRegistry.sol"; import "../ffi/util/G2Operations.sol"; -import {IBLSApkRegistry} from "../../src/interfaces/IBLSApkRegistry.sol"; +import {IBLSApkRegistry, IBLSApkRegistryTypes} from "../../src/interfaces/IBLSApkRegistry.sol"; import {ISlashingRegistryCoordinator} from "../../src/interfaces/ISlashingRegistryCoordinator.sol"; contract BLSApkRegistryFFITests is G2Operations { @@ -16,7 +16,7 @@ contract BLSApkRegistryFFITests is G2Operations { ISlashingRegistryCoordinator registryCoordinator; uint256 privKey; - IBLSApkRegistry.PubkeyRegistrationParams pubkeyRegistrationParams; + IBLSApkRegistryTypes.PubkeyRegistrationParams pubkeyRegistrationParams; address alice = address(0x69); diff --git a/test/ffi/UpdateOperators.t.sol b/test/ffi/UpdateOperators.t.sol index b7bba5b0..349bb8d1 100644 --- a/test/ffi/UpdateOperators.t.sol +++ b/test/ffi/UpdateOperators.t.sol @@ -1027,7 +1027,7 @@ contract Integration_AVS_Sync_GasCosts_FFI is IntegrationChecks { // READ JSON CONFIG DATA string memory config_data = vm.readFile(keysConfigPath); for (uint256 i = 0; i < MAX_OPERATOR_COUNT; i++) { - IBLSApkRegistry.PubkeyRegistrationParams memory pubkey; + IBLSApkRegistryTypes.PubkeyRegistrationParams memory pubkey; uint256 privateKey = privateKeys[i]; // G1 pubkey.pubkeyG1.X = @@ -1050,7 +1050,7 @@ contract Integration_AVS_Sync_GasCosts_FFI is IntegrationChecks { function _generateOperatorKeys() internal { for (uint256 i = 0; i < 200; i++) { - IBLSApkRegistry.PubkeyRegistrationParams memory pubkey; + IBLSApkRegistryTypes.PubkeyRegistrationParams memory pubkey; uint256 privateKey = privateKeys[i]; pubkey.pubkeyG1 = BN254.generatorG1().scalar_mul(privateKey); pubkey.pubkeyG2 = G2Operations.mul(privateKey); diff --git a/test/harnesses/RegistryCoordinatorHarness.t.sol b/test/harnesses/RegistryCoordinatorHarness.t.sol index 8d6e6bc4..7adf32dc 100644 --- a/test/harnesses/RegistryCoordinatorHarness.t.sol +++ b/test/harnesses/RegistryCoordinatorHarness.t.sol @@ -67,11 +67,15 @@ contract RegistryCoordinatorHarness is RegistryCoordinator, Test { _updateOperatorBitmap(operatorId, quorumBitmap); } - function setOperatorSetsEnabled(bool enabled) external { + function setOperatorSetsEnabled( + bool enabled + ) external { operatorSetsEnabled = enabled; } - function setM2QuorumsDisabled(bool disabled) external { + function setM2QuorumsDisabled( + bool disabled + ) external { m2QuorumsDisabled = disabled; } } diff --git a/test/harnesses/StakeRegistryHarness.sol b/test/harnesses/StakeRegistryHarness.sol index 3fe3a187..2a205541 100644 --- a/test/harnesses/StakeRegistryHarness.sol +++ b/test/harnesses/StakeRegistryHarness.sol @@ -10,8 +10,7 @@ contract StakeRegistryHarness is StakeRegistry { IDelegationManager _delegationManager, IAVSDirectory _avsDirectory, IAllocationManager _allocationManager - ) StakeRegistry(_registryCoordinator, _delegationManager, _avsDirectory, _allocationManager) { - } + ) StakeRegistry(_registryCoordinator, _delegationManager, _avsDirectory, _allocationManager) {} function recordOperatorStakeUpdate( bytes32 operatorId, diff --git a/test/integration/CoreRegistration.t.sol b/test/integration/CoreRegistration.t.sol index d3bffe8d..bd1718c6 100644 --- a/test/integration/CoreRegistration.t.sol +++ b/test/integration/CoreRegistration.t.sol @@ -57,7 +57,7 @@ contract Test_CoreRegistration is MockAVSDeployer { address(this), pauserRegistry, 0, // 0 is initialPausedStatus - 50_400, // Initial withdrawal delay blocks + 50400, // Initial withdrawal delay blocks initializeStrategiesToSetDelayBlocks, initializeWithdrawalDelayBlocks ) diff --git a/test/integration/IntegrationBase.t.sol b/test/integration/IntegrationBase.t.sol index 388535c6..180edd11 100644 --- a/test/integration/IntegrationBase.t.sol +++ b/test/integration/IntegrationBase.t.sol @@ -29,22 +29,26 @@ abstract contract IntegrationBase is IntegrationConfig { /// @dev Also checks that the user has NEVER_REGISTERED status function assert_HasNoOperatorInfo(User user, string memory err) internal { - ISlashingRegistryCoordinator.OperatorInfo memory info = _getOperatorInfo(user); + ISlashingRegistryCoordinatorTypes.OperatorInfo memory info = _getOperatorInfo(user); assertEq(info.operatorId, bytes32(0), err); - assertTrue(info.status == ISlashingRegistryCoordinator.OperatorStatus.NEVER_REGISTERED, err); + assertTrue( + info.status == ISlashingRegistryCoordinatorTypes.OperatorStatus.NEVER_REGISTERED, err + ); } function assert_HasRegisteredStatus(User user, string memory err) internal { - ISlashingRegistryCoordinator.OperatorStatus status = registryCoordinator.getOperatorStatus(address(user)); + ISlashingRegistryCoordinatorTypes.OperatorStatus status = + registryCoordinator.getOperatorStatus(address(user)); - assertTrue(status == ISlashingRegistryCoordinator.OperatorStatus.REGISTERED, err); + assertTrue(status == ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED, err); } function assert_HasDeregisteredStatus(User user, string memory err) internal { - ISlashingRegistryCoordinator.OperatorStatus status = registryCoordinator.getOperatorStatus(address(user)); + ISlashingRegistryCoordinatorTypes.OperatorStatus status = + registryCoordinator.getOperatorStatus(address(user)); - assertTrue(status == ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED, err); + assertTrue(status == ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED, err); } function assert_EmptyQuorumBitmap(User user, string memory err) internal { @@ -241,8 +245,8 @@ abstract contract IntegrationBase is IntegrationConfig { } function assert_Snap_Unchanged_OperatorInfo(User user, string memory err) internal { - ISlashingRegistryCoordinator.OperatorInfo memory curInfo = _getOperatorInfo(user); - ISlashingRegistryCoordinator.OperatorInfo memory prevInfo = _getPrevOperatorInfo(user); + ISlashingRegistryCoordinatorTypes.OperatorInfo memory curInfo = _getOperatorInfo(user); + ISlashingRegistryCoordinatorTypes.OperatorInfo memory prevInfo = _getPrevOperatorInfo(user); assertEq(prevInfo.operatorId, curInfo.operatorId, err); assertTrue(prevInfo.status == curInfo.status, err); @@ -862,11 +866,15 @@ abstract contract IntegrationBase is IntegrationConfig { /// RegistryCoordinator: - function _getOperatorInfo(User user) internal view returns (ISlashingRegistryCoordinator.OperatorInfo memory) { + function _getOperatorInfo( + User user + ) internal view returns (ISlashingRegistryCoordinatorTypes.OperatorInfo memory) { return registryCoordinator.getOperator(address(user)); } - function _getPrevOperatorInfo(User user) internal timewarp() returns (ISlashingRegistryCoordinator.OperatorInfo memory) { + function _getPrevOperatorInfo( + User user + ) internal timewarp returns (ISlashingRegistryCoordinatorTypes.OperatorInfo memory) { return _getOperatorInfo(user); } diff --git a/test/integration/IntegrationConfig.t.sol b/test/integration/IntegrationConfig.t.sol index 4581372f..92c394bb 100644 --- a/test/integration/IntegrationConfig.t.sol +++ b/test/integration/IntegrationConfig.t.sol @@ -6,16 +6,18 @@ import "forge-std/Test.sol"; import "test/integration/IntegrationDeployer.t.sol"; import "test/ffi/util/G2Operations.sol"; import "test/integration/utils/BitmapStrings.t.sol"; +import {ISlashingRegistryCoordinatorTypes} from + "../../src/interfaces/ISlashingRegistryCoordinator.sol"; contract Constants { - /// Quorum Config: + /// IECDSAStakeRegistryTypes.Quorum Config: /// @dev Default OperatorSetParam values used to initialize quorums /// NOTE: This means each quorum has an operator limit of MAX_OPERATOR_COUNT by default /// This is a low number because each operator receives its own BLS keypair, which /// is very slow to generate. uint32 constant MAX_OPERATOR_COUNT = 5; - uint16 constant KICK_BIPS_OPERATOR_STAKE = 15_000; + uint16 constant KICK_BIPS_OPERATOR_STAKE = 15000; uint16 constant KICK_BIPS_TOTAL_STAKE = 150; /// Other: @@ -26,7 +28,7 @@ contract Constants { uint256 constant MAX_QUORUM_COUNT = 192; // From RegistryCoordinator.MAX_QUORUM_COUNT - uint16 internal constant BIPS_DENOMINATOR = 10_000; + uint16 internal constant BIPS_DENOMINATOR = 10000; } contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { @@ -73,7 +75,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// (See _fetchKeypair) uint256 fetchIdx = 0; uint256[] privKeys; - IBLSApkRegistry.PubkeyRegistrationParams[] pubkeys; + IBLSApkRegistryTypes.PubkeyRegistrationParams[] pubkeys; /// @dev Current initialized quorums are tracked here: uint256 quorumCount; @@ -93,7 +95,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { */ constructor() { for (uint256 i = 0; i < NUM_GENERATED_OPERATORS; i++) { - IBLSApkRegistry.PubkeyRegistrationParams memory pubkey; + IBLSApkRegistryTypes.PubkeyRegistrationParams memory pubkey; uint256 privKey = uint256(keccak256(abi.encodePacked(i + 1))); pubkey.pubkeyG1 = BN254.generatorG1().scalar_mul(privKey); @@ -158,7 +160,8 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { emit log_named_uint("_configRand: number of quorums being initialized", quorumCount); // Default OperatorSetParams for all quorums - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSet = ISlashingRegistryCoordinator.OperatorSetParam({ + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSet = + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: MAX_OPERATOR_COUNT, kickBIPsOfOperatorStake: KICK_BIPS_OPERATOR_STAKE, kickBIPsOfTotalStake: KICK_BIPS_TOTAL_STAKE @@ -166,7 +169,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { // Initialize each quorum for (uint256 i = 0; i < quorumCount; i++) { - IStakeRegistry.StrategyParams[] memory strategyParams = _randStrategyParams(); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = _randStrategyParams(); uint96 minimumStake = _randMinStake(); emit log_named_uint("_configRand: creating quorum", i); @@ -232,7 +235,8 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { string memory name ) internal returns (User, IStrategy[] memory, uint256[] memory) { // Create User contract and give it a unique BLS keypair - (uint256 privKey, IBLSApkRegistry.PubkeyRegistrationParams memory pubkey) = _fetchKeypair(); + (uint256 privKey, IBLSApkRegistryTypes.PubkeyRegistrationParams memory pubkey) = + _fetchKeypair(); // Use userFlags to pick the kind of user to generate User user; @@ -317,8 +321,8 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { for (uint256 i = 0; i < churnQuorums.length; i++) { uint8 quorum = uint8(churnQuorums[i]); - ISlashingRegistryCoordinator.OperatorSetParam memory params - = registryCoordinator.getOperatorSetParams(quorum); + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory params = + registryCoordinator.getOperatorSetParams(quorum); // Sanity check - make sure we're at the operator cap uint32 curNumOperators = indexRegistry.totalOperatorsForQuorum(quorum); @@ -364,7 +368,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// From RegistryCoordinator._individualKickThreshold function _individualKickThreshold( uint96 operatorStake, - ISlashingRegistryCoordinator.OperatorSetParam memory setParams + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory setParams ) internal pure returns (uint96) { return operatorStake * setParams.kickBIPsOfOperatorStake / BIPS_DENOMINATOR; } @@ -372,7 +376,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// From RegistryCoordinator._totalKickThreshold function _totalKickThreshold( uint96 totalStake, - ISlashingRegistryCoordinator.OperatorSetParam memory setParams + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory setParams ) internal pure returns (uint96) { return totalStake * setParams.kickBIPsOfTotalStake / BIPS_DENOMINATOR; } @@ -421,7 +425,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { function _fetchKeypair() internal - returns (uint256, IBLSApkRegistry.PubkeyRegistrationParams memory) + returns (uint256, IBLSApkRegistryTypes.PubkeyRegistrationParams memory) { // should probably just generate another keypair at this point if (fetchIdx == privKeys.length) { @@ -431,7 +435,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { } uint256 privKey = privKeys[fetchIdx]; - IBLSApkRegistry.PubkeyRegistrationParams memory pubkey = pubkeys[fetchIdx]; + IBLSApkRegistryTypes.PubkeyRegistrationParams memory pubkey = pubkeys[fetchIdx]; fetchIdx++; return (privKey, pubkey); @@ -527,7 +531,7 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { /// NOTE: This should only be used when creating a quorum for the first time. If you're /// selecting strategies to add after the quorum has been initialized, this is likely to /// return duplicates. - function _randStrategyParams() private returns (IStakeRegistry.StrategyParams[] memory) { + function _randStrategyParams() private returns (IStakeRegistryTypes.StrategyParams[] memory) { uint256 strategyFlag = _randValue(numStrategyFlags); uint256 strategyCount; @@ -547,11 +551,11 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { revert("_randStrategyCount: flag not recognized"); } - IStakeRegistry.StrategyParams[] memory params = - new IStakeRegistry.StrategyParams[](strategyCount); + IStakeRegistryTypes.StrategyParams[] memory params = + new IStakeRegistryTypes.StrategyParams[](strategyCount); for (uint256 i = 0; i < params.length; i++) { - params[i] = IStakeRegistry.StrategyParams({ + params[i] = IStakeRegistryTypes.StrategyParams({ strategy: allStrats[i], multiplier: DEFAULT_STRATEGY_MULTIPLIER }); @@ -564,8 +568,10 @@ contract IntegrationConfig is IntegrationDeployer, G2Operations, Constants { * @dev Uses _randFillType to determine how many operators to register for a quorum initially * @return The number of operators to register */ - function _randInitialOperators(ISlashingRegistryCoordinator.OperatorSetParam memory operatorSet) private returns (uint) { - uint fillTypeFlag = _randValue(fillTypeFlags); + function _randInitialOperators( + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSet + ) private returns (uint256) { + uint256 fillTypeFlag = _randValue(fillTypeFlags); if (fillTypeFlag == EMPTY) { return 0; diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index 323c1cc8..508fb869 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -107,9 +107,9 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { /// @notice Upper bound start range is ~1 month into the future, multiple of CALCULATION_INTERVAL_SECONDS uint32 MAX_FUTURE_LENGTH = 28 days; /// @notice absolute min timestamp that a rewards can start at - uint32 GENESIS_REWARDS_TIMESTAMP = 1_712_188_800; + uint32 GENESIS_REWARDS_TIMESTAMP = 1712188800; /// @notice Equivalent to 100%, but in basis points. - uint16 internal constant ONE_HUNDRED_IN_BIPS = 10_000; + uint16 internal constant ONE_HUNDRED_IN_BIPS = 10000; uint32 defaultOperatorSplitBips = 1000; /// @notice Delay in timestamp before a posted root can be claimed against @@ -339,7 +339,10 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { cheats.stopPrank(); StakeRegistry stakeRegistryImplementation = new StakeRegistry( - ISlashingRegistryCoordinator(registryCoordinator), IDelegationManager(delegationManager), IAVSDirectory(avsDirectory), allocationManager + ISlashingRegistryCoordinator(registryCoordinator), + IDelegationManager(delegationManager), + IAVSDirectory(avsDirectory), + allocationManager ); BLSApkRegistry blsApkRegistryImplementation = new BLSApkRegistry(ISlashingRegistryCoordinator(registryCoordinator)); @@ -379,7 +382,8 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { rewardsInitiator: address(msg.sender) }); - StakeType[] memory quorumStakeTypes = new StakeType[](0); + IStakeRegistryTypes.StakeType[] memory quorumStakeTypes = + new IStakeRegistryTypes.StakeType[](0); uint32[] memory slashableStakeQuorumLookAheadPeriods = new uint32[](0); RegistryCoordinator registryCoordinatorImplementation = new RegistryCoordinator( @@ -399,7 +403,11 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { churnApprover, ejector, 0, /*initialPausedStatus*/ - address(serviceManager) // _accountIdentifier + new IRegistryCoordinator.OperatorSetParam[](0), + new uint96[](0), + new IStakeRegistryTypes.StrategyParams[][](0), + quorumStakeTypes, + slashableStakeQuorumLookAheadPeriods ) ); @@ -445,26 +453,32 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { /// @notice Overwrite RegistryCoordinator.operatorSetsEnabled to the specified value. /// This is to enable testing of RegistryCoordinator in non-operator set mode. - function _setOperatorSetsEnabled(bool operatorSetsEnabled) internal { + function _setOperatorSetsEnabled( + bool operatorSetsEnabled + ) internal { // 1. First read the current value of the entire slot // which holds operatorSetsEnabled, m2QuorumsDisabled, and accountIdentifier bytes32 currentSlot = cheats.load(address(registryCoordinator), bytes32(uint256(161))); // 2. Clear only the first byte (operatorSetsEnabled) while keeping the rest - bytes32 newSlot = (currentSlot & ~bytes32(uint256(0xff))) | bytes32(uint256(operatorSetsEnabled ? 0x01 : 0x00)); + bytes32 newSlot = (currentSlot & ~bytes32(uint256(0xff))) + | bytes32(uint256(operatorSetsEnabled ? 0x01 : 0x00)); // 3. Store the modified slot cheats.store(address(registryCoordinator), bytes32(uint256(161)), newSlot); } /// @notice Overwrite RegistryCoordinator.m2QuorumsDisabled to the specified value. - function _setM2QuorumsDisabled(bool m2QuorumsDisabled) internal { + function _setM2QuorumsDisabled( + bool m2QuorumsDisabled + ) internal { // 1. First read the current value of the entire slot // which holds operatorSetsEnabled, m2QuorumsDisabled, and accountIdentifier bytes32 currentSlot = cheats.load(address(registryCoordinator), bytes32(uint256(161))); // 2. Clear only the second byte (m2QuorumsDisabled) while keeping the rest - bytes32 newSlot = (currentSlot & ~bytes32(uint256(0xff) << 8)) | bytes32(uint256(m2QuorumsDisabled ? 0x01 : 0x00) << 8); + bytes32 newSlot = (currentSlot & ~bytes32(uint256(0xff) << 8)) + | bytes32(uint256(m2QuorumsDisabled ? 0x01 : 0x00) << 8); // 3. Store the modified slot cheats.store(address(registryCoordinator), bytes32(uint256(161)), newSlot); diff --git a/test/integration/User.t.sol b/test/integration/User.t.sol index 42e8740e..8a1a9b61 100644 --- a/test/integration/User.t.sol +++ b/test/integration/User.t.sol @@ -16,6 +16,7 @@ import "eigenlayer-contracts/src/contracts/core/StrategyManager.sol"; import "eigenlayer-contracts/src/contracts/core/AVSDirectory.sol"; // Middleware +import "src/interfaces/IRegistryCoordinator.sol"; import "src/RegistryCoordinator.sol"; import "src/BLSApkRegistry.sol"; import "src/IndexRegistry.sol"; @@ -66,7 +67,7 @@ contract User is Test { // BLS keypair: uint256 privKey; - IBLSApkRegistry.PubkeyRegistrationParams pubkeyParams; + IBLSApkRegistryTypes.PubkeyRegistrationParams pubkeyParams; // EIP1271 sigs: mapping(bytes32 => bool) digests; @@ -75,7 +76,7 @@ contract User is Test { constructor( string memory name, uint256 _privKey, - IBLSApkRegistry.PubkeyRegistrationParams memory _pubkeyParams + IBLSApkRegistryTypes.PubkeyRegistrationParams memory _pubkeyParams ) { IUserDeployer deployer = IUserDeployer(msg.sender); @@ -160,8 +161,8 @@ contract User is Test { bytes memory allQuorums = churnBitmap.plus(standardBitmap).bitmapToBytesArray(); - ISlashingRegistryCoordinator.OperatorKickParam[] memory kickParams - = new ISlashingRegistryCoordinator.OperatorKickParam[](allQuorums.length); + ISlashingRegistryCoordinator.OperatorKickParam[] memory kickParams = + new ISlashingRegistryCoordinator.OperatorKickParam[](allQuorums.length); // this constructs OperatorKickParam[] in ascending quorum order // (yikes) @@ -169,19 +170,21 @@ contract User is Test { uint256 stdIdx; while (churnIdx + stdIdx < allQuorums.length) { if (churnIdx == churnQuorums.length) { - kickParams[churnIdx + stdIdx] = ISlashingRegistryCoordinator.OperatorKickParam({ + kickParams[churnIdx + stdIdx] = ISlashingRegistryCoordinatorTypes.OperatorKickParam({ quorumNumber: 0, operator: address(0) }); stdIdx++; - } else if (stdIdx == standardQuorums.length || churnQuorums[churnIdx] < standardQuorums[stdIdx]) { - kickParams[churnIdx + stdIdx] = ISlashingRegistryCoordinator.OperatorKickParam({ + } else if ( + stdIdx == standardQuorums.length || churnQuorums[churnIdx] < standardQuorums[stdIdx] + ) { + kickParams[churnIdx + stdIdx] = ISlashingRegistryCoordinatorTypes.OperatorKickParam({ quorumNumber: uint8(churnQuorums[churnIdx]), operator: address(churnTargets[churnIdx]) }); churnIdx++; } else if (standardQuorums[stdIdx] < churnQuorums[churnIdx]) { - kickParams[churnIdx + stdIdx] = ISlashingRegistryCoordinator.OperatorKickParam({ + kickParams[churnIdx + stdIdx] = ISlashingRegistryCoordinatorTypes.OperatorKickParam({ quorumNumber: 0, operator: address(0) }); @@ -386,7 +389,7 @@ contract User_AltMethods is User { constructor( string memory name, uint256 _privKey, - IBLSApkRegistry.PubkeyRegistrationParams memory _pubkeyParams + IBLSApkRegistryTypes.PubkeyRegistrationParams memory _pubkeyParams ) User(name, _privKey, _pubkeyParams) {} /// @dev Rather than calling deregisterOperator, this pranks the ejector and calls diff --git a/test/mocks/AVSRegistrarMock.sol b/test/mocks/AVSRegistrarMock.sol index 2684275c..9a61b26e 100644 --- a/test/mocks/AVSRegistrarMock.sol +++ b/test/mocks/AVSRegistrarMock.sol @@ -3,7 +3,6 @@ pragma solidity ^0.8.27; import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSRegistrar.sol"; - contract AVSRegistrarMock is IAVSRegistrar { function registerOperator( address operator, diff --git a/test/mocks/DelegationMock.sol b/test/mocks/DelegationMock.sol index ff04b970..11bce967 100644 --- a/test/mocks/DelegationMock.sol +++ b/test/mocks/DelegationMock.sol @@ -283,6 +283,6 @@ contract DelegationMock is DelegationIntermediate { } function minWithdrawalDelayBlocks() external view override returns (uint32) { - return 10_000; + return 10000; } } diff --git a/test/mocks/ECDSAServiceManagerMock.sol b/test/mocks/ECDSAServiceManagerMock.sol index d77fc961..07a263cf 100644 --- a/test/mocks/ECDSAServiceManagerMock.sol +++ b/test/mocks/ECDSAServiceManagerMock.sol @@ -37,7 +37,10 @@ contract ECDSAServiceManagerMock is ECDSAServiceManagerBase { address pendingAdmin ) external {} - function deregisterOperatorFromOperatorSets(address operator, uint32[] memory operatorSetIds) external {} + function deregisterOperatorFromOperatorSets( + address operator, + uint32[] memory operatorSetIds + ) external {} function removeAdmin( address admin diff --git a/test/mocks/RegistryCoordinatorMock.sol b/test/mocks/RegistryCoordinatorMock.sol index 533e14ef..78c98660 100644 --- a/test/mocks/RegistryCoordinatorMock.sol +++ b/test/mocks/RegistryCoordinatorMock.sol @@ -3,130 +3,162 @@ pragma solidity ^0.8.27; import "../../src/interfaces/IRegistryCoordinator.sol"; import "../../src/interfaces/ISlashingRegistryCoordinator.sol"; - - -contract RegistryCoordinatorMock is ISlashingRegistryCoordinator, IRegistryCoordinator { - function blsApkRegistry() external view returns (IBLSApkRegistry) {} - - function ejectOperator(address operator, bytes calldata quorumNumbers) external {} - +import "../../src/libraries/BN254.sol"; + +abstract contract RegistryCoordinatorMock is IRegistryCoordinator { + // Add missing function declarations from interface + function OPERATOR_CHURN_APPROVAL_TYPEHASH() external pure virtual returns (bytes32); + function PUBKEY_REGISTRATION_TYPEHASH() external pure virtual returns (bytes32); + function allocationManager() external view virtual returns (IAllocationManager); + function calculateOperatorChurnApprovalDigestHash( + address registeringOperator, + bytes32 registeringOperatorId, + OperatorKickParam[] memory operatorKickParams, + bytes32 salt, + uint256 expiry + ) external view virtual returns (bytes32); + function churnApprover() external view virtual returns (address); + function createSlashableStakeQuorum( + OperatorSetParam memory operatorSetParams, + uint96 minimumStake, + IStakeRegistryTypes.StrategyParams[] memory strategyParams, + uint32 lookAheadPeriod + ) external virtual; + function createTotalDelegatedStakeQuorum( + OperatorSetParam memory operatorSetParams, + uint96 minimumStake, + IStakeRegistryTypes.StrategyParams[] memory strategyParams + ) external virtual; + function deregisterOperator( + address operator, + uint32[] memory operatorSetIds + ) external virtual; + function ejectionCooldown() external view virtual returns (uint256); + function ejector() external view virtual returns (address); + function enableOperatorSets() external virtual; + function initialize( + address _initialOwner, + address _churnApprover, + address _ejector, + uint256 _initialPausedStatus, + OperatorSetParam[] memory _operatorSetParams, + uint96[] memory _minimumStakes, + IStakeRegistryTypes.StrategyParams[][] memory _strategyParams, + IStakeRegistryTypes.StakeType[] memory _stakeTypes, + uint32[] memory _lookAheadPeriods + ) external virtual; + function isChurnApproverSaltUsed( + bytes32 salt + ) external view virtual returns (bool); + function lastEjectionTimestamp( + address operator + ) external view virtual returns (uint256); + function registerOperator( + address operator, + uint32[] memory operatorSetIds, + bytes memory data + ) external virtual; + function registerOperator( + bytes memory quorumNumbers, + string memory socket, + IBLSApkRegistryTypes.PubkeyRegistrationParams memory params, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external virtual; + function registerOperatorWithChurn( + bytes calldata quorumNumbers, + string memory socket, + IBLSApkRegistryTypes.PubkeyRegistrationParams memory params, + OperatorKickParam[] memory operatorKickParams, + ISignatureUtils.SignatureWithSaltAndExpiry memory churnApproverSignature, + ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature + ) external virtual; + function setChurnApprover( + address _churnApprover + ) external virtual; + function setEjectionCooldown( + uint256 _ejectionCooldown + ) external virtual; + function setEjector( + address _ejector + ) external virtual; + function setOperatorSetParams( + uint8 quorumNumber, + OperatorSetParam memory operatorSetParams + ) external virtual; + function updateOperators( + address[] memory operators + ) external virtual; + function updateOperatorsForQuorum( + address[][] memory operatorsPerQuorum, + bytes calldata quorumNumbers + ) external virtual; + function updateSocket( + string memory socket + ) external virtual; + + // Keep existing implementations + function blsApkRegistry() external view virtual returns (IBLSApkRegistry) {} + function ejectOperator(address operator, bytes calldata quorumNumbers) external virtual {} function getOperatorSetParams( uint8 quorumNumber - ) external view returns (OperatorSetParam memory) {} - - function indexRegistry() external view returns (IIndexRegistry) {} - - function stakeRegistry() external view returns (IStakeRegistry) {} - - function quorumCount() external view returns (uint8) {} - /// @notice Returns the bitmap of the quorums the operator is registered for. - function operatorIdToQuorumBitmap( - bytes32 pubkeyHash - ) external view returns (uint256) {} - + ) external view virtual returns (OperatorSetParam memory) {} + function indexRegistry() external view virtual returns (IIndexRegistry) {} + function stakeRegistry() external view virtual returns (IStakeRegistry) {} + function quorumCount() external view virtual returns (uint8) {} function getOperator( address operator - ) external view returns (OperatorInfo memory) {} - - /// @notice Returns the stored id for the specified `operator`. + ) external view virtual returns (OperatorInfo memory) {} function getOperatorId( address operator - ) external view returns (bytes32) {} - - /// @notice Returns the operator address for the given `operatorId` + ) external view virtual returns (bytes32) {} function getOperatorFromId( bytes32 operatorId - ) external view returns (address) {} - - /// @notice Returns the status for the given `operator` - function getOperatorStatus(address operator) external view returns (OperatorStatus){} - - /// @notice Returns task number from when `operator` has been registered. - function getFromTaskNumberForOperator( + ) external view virtual returns (address) {} + function getOperatorStatus( address operator - ) external view returns (uint32) {} - + ) external view virtual returns (OperatorStatus) {} function getQuorumBitmapIndicesAtBlockNumber( uint32 blockNumber, bytes32[] memory operatorIds - ) external view returns (uint32[] memory) {} - - /// @notice Returns the quorum bitmap for the given `operatorId` at the given `blockNumber` via the `index` + ) external view virtual returns (uint32[] memory) {} function getQuorumBitmapAtBlockNumberByIndex( bytes32 operatorId, uint32 blockNumber, uint256 index - ) external view returns (uint192) {} - - /// @notice Returns the `index`th entry in the operator with `operatorId`'s bitmap history + ) external view virtual returns (uint192) {} function getQuorumBitmapUpdateByIndex( bytes32 operatorId, uint256 index - ) external view returns (QuorumBitmapUpdate memory) {} - - /// @notice Returns the current quorum bitmap for the given `operatorId` + ) external view virtual returns (QuorumBitmapUpdate memory) {} function getCurrentQuorumBitmap( bytes32 operatorId - ) external view returns (uint192) {} - - /// @notice Returns the length of the quorum bitmap history for the given `operatorId` + ) external view virtual returns (uint192) {} function getQuorumBitmapHistoryLength( bytes32 operatorId - ) external view returns (uint256) {} - - function numRegistries() external view returns (uint256) {} - + ) external view virtual returns (uint256) {} + function numRegistries() external view virtual returns (uint256) {} function registries( uint256 - ) external view returns (address) {} - - function registerOperator(bytes memory quorumNumbers, bytes calldata) external {} - - function deregisterOperator(bytes calldata quorumNumbers, bytes calldata) external {} + ) external view virtual returns (address) {} + function deregisterOperator( + bytes calldata quorumNumbers + ) external virtual {} function pubkeyRegistrationMessageHash( address operator - ) public view returns (BN254.G1Point memory) { + ) public view virtual returns (BN254.G1Point memory) { return BN254.hashToG1(keccak256(abi.encode(operator))); } function quorumUpdateBlockNumber( uint8 quorumNumber - ) external view returns (uint256) {} - - function owner() external view returns (address) {} - - function serviceManager() external view returns (IServiceManager) {} + ) external view virtual returns (uint256) {} + function owner() external view virtual returns (address) {} + function serviceManager() external view virtual returns (IServiceManager) {} function isM2Quorum( uint8 quorumNumber - ) external view returns (bool) { + ) external view virtual returns (bool) { return false; } - - function accountIdentifier() external view returns (address) {} - - function deregisterOperator(bytes memory quorumNumbers) external {} - - function enableOperatorSets() external {} - - function registerOperator( - bytes memory quorumNumbers, - string memory socket, - IBLSApkRegistry.PubkeyRegistrationParams memory params, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature - ) external {} - - function registerOperatorWithChurn( - bytes calldata quorumNumbers, - string memory socket, - IBLSApkRegistry.PubkeyRegistrationParams memory params, - ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams, - ISignatureUtils.SignatureWithSaltAndExpiry memory churnApproverSignature, - ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature - ) external {} - - function disableM2QuorumRegistration() external {} - - function operatorSetsEnabled() external view returns (bool) {} } diff --git a/test/mocks/StakeRegistryMock.sol b/test/mocks/StakeRegistryMock.sol index a70c8f13..f428928e 100644 --- a/test/mocks/StakeRegistryMock.sol +++ b/test/mocks/StakeRegistryMock.sol @@ -12,6 +12,19 @@ contract StakeRegistryMock is IStakeRegistry { // bitmap returned by the mocked `updateOperatorStake` function uint192 updateOperatorStakeReturnBitmap; + function isOperatorSetQuorum( + uint8 quorumNumber + ) external view returns (bool) {} + + function getStakeHistoryLength( + bytes32 operatorId, + uint8 quorumNumber + ) external view returns (uint256) {} + + function setMinimumStakeForQuorum(uint8 quorumNumber, uint96 minimumStake) external {} + + function setSlashableStakeLookahead(uint8 quorumNumber, uint32 lookAheadBlocks) external {} + function set_updateOperatorStakeReturnBitmap( uint192 newValue ) external { diff --git a/test/unit/BLSApkRegistryUnit.t.sol b/test/unit/BLSApkRegistryUnit.t.sol index 295d5cec..785811fd 100644 --- a/test/unit/BLSApkRegistryUnit.t.sol +++ b/test/unit/BLSApkRegistryUnit.t.sol @@ -66,13 +66,13 @@ contract BLSApkRegistryUnitTests is BLSMockAVSDeployer, IBLSApkRegistryEvents { //privKey*G2 pubkeyRegistrationParams.pubkeyG2.X[1] = - 19_101_821_850_089_705_274_637_533_855_249_918_363_070_101_489_527_618_151_493_230_256_975_900_223_847; + 19101821850089705274637533855249918363070101489527618151493230256975900223847; pubkeyRegistrationParams.pubkeyG2.X[0] = - 5_334_410_886_741_819_556_325_359_147_377_682_006_012_228_123_419_628_681_352_847_439_302_316_235_957; + 5334410886741819556325359147377682006012228123419628681352847439302316235957; pubkeyRegistrationParams.pubkeyG2.Y[1] = - 354_176_189_041_917_478_648_604_979_334_478_067_325_821_134_838_555_150_300_539_079_146_482_658_331; + 354176189041917478648604979334478067325821134838555150300539079146482658331; pubkeyRegistrationParams.pubkeyG2.Y[0] = - 4_185_483_097_059_047_421_902_184_823_581_361_466_320_657_066_600_218_863_748_375_739_772_335_928_910; + 4185483097059047421902184823581361466320657066600218863748375739772335928910; // Initialize 3 quorums _initializeQuorum(); diff --git a/test/unit/BLSSignatureCheckerUnit.t.sol b/test/unit/BLSSignatureCheckerUnit.t.sol index a58d6112..ef13c575 100644 --- a/test/unit/BLSSignatureCheckerUnit.t.sol +++ b/test/unit/BLSSignatureCheckerUnit.t.sol @@ -3,7 +3,10 @@ pragma solidity ^0.8.27; import "../../src/BLSSignatureChecker.sol"; import "../utils/BLSMockAVSDeployer.sol"; -import {IBLSSignatureCheckerErrors} from "../../src/interfaces/IBLSSignatureChecker.sol"; +import { + IBLSSignatureCheckerErrors, + IBLSSignatureCheckerTypes +} from "../../src/interfaces/IBLSSignatureChecker.sol"; import {IBLSApkRegistryErrors} from "../../src/interfaces/IBLSApkRegistry.sol"; import {QuorumBitmapHistoryLib} from "../../src/libraries/QuorumBitmapHistoryLib.sol"; import {IStakeRegistryErrors} from "../../src/interfaces/IStakeRegistry.sol"; @@ -128,12 +131,12 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { assertEq( quorumStakeTotals.signedStakeForQuorum[0], - 3_000_000_000_000_000_000, + 3000000000000000000, "signedStakeForQuorum incorrect" ); assertEq( quorumStakeTotals.totalStakeForQuorum[0], - 4_000_000_000_000_000_000, + 4000000000000000000, "totalStakeForQuorum incorrect" ); } @@ -201,8 +204,8 @@ contract BLSSignatureCheckerUnitTests is BLSMockAVSDeployer { 1, numNonSigners, quorumBitmap ); - IBLSSignatureChecker.NonSignerStakesAndSignature memory incorrectLengthInputs = - IBLSSignatureChecker.NonSignerStakesAndSignature({ + IBLSSignatureCheckerTypes.NonSignerStakesAndSignature memory incorrectLengthInputs = + IBLSSignatureCheckerTypes.NonSignerStakesAndSignature({ nonSignerQuorumBitmapIndices: nonSignerStakesAndSignature.nonSignerQuorumBitmapIndices, nonSignerPubkeys: nonSignerStakesAndSignature.nonSignerPubkeys, quorumApks: nonSignerStakesAndSignature.quorumApks, diff --git a/test/unit/BitmapUtils.t.sol b/test/unit/BitmapUtils.t.sol index 1563d687..6e62f466 100644 --- a/test/unit/BitmapUtils.t.sol +++ b/test/unit/BitmapUtils.t.sol @@ -298,7 +298,7 @@ contract BitmapUtilsUnitTests_bytesArrayToBitmap is BitmapUtilsUnitTests { function test_bitmapToBytesArrayToBitmap_distributedTenEntriesBitmap() public { // 2^0+2^10+2^20+2^30+2^40+2^50+2^60+2^70+2^80+2^90 - uint256 originalBitmap = 1_239_150_146_850_664_126_585_242_625; + uint256 originalBitmap = 1239150146850664126585242625; testFuzz_bitmapToBytesArrayToBitmap(originalBitmap); } } diff --git a/test/unit/ECDSAServiceManager.t.sol b/test/unit/ECDSAServiceManager.t.sol index bcd17052..aac2bd38 100644 --- a/test/unit/ECDSAServiceManager.t.sol +++ b/test/unit/ECDSAServiceManager.t.sol @@ -10,7 +10,7 @@ // import {ECDSAServiceManagerMock} from "../mocks/ECDSAServiceManagerMock.sol"; // import {ECDSAStakeRegistryMock} from "../mocks/ECDSAStakeRegistryMock.sol"; -// import {Quorum, StrategyParams} from "../../src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; +// import {IECDSAStakeRegistryTypes.Quorum, StrategyParams} from "../../src/interfaces/IECDSAStakeRegistry.sol"; // contract MockDelegationManager { // function operatorShares(address, address) external pure returns (uint256) { @@ -84,7 +84,7 @@ // operator2 = vm.addr(operator2Pk); // // Create a quorum -// Quorum memory quorum = Quorum({strategies: new StrategyParams[](2)}); +// IECDSAStakeRegistryTypes.Quorum memory quorum = IECDSAStakeRegistryTypes.Quorum({strategies: new StrategyParams[](2)}); // quorum.strategies[0] = StrategyParams({ // strategy: IStrategy(address(420)), // multiplier: 5000 diff --git a/test/unit/ECDSAStakeRegistryEqualWeightUnit.t.sol b/test/unit/ECDSAStakeRegistryEqualWeightUnit.t.sol index 2878e67d..befc76c4 100644 --- a/test/unit/ECDSAStakeRegistryEqualWeightUnit.t.sol +++ b/test/unit/ECDSAStakeRegistryEqualWeightUnit.t.sol @@ -7,10 +7,9 @@ import {IDelegationManager} from import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import { - ECDSAStakeRegistryEventsAndErrors, - Quorum, - StrategyParams -} from "../../src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; + IECDSAStakeRegistry, + IECDSAStakeRegistryTypes +} from "../../src/interfaces/IECDSAStakeRegistry.sol"; import {ECDSAStakeRegistrySetup} from "./ECDSAStakeRegistryUnit.t.sol"; import {ECDSAStakeRegistryEqualWeight} from "../../src/unaudited/examples/ECDSAStakeRegistryEqualWeight.sol"; @@ -23,8 +22,9 @@ contract EqualWeightECDSARegistry is ECDSAStakeRegistrySetup { fixedWeightRegistry = new ECDSAStakeRegistryEqualWeight(IDelegationManager(address(mockDelegationManager))); IStrategy mockStrategy = IStrategy(address(0x1234)); - Quorum memory quorum = Quorum({strategies: new StrategyParams[](1)}); - quorum.strategies[0] = StrategyParams({strategy: mockStrategy, multiplier: 10_000}); + IECDSAStakeRegistryTypes.Quorum memory quorum = + IECDSAStakeRegistryTypes.Quorum({strategies: new StrategyParams[](1)}); + quorum.strategies[0] = StrategyParams({strategy: mockStrategy, multiplier: 10000}); fixedWeightRegistry.initialize(address(mockServiceManager), 100, quorum); fixedWeightRegistry.permitOperator(operator1); diff --git a/test/unit/ECDSAStakeRegistryPermissionedUnit.t.sol b/test/unit/ECDSAStakeRegistryPermissionedUnit.t.sol index ced14a41..7269e1ce 100644 --- a/test/unit/ECDSAStakeRegistryPermissionedUnit.t.sol +++ b/test/unit/ECDSAStakeRegistryPermissionedUnit.t.sol @@ -7,10 +7,10 @@ import {IDelegationManager} from import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import { - ECDSAStakeRegistryEventsAndErrors, - Quorum, - StrategyParams -} from "../../src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; + IECDSAStakeRegistry, + IECDSAStakeRegistryTypes, + IECDSAStakeRegistryErrors +} from "../../src/interfaces/IECDSAStakeRegistry.sol"; import {ECDSAStakeRegistrySetup} from "./ECDSAStakeRegistryUnit.t.sol"; import {ECDSAStakeRegistryPermissioned} from "../../src/unaudited/examples/ECDSAStakeRegistryPermissioned.sol"; @@ -23,8 +23,9 @@ contract PermissionedECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { permissionedRegistry = new ECDSAStakeRegistryPermissioned(IDelegationManager(address(mockDelegationManager))); IStrategy mockStrategy = IStrategy(address(0x1234)); - Quorum memory quorum = Quorum({strategies: new StrategyParams[](1)}); - quorum.strategies[0] = StrategyParams({strategy: mockStrategy, multiplier: 10_000}); + IECDSAStakeRegistryTypes.Quorum memory quorum = + IECDSAStakeRegistryTypes.Quorum({strategies: new StrategyParams[](1)}); + quorum.strategies[0] = StrategyParams({strategy: mockStrategy, multiplier: 10000}); permissionedRegistry.initialize(address(mockServiceManager), 100, quorum); permissionedRegistry.permitOperator(operator1); @@ -75,7 +76,9 @@ contract PermissionedECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { function test_RevertsWhen_NotOperator_EjectOperator() public { address notOperator = address(0xBEEF); - vm.expectRevert(abi.encodeWithSelector(OperatorNotRegistered.selector)); + vm.expectRevert( + abi.encodeWithSelector(IECDSAStakeRegistryErrors.OperatorNotRegistered.selector) + ); permissionedRegistry.ejectOperator(notOperator); } diff --git a/test/unit/ECDSAStakeRegistryUnit.t.sol b/test/unit/ECDSAStakeRegistryUnit.t.sol index 89a4dc98..540f8dcc 100644 --- a/test/unit/ECDSAStakeRegistryUnit.t.sol +++ b/test/unit/ECDSAStakeRegistryUnit.t.sol @@ -10,10 +10,11 @@ import {IStrategy} from "eigenlayer-contracts/src/contracts/interfaces/IStrategy import {ECDSAStakeRegistry} from "../../src/unaudited/ECDSAStakeRegistry.sol"; import { - ECDSAStakeRegistryEventsAndErrors, - Quorum, - StrategyParams -} from "../../src/interfaces/IECDSAStakeRegistryEventsAndErrors.sol"; + IECDSAStakeRegistry, + IECDSAStakeRegistryErrors, + IECDSAStakeRegistryTypes, + IECDSAStakeRegistryEvents +} from "../../src/interfaces/IECDSAStakeRegistry.sol"; contract MockServiceManager { // solhint-disable-next-line @@ -44,7 +45,7 @@ contract MockDelegationManager { } } -contract ECDSAStakeRegistrySetup is Test, ECDSAStakeRegistryEventsAndErrors { +contract ECDSAStakeRegistrySetup is Test, IECDSAStakeRegistryEvents { MockDelegationManager public mockDelegationManager; MockServiceManager public mockServiceManager; ECDSAStakeRegistry public registry; @@ -64,8 +65,11 @@ contract ECDSAStakeRegistrySetup is Test, ECDSAStakeRegistryEventsAndErrors { mockDelegationManager = new MockDelegationManager(); mockServiceManager = new MockServiceManager(); IStrategy mockStrategy = IStrategy(address(0x1234)); - Quorum memory quorum = Quorum({strategies: new StrategyParams[](1)}); - quorum.strategies[0] = StrategyParams({strategy: mockStrategy, multiplier: 10_000}); + IECDSAStakeRegistryTypes.Quorum memory quorum = IECDSAStakeRegistryTypes.Quorum({ + strategies: new IECDSAStakeRegistryTypes.StrategyParams[](1) + }); + quorum.strategies[0] = + IECDSAStakeRegistryTypes.StrategyParams({strategy: mockStrategy, multiplier: 10000}); registry = new ECDSAStakeRegistry(IDelegationManager(address(mockDelegationManager))); registry.initialize(address(mockServiceManager), 100, quorum); ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; @@ -81,9 +85,12 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { function test_UpdateQuorumConfig() public { IStrategy mockStrategy = IStrategy(address(420)); - Quorum memory oldQuorum = registry.quorum(); - Quorum memory newQuorum = Quorum({strategies: new StrategyParams[](1)}); - newQuorum.strategies[0] = StrategyParams({strategy: mockStrategy, multiplier: 10_000}); + IECDSAStakeRegistryTypes.Quorum memory oldQuorum = registry.quorum(); + IECDSAStakeRegistryTypes.Quorum memory newQuorum = IECDSAStakeRegistryTypes.Quorum({ + strategies: new IECDSAStakeRegistryTypes.StrategyParams[](1) + }); + newQuorum.strategies[0] = + IECDSAStakeRegistryTypes.StrategyParams({strategy: mockStrategy, multiplier: 10000}); address[] memory operators = new address[](2); operators[0] = operator1; operators[1] = operator2; @@ -95,8 +102,10 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { } function test_RevertsWhen_InvalidQuorum_UpdateQuourmConfig() public { - Quorum memory invalidQuorum = Quorum({strategies: new StrategyParams[](1)}); - invalidQuorum.strategies[0] = StrategyParams({ + IECDSAStakeRegistryTypes.Quorum memory invalidQuorum = IECDSAStakeRegistryTypes.Quorum({ + strategies: new IECDSAStakeRegistryTypes.StrategyParams[](1) + }); + invalidQuorum.strategies[0] = IECDSAStakeRegistryTypes.StrategyParams({ /// TODO: Make mock strategy strategy: IStrategy(address(420)), multiplier: 5000 // This should cause the update to revert as it's not the total required @@ -105,14 +114,18 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { operators[0] = operator1; operators[1] = operator2; - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.InvalidQuorum.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.InvalidQuorum.selector); registry.updateQuorumConfig(invalidQuorum, operators); } function test_RevertsWhen_NotOwner_UpdateQuorumConfig() public { - Quorum memory validQuorum = Quorum({strategies: new StrategyParams[](1)}); - validQuorum.strategies[0] = - StrategyParams({strategy: IStrategy(address(420)), multiplier: 10_000}); + IECDSAStakeRegistryTypes.Quorum memory validQuorum = IECDSAStakeRegistryTypes.Quorum({ + strategies: new IECDSAStakeRegistryTypes.StrategyParams[](1) + }); + validQuorum.strategies[0] = IECDSAStakeRegistryTypes.StrategyParams({ + strategy: IStrategy(address(420)), + multiplier: 10000 + }); address[] memory operators = new address[](2); operators[0] = operator1; @@ -126,7 +139,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { } function test_RevertsWhen_SameQuorum_UpdateQuorumConfig() public { - Quorum memory quorum = registry.quorum(); + IECDSAStakeRegistryTypes.Quorum memory quorum = registry.quorum(); address[] memory operators = new address[](2); operators[0] = operator1; operators[1] = operator2; @@ -136,7 +149,8 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { } function test_RevertSWhen_Duplicate_UpdateQuorumConfig() public { - Quorum memory invalidQuorum = Quorum({strategies: new StrategyParams[](2)}); + IECDSAStakeRegistryTypes.Quorum memory invalidQuorum = + IECDSAStakeRegistryTypes.Quorum({strategies: new StrategyParams[](2)}); invalidQuorum.strategies[0] = StrategyParams({strategy: IStrategy(address(420)), multiplier: 5000}); address[] memory operators = new address[](2); @@ -145,12 +159,13 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { invalidQuorum.strategies[1] = StrategyParams({strategy: IStrategy(address(420)), multiplier: 5000}); - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.NotSorted.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.NotSorted.selector); registry.updateQuorumConfig(invalidQuorum, operators); } function test_RevertSWhen_NotSorted_UpdateQuorumConfig() public { - Quorum memory invalidQuorum = Quorum({strategies: new StrategyParams[](2)}); + IECDSAStakeRegistryTypes.Quorum memory invalidQuorum = + IECDSAStakeRegistryTypes.Quorum({strategies: new StrategyParams[](2)}); invalidQuorum.strategies[0] = StrategyParams({strategy: IStrategy(address(420)), multiplier: 5000}); address[] memory operators = new address[](2); @@ -159,19 +174,20 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { invalidQuorum.strategies[1] = StrategyParams({strategy: IStrategy(address(419)), multiplier: 5000}); - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.NotSorted.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.NotSorted.selector); registry.updateQuorumConfig(invalidQuorum, operators); } function test_RevertSWhen_OverMultiplierTotal_UpdateQuorumConfig() public { - Quorum memory invalidQuorum = Quorum({strategies: new StrategyParams[](1)}); + IECDSAStakeRegistryTypes.Quorum memory invalidQuorum = + IECDSAStakeRegistryTypes.Quorum({strategies: new StrategyParams[](1)}); invalidQuorum.strategies[0] = - StrategyParams({strategy: IStrategy(address(420)), multiplier: 10_001}); + StrategyParams({strategy: IStrategy(address(420)), multiplier: 10001}); address[] memory operators = new address[](2); operators[0] = operator1; operators[1] = operator2; - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.InvalidQuorum.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.InvalidQuorum.selector); registry.updateQuorumConfig(invalidQuorum, operators); } @@ -189,7 +205,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { assertEq(registry.getLastCheckpointTotalWeight(), 2000); ISignatureUtils.SignatureWithSaltAndExpiry memory signature; - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.OperatorAlreadyRegistered.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.OperatorAlreadyRegistered.selector); vm.prank(operator1); registry.registerOperatorWithSignature(signature, operator1); } @@ -225,7 +241,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { function test_RevertsWhen_NotOperator_DeregisterOperator() public { address notOperator = address(0x2); vm.prank(notOperator); - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.OperatorNotRegistered.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.OperatorNotRegistered.selector); registry.deregisterOperator(); } @@ -302,7 +318,8 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { IStrategy mockStrategy = IStrategy(address(420)); IStrategy mockStrategy2 = IStrategy(address(421)); - Quorum memory quorum = Quorum({strategies: new StrategyParams[](2)}); + IECDSAStakeRegistryTypes.Quorum memory quorum = + IECDSAStakeRegistryTypes.Quorum({strategies: new StrategyParams[](2)}); quorum.strategies[0] = StrategyParams({strategy: mockStrategy, multiplier: 5000}); quorum.strategies[1] = StrategyParams({strategy: mockStrategy2, multiplier: 5000}); @@ -387,13 +404,13 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { } function testUpdateThresholdStake_UpdateThresholdStake() public { - uint256 thresholdWeight = 10_000_000_000; + uint256 thresholdWeight = 10000000000; vm.prank(registry.owner()); registry.updateStakeThreshold(thresholdWeight); } function test_RevertsWhen_NotOwner_UpdateThresholdStake() public { - uint256 thresholdWeight = 10_000_000_000; + uint256 thresholdWeight = 10000000000; address notOwner = address(0x123); vm.prank(notOwner); vm.expectRevert("Ownable: caller is not the owner"); @@ -421,7 +438,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { (uint8 v, bytes32 r, bytes32 s) = vm.sign(operator1Pk, msgHash); signatures[0] = abi.encode(v, r, s); - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.LengthMismatch.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.LengthMismatch.selector); registry.isValidSignature(msgHash, abi.encode(signers, signatures, block.number - 1)); } @@ -430,7 +447,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { address[] memory signers = new address[](0); bytes[] memory signatures = new bytes[](0); - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.InvalidLength.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.InvalidLength.selector); registry.isValidSignature(dataHash, abi.encode(signers, signatures, block.number - 1)); } @@ -445,7 +462,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { (v, r, s) = vm.sign(operator2Pk, msgHash); signatures[0] = abi.encodePacked(r, s, v); - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.NotSorted.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.NotSorted.selector); registry.isValidSignature(msgHash, abi.encode(signers, signatures, block.number - 1)); } @@ -463,7 +480,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { signatures[0] = abi.encodePacked(r, s, v); signatures[1] = abi.encodePacked(r, s, v); - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.NotSorted.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.NotSorted.selector); registry.isValidSignature(msgHash, abi.encode(signers, signatures, block.number - 1)); } @@ -474,7 +491,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { bytes[] memory signatures = new bytes[](1); signatures[0] = "invalid-signature"; - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.InvalidSignature.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.InvalidSignature.selector); registry.isValidSignature(dataHash, abi.encode(signers, signatures, block.number - 1)); } @@ -489,7 +506,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { (v, r, s) = vm.sign(operator2Pk, msgHash); signatures[1] = abi.encodePacked(r, s, v); - uint256 thresholdWeight = 10_000_000_000; + uint256 thresholdWeight = 10000000000; vm.prank(registry.owner()); registry.updateStakeThreshold(thresholdWeight); vm.roll(block.number + 1); @@ -502,7 +519,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { abi.encode(50) ); - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.InsufficientSignedStake.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.InsufficientSignedStake.selector); registry.isValidSignature(msgHash, abi.encode(signers, signatures, block.number - 1)); } @@ -514,7 +531,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { signers[1] = operator2; bytes[] memory signatures = new bytes[](1); - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.LengthMismatch.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.LengthMismatch.selector); registry.isValidSignature(dataHash, abi.encode(signers, signatures, referenceBlock)); } @@ -524,7 +541,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { address[] memory signers = new address[](0); bytes[] memory signatures = new bytes[](0); - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.InvalidLength.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.InvalidLength.selector); registry.isValidSignature(dataHash, abi.encode(signers, signatures, referenceBlock)); } @@ -541,7 +558,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { (v, r, s) = vm.sign(operator2Pk, msgHash); signatures[0] = abi.encodePacked(r, s, v); - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.NotSorted.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.NotSorted.selector); registry.isValidSignature(msgHash, abi.encode(signers, signatures, referenceBlock)); } @@ -557,7 +574,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { (v, r, s) = vm.sign(operator2Pk, msgHash); signatures[1] = abi.encodePacked(r, s, v); - uint256 thresholdWeight = 10_000_000_000; + uint256 thresholdWeight = 10000000000; vm.prank(registry.owner()); registry.updateStakeThreshold(thresholdWeight); vm.roll(referenceBlock + 1); @@ -570,7 +587,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { abi.encode(50) ); - vm.expectRevert(ECDSAStakeRegistryEventsAndErrors.InsufficientSignedStake.selector); + vm.expectRevert(IECDSAStakeRegistryErrors.InsufficientSignedStake.selector); registry.isValidSignature(msgHash, abi.encode(signers, signatures, referenceBlock)); } @@ -643,7 +660,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { registry.registerOperatorWithSignature(operatorSignature, signer); // Verify that the signing key has been successfully registered for the operator - address registeredSigningKey = registry.getLastestOperatorSigningKey(operator); + address registeredSigningKey = registry.getLatestOperatorSigningKey(operator); assertEq( registeredSigningKey, signer, @@ -665,7 +682,7 @@ contract ECDSAStakeRegistryTest is ECDSAStakeRegistrySetup { registry.updateOperatorSigningKey(address(420)); // Verify that the signing key has been successfully registered for the operator - address registeredSigningKey = registry.getLastestOperatorSigningKey(operator); + address registeredSigningKey = registry.getLatestOperatorSigningKey(operator); vm.roll(block.number + 1); registeredSigningKey = diff --git a/test/unit/EjectionManagerUnit.t.sol b/test/unit/EjectionManagerUnit.t.sol index 886a94f5..6ff658a9 100644 --- a/test/unit/EjectionManagerUnit.t.sol +++ b/test/unit/EjectionManagerUnit.t.sol @@ -3,8 +3,12 @@ pragma solidity ^0.8.27; import {EjectionManager} from "../../src/EjectionManager.sol"; -import {IEjectionManager, IEjectionManagerErrors} from "../../src/interfaces/IEjectionManager.sol"; - +import { + IEjectionManager, + IEjectionManagerErrors, + IEjectionManagerTypes +} from "../../src/interfaces/IEjectionManager.sol"; +import {ISlashingRegistryCoordinatorTypes} from "../../src/interfaces/IRegistryCoordinator.sol"; import "../utils/MockAVSDeployer.sol"; contract EjectionManagerUnitTests is MockAVSDeployer { @@ -18,7 +22,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { EjectionManager public ejectionManager; IEjectionManager public ejectionManagerImplementation; - IEjectionManager.QuorumEjectionParams[] public quorumEjectionParams; + IEjectionManagerTypes.QuorumEjectionParams[] public quorumEjectionParams; uint32 public ratelimitWindow = 1 days; uint16 public ejectableStakePercent = 1000; @@ -26,7 +30,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { function setUp() public virtual { for (uint8 i = 0; i < numQuorums; i++) { quorumEjectionParams.push( - IEjectionManager.QuorumEjectionParams({ + IEjectionManagerTypes.QuorumEjectionParams({ rateLimitWindow: ratelimitWindow, ejectableStakePercent: ejectableStakePercent }) @@ -42,7 +46,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { ) ); - ejectionManagerImplementation = new EjectionManager(registryCoordinator, stakeRegistry); + ejectionManagerImplementation = + new EjectionManager(IRegistryCoordinator(address(registryCoordinator)), stakeRegistry); address[] memory ejectors = new address[](1); ejectors[0] = ejector; @@ -80,7 +85,10 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } - assertEq(uint8(registryCoordinator.getOperatorStatus(defaultOperator)), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); + assertEq( + uint8(registryCoordinator.getOperatorStatus(defaultOperator)), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED) + ); for (uint8 i = 0; i < numQuorums; i++) { for (uint8 j = 0; j < operatorsToEject; j++) { @@ -92,7 +100,10 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - assertEq(uint8(registryCoordinator.getOperatorStatus(defaultOperator)), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); + assertEq( + uint8(registryCoordinator.getOperatorStatus(defaultOperator)), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED) + ); } function testEjectOperators_MultipleOperatorInsideRatelimit() public { @@ -110,8 +121,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED) + ); } for (uint8 i = 0; i < numQuorums; i++) { @@ -124,8 +138,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED) + ); } } @@ -145,8 +162,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED) + ); } for (uint8 i = 0; i < numQuorums; i++) { @@ -159,12 +179,18 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsCanEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsCanEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED) + ); } - for(uint8 i = operatorsCanEject; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = operatorsCanEject; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED) + ); } } @@ -183,8 +209,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED) + ); } for (uint8 i = 0; i < numQuorums; i++) { @@ -197,8 +226,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED) + ); } cheats.warp(block.timestamp + (ratelimitWindow / 2)); @@ -213,8 +245,15 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, operatorsToEject + i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8( + registryCoordinator.getOperatorStatus( + _incrementAddress(defaultOperator, operatorsToEject + i) + ) + ), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED) + ); } for (uint8 i = 0; i < numQuorums; i++) { @@ -227,8 +266,15 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, operatorsToEject + i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8( + registryCoordinator.getOperatorStatus( + _incrementAddress(defaultOperator, operatorsToEject + i) + ) + ), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED) + ); } } @@ -254,8 +300,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED) + ); } for (uint8 i = 0; i < numQuorums; i++) { @@ -268,8 +317,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED) + ); } } @@ -288,8 +340,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } } - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED) + ); } for (uint8 i = 0; i < numQuorums; i++) { @@ -302,8 +357,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(registryCoordinatorOwner); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED) + ); } } @@ -325,8 +383,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(defaultOperator); registryCoordinator.deregisterOperator(BitmapUtils.bitmapToBytesArray(MAX_QUORUM_BITMAP)); - for(uint8 i = 1; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.REGISTERED)); + for (uint8 i = 1; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED) + ); } for (uint8 i = 0; i < numQuorums; i++) { @@ -339,8 +400,11 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED) + ); } } @@ -348,8 +412,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { uint8 quorumNumber = 0; ratelimitWindow = 2 days; ejectableStakePercent = 2000; - IEjectionManager.QuorumEjectionParams memory _quorumEjectionParams = IEjectionManager - .QuorumEjectionParams({ + IEjectionManagerTypes.QuorumEjectionParams memory _quorumEjectionParams = + IEjectionManagerTypes.QuorumEjectionParams({ rateLimitWindow: ratelimitWindow, ejectableStakePercent: ejectableStakePercent }); @@ -393,13 +457,13 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(registryCoordinatorOwner); ejectionManager.setQuorumEjectionParams( 0, - IEjectionManager.QuorumEjectionParams({ + IEjectionManagerTypes.QuorumEjectionParams({ rateLimitWindow: 7 days, ejectableStakePercent: 9999 }) ); - stakeRegistry.recordTotalStakeUpdate(1, 2_000_000_000 * 1 ether); + stakeRegistry.recordTotalStakeUpdate(1, 2000000000 * 1 ether); ejectionManager.amountEjectableForQuorum(1); } diff --git a/test/unit/IndexRegistryUnit.t.sol b/test/unit/IndexRegistryUnit.t.sol index 8846ff9d..0a6d424c 100644 --- a/test/unit/IndexRegistryUnit.t.sol +++ b/test/unit/IndexRegistryUnit.t.sol @@ -4,7 +4,7 @@ pragma solidity ^0.8.27; import "../../src/interfaces/IIndexRegistry.sol"; import "../../src/IndexRegistry.sol"; import "../harnesses/BitmapUtilsWrapper.sol"; -import {IIndexRegistryEvents} from "../events/IIndexRegistryEvents.sol"; +import {IIndexRegistryEvents} from "../../src/interfaces/IIndexRegistry.sol"; import "../utils/MockAVSDeployer.sol"; diff --git a/test/unit/OperatorStateRetrieverUnit.t.sol b/test/unit/OperatorStateRetrieverUnit.t.sol index cc40349c..79a93988 100644 --- a/test/unit/OperatorStateRetrieverUnit.t.sol +++ b/test/unit/OperatorStateRetrieverUnit.t.sol @@ -3,6 +3,7 @@ pragma solidity ^0.8.27; import "../utils/MockAVSDeployer.sol"; import {IStakeRegistryErrors} from "../../src/interfaces/IStakeRegistry.sol"; +import {ISlashingRegistryCoordinatorTypes} from "../../src/interfaces/IRegistryCoordinator.sol"; contract OperatorStateRetrieverUnitTests is MockAVSDeployer { using BN254 for BN254.G1Point; @@ -81,17 +82,19 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { function test_getOperatorState_revert_quorumNotCreatedAtReferenceBlockNumber() public { cheats.roll(registrationBlockNumber); - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator - .OperatorSetParam({ + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: defaultMaxOperatorCount, kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake }); uint96 minimumStake = 1; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = - IStakeRegistry.StrategyParams({strategy: IStrategy(address(1000)), multiplier: 1e16}); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); + strategyParams[0] = IStakeRegistryTypes.StrategyParams({ + strategy: IStrategy(address(1000)), + multiplier: 1e16 + }); cheats.prank(registryCoordinator.owner()); registryCoordinator.createTotalDelegatedStakeQuorum( @@ -223,17 +226,19 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { bytes32[] memory nonSignerOperatorIds = new bytes32[](1); nonSignerOperatorIds[0] = defaultOperatorId; - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator - .OperatorSetParam({ + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: defaultMaxOperatorCount, kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake }); uint96 minimumStake = 1; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = - IStakeRegistry.StrategyParams({strategy: IStrategy(address(1000)), multiplier: 1e16}); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); + strategyParams[0] = IStakeRegistryTypes.StrategyParams({ + strategy: IStrategy(address(1000)), + multiplier: 1e16 + }); cheats.prank(registryCoordinator.owner()); registryCoordinator.createTotalDelegatedStakeQuorum( @@ -255,8 +260,7 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { uint256 quorumBitmapThree = 3; assertFalse( - registryCoordinator.operatorSetsEnabled(), - "operatorSetsEnabled should be false" + registryCoordinator.operatorSetsEnabled(), "operatorSetsEnabled should be false" ); cheats.roll(registrationBlockNumber); diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index 06a19576..a734171a 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -2,7 +2,13 @@ pragma solidity ^0.8.27; import "../utils/MockAVSDeployer.sol"; -import {ISlashingRegistryCoordinator, IRegistryCoordinatorErrors} from "../../src/interfaces/ISlashingRegistryCoordinator.sol"; +import { + ISlashingRegistryCoordinator, + ISlashingRegistryCoordinatorTypes, + ISlashingRegistryCoordinatorErrors +} from "../../src/interfaces/ISlashingRegistryCoordinator.sol"; + +import {IBLSApkRegistryTypes} from "../../src/interfaces/IBLSApkRegistry.sol"; import {QuorumBitmapHistoryLib} from "../../src/libraries/QuorumBitmapHistoryLib.sol"; import {BitmapUtils} from "../../src/libraries/BitmapUtils.sol"; import {console} from "forge-std/console.sol"; @@ -35,7 +41,10 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { // emitted when an operator's index in the orderd operator list for the quorum with number `quorumNumber` is updated event QuorumIndexUpdate(bytes32 indexed operatorId, uint8 quorumNumber, uint32 newIndex); - event OperatorSetParamsUpdated(uint8 indexed quorumNumber, ISlashingRegistryCoordinator.OperatorSetParam operatorSetParams); + event OperatorSetParamsUpdated( + uint8 indexed quorumNumber, + ISlashingRegistryCoordinatorTypes.OperatorSetParam operatorSetParams + ); event ChurnApproverUpdated(address prevChurnApprover, address newChurnApprover); @@ -51,11 +60,14 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { uint256 pseudoRandomNumber, bytes memory quorumNumbers, uint96 operatorToKickStake - ) internal returns( - address operatorToRegister, - BN254.G1Point memory operatorToRegisterPubKey, - ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams - ) { + ) + internal + returns ( + address operatorToRegister, + BN254.G1Point memory operatorToRegisterPubKey, + ISlashingRegistryCoordinatorTypes.OperatorKickParam[] memory operatorKickParams + ) + { uint32 kickRegistrationBlockNumber = 100; uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); @@ -78,7 +90,7 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { address operatorToKick; // register last operator before kick - operatorKickParams = new ISlashingRegistryCoordinator.OperatorKickParam[](1); + operatorKickParams = new ISlashingRegistryCoordinatorTypes.OperatorKickParam[](1); { BN254.G1Point memory pubKey = BN254.hashToG1( keccak256(abi.encodePacked(pseudoRandomNumber, defaultMaxOperatorCount - 1)) @@ -95,7 +107,7 @@ contract RegistryCoordinatorUnitTests is MockAVSDeployer { // operatorIdsToSwap[0] = operatorToRegisterId operatorIdsToSwap[0] = operatorToRegisterId; - operatorKickParams[0] = ISlashingRegistryCoordinator.OperatorKickParam({ + operatorKickParams[0] = ISlashingRegistryCoordinatorTypes.OperatorKickParam({ quorumNumber: uint8(quorumNumbers[0]), operator: operatorToKick }); @@ -125,7 +137,7 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina registryCoordinatorOwner, churnApprover, ejector, - 0/*initialPausedStatus*/, + 0, // _initialPausedStatus address(serviceManager) // _accountIdentifier ); } @@ -200,9 +212,9 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina } function test_createQuorum_revert_notOwner() public { - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams; + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams; uint96 minimumStake; - IStakeRegistry.StrategyParams[] memory strategyParams; + IStakeRegistryTypes.StrategyParams[] memory strategyParams; cheats.expectRevert("Ownable: caller is not the owner"); cheats.prank(defaultOperator); @@ -216,17 +228,19 @@ contract RegistryCoordinatorUnitTests_Initialization_Setters is RegistryCoordina // this is necessary since the default setup already configures the max number of quorums, preventing adding more _deployMockEigenLayerAndAVS(0); - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = - ISlashingRegistryCoordinator.OperatorSetParam({ - maxOperatorCount: defaultMaxOperatorCount, - kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, - kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake - }); + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ + maxOperatorCount: defaultMaxOperatorCount, + kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, + kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake + }); uint96 minimumStake = 1; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = - IStakeRegistry.StrategyParams({strategy: IStrategy(address(1000)), multiplier: 1e16}); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); + strategyParams[0] = IStakeRegistryTypes.StrategyParams({ + strategy: IStrategy(address(1000)), + multiplier: 1e16 + }); uint8 quorumCountBefore = registryCoordinator.quorumCount(); @@ -332,19 +346,29 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED + }) + ) + ) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }) + ) + ) ); } @@ -390,19 +414,29 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED + }) + ) + ) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }) + ) + ) ); } @@ -447,27 +481,43 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED + }) + ) + ) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers)), - updateBlockNumber: uint32(registrationBlockNumber), - nextUpdateBlockNumber: uint32(nextRegistrationBlockNumber) - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers)), + updateBlockNumber: uint32(registrationBlockNumber), + nextUpdateBlockNumber: uint32(nextRegistrationBlockNumber) + }) + ) + ) ); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(nextRegistrationBlockNumber), - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1)) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(nextRegistrationBlockNumber), + nextUpdateBlockNumber: 0 + }) + ) + ) ); } @@ -595,12 +645,18 @@ contract RegistryCoordinatorUnitTests_RegisterOperator is RegistryCoordinatorUni assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }) + ) + ) ); } } @@ -643,6 +699,8 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is cheats.prank(registryCoordinator.owner()); registryCoordinator.enableOperatorSets(); + console.log("quorumCount", registryCoordinator.quorumCount()); + assertTrue( registryCoordinator.isM2Quorum(uint8(defaultQuorumNumber)), "defaultQuorumNumber should be a M2 quorum" @@ -652,7 +710,6 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is quorumNumbers[0] = bytes1(defaultQuorumNumber); uint256 quorumBitmap = BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers); - quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(defaultQuorumNumber); @@ -696,19 +753,29 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED - }))) + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED + }) + ) + ) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }) + ) + ) ); } @@ -755,19 +822,29 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED - }))) + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED + }) + ) + ) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }) + ) + ) ); } // @notice verifies that an operator who was registered for a fuzzed set of quorums can be deregistered from a subset of those quorums @@ -826,18 +903,26 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is if (deregistrationQuorumBitmap == registrationQuorumBitmap) { assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED - }))) + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED + }) + ) + ) ); } else { assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED + }) + ) + ) ); } // ensure that the operator's current quorum bitmap matches the expectation @@ -848,22 +933,36 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is ); // check that the quorum bitmap history is as expected assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(registrationQuorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(registrationQuorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }) + ) + ) ); // note: there will be no second entry in the operator's bitmap history in the event that the operator has totally deregistered if (deregistrationQuorumBitmap != registrationQuorumBitmap) { assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(expectedQuorumBitmap), - updateBlockNumber: deregistrationBlockNumber, - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode( + registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1) + ) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(expectedQuorumBitmap), + updateBlockNumber: deregistrationBlockNumber, + nextUpdateBlockNumber: 0 + }) + ) + ) ); } } @@ -940,19 +1039,31 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is assertEq( keccak256(abi.encode(registryCoordinator.getOperator(operatorToDeregister))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: operatorToDeregisterId, - status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED - }))) + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: operatorToDeregisterId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED + }) + ) + ) ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToDeregisterId, 0))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(operatorToDeregisterQuorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }))) + keccak256( + abi.encode( + registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToDeregisterId, 0) + ) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(operatorToDeregisterQuorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }) + ) + ) ); } @@ -971,7 +1082,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is cheats.roll(reregistrationBlockNumber); // store data before registering, to check against later - ISlashingRegistryCoordinator.QuorumBitmapUpdate memory previousQuorumBitmapUpdate = + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate memory previousQuorumBitmapUpdate = registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0); // re-register the operator @@ -983,10 +1094,14 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is assertEq(registryCoordinator.getOperatorId(defaultOperator), defaultOperatorId, "1"); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED - }))), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED + }) + ) + ), "2" ); assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap, "3"); @@ -1001,12 +1116,22 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is // check that new entry in bitmap history is as expected uint256 historyLength = registryCoordinator.getQuorumBitmapHistoryLength(defaultOperatorId); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, historyLength - 1))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: uint32(reregistrationBlockNumber), - nextUpdateBlockNumber: 0 - }))), + keccak256( + abi.encode( + registryCoordinator.getQuorumBitmapUpdateByIndex( + defaultOperatorId, historyLength - 1 + ) + ) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: uint32(reregistrationBlockNumber), + nextUpdateBlockNumber: 0 + }) + ) + ), "5" ); } @@ -1181,18 +1306,26 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is if (deregistrationQuorumBitmap == registrationQuorumBitmap) { assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED - }))) + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED + }) + ) + ) ); } else { assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED + }) + ) + ) ); } // ensure that the operator's current quorum bitmap matches the expectation @@ -1203,22 +1336,36 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is ); // check that the quorum bitmap history is as expected assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(registrationQuorumBitmap), - updateBlockNumber: registrationBlockNumber, - nextUpdateBlockNumber: deregistrationBlockNumber - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(registrationQuorumBitmap), + updateBlockNumber: registrationBlockNumber, + nextUpdateBlockNumber: deregistrationBlockNumber + }) + ) + ) ); // note: there will be no second entry in the operator's bitmap history in the event that the operator has totally deregistered if (deregistrationQuorumBitmap != registrationQuorumBitmap) { assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(expectedQuorumBitmap), - updateBlockNumber: deregistrationBlockNumber, - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode( + registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1) + ) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(expectedQuorumBitmap), + updateBlockNumber: deregistrationBlockNumber, + nextUpdateBlockNumber: 0 + }) + ) + ) ); } } @@ -1249,10 +1396,14 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is // make sure the operator is deregistered assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED - }))) + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED + }) + ) + ) ); // make sure the operator is not in any quorums assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); @@ -1290,10 +1441,14 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is // make sure the operator is registered assertEq( keccak256(abi.encode(registryCoordinator.getOperator(defaultOperator))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: defaultOperatorId, - status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: defaultOperatorId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED + }) + ) + ) ); // make sure the operator is properly removed from the quorums assertEq( @@ -1524,7 +1679,8 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord address operatorToKick; // register last operator before kick - ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = new ISlashingRegistryCoordinator.OperatorKickParam[](1); + ISlashingRegistryCoordinatorTypes.OperatorKickParam[] memory operatorKickParams = + new ISlashingRegistryCoordinatorTypes.OperatorKickParam[](1); { BN254.G1Point memory pubKey = BN254.hashToG1(keccak256(abi.encodePacked(pseudoRandomNumber, numOperators - 1))); @@ -1537,7 +1693,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord // operatorIdsToSwap[0] = operatorToRegisterId operatorIdsToSwap[0] = operatorToRegisterId; - operatorKickParams[0] = ISlashingRegistryCoordinator.OperatorKickParam({ + operatorKickParams[0] = ISlashingRegistryCoordinatorTypes.OperatorKickParam({ quorumNumber: defaultQuorumNumber, operator: operatorToKick }); @@ -1563,7 +1719,9 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord cheats.expectEmit(true, true, true, true, address(registryCoordinator)); emit OperatorDeregistered(operatorKickParams[0].operator, operatorToKickId); cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); - emit OperatorRemovedFromQuorums(operatorKickParams[0].operator, operatorToKickId, quorumNumbers); + emit OperatorRemovedFromQuorums( + operatorKickParams[0].operator, operatorToKickId, quorumNumbers + ); cheats.expectEmit(true, true, true, true, address(stakeRegistry)); emit OperatorStakeUpdate(operatorToKickId, defaultQuorumNumber, 0); cheats.expectEmit(true, true, true, true, address(indexRegistry)); @@ -1597,25 +1755,39 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord assertEq( keccak256(abi.encode(registryCoordinator.getOperator(operatorToRegister))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: operatorToRegisterId, - status: ISlashingRegistryCoordinator.OperatorStatus.REGISTERED - }))) + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: operatorToRegisterId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED + }) + ) + ) ); assertEq( keccak256(abi.encode(registryCoordinator.getOperator(operatorToKick))), - keccak256(abi.encode(ISlashingRegistryCoordinator.OperatorInfo({ - operatorId: operatorToKickId, - status: ISlashingRegistryCoordinator.OperatorStatus.DEREGISTERED - }))) + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.OperatorInfo({ + operatorId: operatorToKickId, + status: ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED + }) + ) + ) ); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToKickId, 0))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(quorumBitmap), - updateBlockNumber: kickRegistrationBlockNumber, - nextUpdateBlockNumber: registrationBlockNumber - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToKickId, 0)) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(quorumBitmap), + updateBlockNumber: kickRegistrationBlockNumber, + nextUpdateBlockNumber: registrationBlockNumber + }) + ) + ) ); } @@ -1629,7 +1801,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ( address operatorToRegister, BN254.G1Point memory operatorToRegisterPubKey, - ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams + ISlashingRegistryCoordinatorTypes.OperatorKickParam[] memory operatorKickParams ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, defaultStake); bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); @@ -1667,15 +1839,17 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ( address operatorToRegister, BN254.G1Point memory operatorToRegisterPubKey, - ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams - ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, operatorToKickStake); + ISlashingRegistryCoordinatorTypes.OperatorKickParam[] memory operatorKickParams + ) = _test_registerOperatorWithChurn_SetUp( + pseudoRandomNumber, quorumNumbers, operatorToKickStake + ); bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); // set the stake of the operator to register to the defaultKickBIPsOfOperatorStake multiple of the operatorToKickStake _setOperatorWeight( operatorToRegister, defaultQuorumNumber, - operatorToKickStake * defaultKickBIPsOfOperatorStake / 10_000 + 1 + operatorToKickStake * defaultKickBIPsOfOperatorStake / 10000 + 1 ); cheats.roll(registrationBlockNumber); @@ -1709,7 +1883,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ( address operatorToRegister, , - ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams + ISlashingRegistryCoordinatorTypes.OperatorKickParam[] memory operatorKickParams ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, defaultStake); uint96 registeringStake = defaultKickBIPsOfOperatorStake * defaultStake; @@ -1743,7 +1917,7 @@ contract RegistryCoordinatorUnitTests_RegisterOperatorWithChurn is RegistryCoord ( address operatorToRegister, BN254.G1Point memory operatorToRegisterPubKey, - ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams + ISlashingRegistryCoordinatorTypes.OperatorKickParam[] memory operatorKickParams ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, defaultStake); bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); @@ -2073,7 +2247,7 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit ), keccak256( abi.encode( - ISlashingRegistryCoordinator.QuorumBitmapUpdate({ + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ quorumBitmap: uint192(newBitmap), updateBlockNumber: uint32(block.number), nextUpdateBlockNumber: 0 @@ -2092,12 +2266,18 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(newBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(newBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }) + ) + ) ); } @@ -2114,20 +2294,32 @@ contract RegistryCoordinatorUnitTests_UpdateOperators is RegistryCoordinatorUnit registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(pastBitmap), - updateBlockNumber: uint32(previousBlockNumber), - nextUpdateBlockNumber: uint32(block.number) - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0)) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(pastBitmap), + updateBlockNumber: uint32(previousBlockNumber), + nextUpdateBlockNumber: uint32(block.number) + }) + ) + ) ); assertEq( - keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), - keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ - quorumBitmap: uint192(newBitmap), - updateBlockNumber: uint32(block.number), - nextUpdateBlockNumber: 0 - }))) + keccak256( + abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1)) + ), + keccak256( + abi.encode( + ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ + quorumBitmap: uint192(newBitmap), + updateBlockNumber: uint32(block.number), + nextUpdateBlockNumber: 0 + }) + ) + ) ); } } @@ -2152,16 +2344,19 @@ contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnit function test_CreateTotalDelegatedStakeQuorum() public { _deployMockEigenLayerAndAVS(0); // Set up test params - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 0, kickBIPsOfTotalStake: 0 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = - IStakeRegistry.StrategyParams({strategy: IStrategy(address(0x1)), multiplier: 1000}); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); + strategyParams[0] = IStakeRegistryTypes.StrategyParams({ + strategy: IStrategy(address(0x1)), + multiplier: 1000 + }); // Get initial quorum count uint8 initialQuorumCount = registryCoordinator.quorumCount(); @@ -2176,7 +2371,8 @@ contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnit assertEq(registryCoordinator.quorumCount(), initialQuorumCount + 1); // Verify quorum params were set correctly - ISlashingRegistryCoordinator.OperatorSetParam memory storedParams = registryCoordinator.getOperatorSetParams(initialQuorumCount); + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory storedParams = + registryCoordinator.getOperatorSetParams(initialQuorumCount); assertEq(storedParams.maxOperatorCount, operatorSetParams.maxOperatorCount); assertEq(storedParams.kickBIPsOfOperatorStake, operatorSetParams.kickBIPsOfOperatorStake); assertEq(storedParams.kickBIPsOfTotalStake, operatorSetParams.kickBIPsOfTotalStake); @@ -2184,16 +2380,19 @@ contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnit function test_CreateSlashableStakeQuorum_Reverts() public { _deployMockEigenLayerAndAVS(0); - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 0, kickBIPsOfTotalStake: 0 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = - IStakeRegistry.StrategyParams({strategy: IStrategy(address(0x1)), multiplier: 1000}); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); + strategyParams[0] = IStakeRegistryTypes.StrategyParams({ + strategy: IStrategy(address(0x1)), + multiplier: 1000 + }); uint32 lookAheadPeriod = 100; // Attempt to create quorum with slashable stake type before enabling operator sets @@ -2213,7 +2412,6 @@ contract RegistryCoordinatorUnitTests_BeforeMigration is RegistryCoordinatorUnit } contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitTests { - function test_MigrateToOperatorSets() public { cheats.prank(registryCoordinatorOwner); registryCoordinator.enableOperatorSets(); @@ -2230,8 +2428,8 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT ISignatureUtils.SignatureWithSaltAndExpiry memory emptySignature = ISignatureUtils .SignatureWithSaltAndExpiry({signature: new bytes(0), salt: bytes32(0), expiry: 0}); - IBLSApkRegistry.PubkeyRegistrationParams memory operatorRegisterApkParams = IBLSApkRegistry - .PubkeyRegistrationParams({ + IBLSApkRegistryTypes.PubkeyRegistrationParams memory operatorRegisterApkParams = + IBLSApkRegistryTypes.PubkeyRegistrationParams({ pubkeyRegistrationSignature: BN254.G1Point({X: 0, Y: 0}), pubkeyG1: BN254.G1Point({X: 0, Y: 0}), pubkeyG2: BN254.G2Point({X: [uint256(0), uint256(0)], Y: [uint256(0), uint256(0)]}) @@ -2261,8 +2459,13 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT assertEq(bitmap, 0, "Operator bitmap should be empty after deregistration"); // Verify operator status is NEVER_REGISTERED - ISlashingRegistryCoordinator.OperatorStatus status = registryCoordinator.getOperatorStatus(operatorToRegister); - assertEq(uint8(status), uint8(ISlashingRegistryCoordinator.OperatorStatus.NEVER_REGISTERED), "Operator status should be NEVER_REGISTERED"); + ISlashingRegistryCoordinatorTypes.OperatorStatus status = + registryCoordinator.getOperatorStatus(operatorToRegister); + assertEq( + uint8(status), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.NEVER_REGISTERED), + "Operator status should be NEVER_REGISTERED" + ); } function test_M2_Register_Reverts() public { @@ -2271,7 +2474,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT bytes memory quorumNumbers = new bytes(1); quorumNumbers[0] = bytes1(uint8(0)); - IBLSApkRegistry.PubkeyRegistrationParams memory params; + IBLSApkRegistryTypes.PubkeyRegistrationParams memory params; ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; cheats.expectRevert(); @@ -2289,16 +2492,17 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT registryCoordinator.enableOperatorSets(); // Create quorum params - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); strategyParams[0] = - IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 1}); + IStakeRegistryTypes.StrategyParams({strategy: IStrategy(address(1)), multiplier: 1}); uint32 lookAheadPeriod = 100; // Create slashable stake quorum @@ -2317,16 +2521,17 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT registryCoordinator.enableOperatorSets(); // Create quorum params - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); strategyParams[0] = - IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10_000}); + IStakeRegistryTypes.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10000}); // Create total delegated stake quorum cheats.prank(registryCoordinatorOwner); @@ -2345,44 +2550,38 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT registryCoordinator.enableOperatorSets(); // Create quorum params - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); strategyParams[0] = - IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10_000}); + IStakeRegistryTypes.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10000}); // Create total delegated stake quorum cheats.prank(registryCoordinatorOwner); - registryCoordinator.createTotalDelegatedStakeQuorum( - operatorSetParams, - 0, - strategyParams - ); + registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, 0, strategyParams); uint32[] memory operatorSetIds = new uint32[](1); operatorSetIds[0] = 0; string memory socket = "socket"; - IBLSApkRegistry.PubkeyRegistrationParams memory params; + IBLSApkRegistryTypes.PubkeyRegistrationParams memory params; // TODO: - // params = IBLSApkRegistry.PubkeyRegistrationParams({ + // params = IBLSApkRegistryTypes.PubkeyRegistrationParams({ // pubkeyG1: defaultPubKey, // pubkeyG2: defaultPubKeyG2, // pubkeySignature: defaultPubKeySignature // }); // Encode with RegistrationType.NORMAL - bytes memory data = abi.encode( - ISlashingRegistryCoordinator.RegistrationType.NORMAL, - socket, - params - ); + bytes memory data = + abi.encode(ISlashingRegistryCoordinatorTypes.RegistrationType.NORMAL, socket, params); cheats.prank(address(registryCoordinator.allocationManager())); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); @@ -2396,17 +2595,18 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT registryCoordinator.enableOperatorSets(); // Create quorum params - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); strategyParams[0] = - IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10_000}); + IStakeRegistryTypes.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10000}); // Create total delegated stake quorum cheats.prank(registryCoordinatorOwner); @@ -2416,16 +2616,17 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT operatorSetIds[0] = 0; string memory socket = "socket"; - IBLSApkRegistry.PubkeyRegistrationParams memory params; + IBLSApkRegistryTypes.PubkeyRegistrationParams memory params; // TODO: - // params = IBLSApkRegistry.PubkeyRegistrationParams({ + // params = IBLSApkRegistryTypes.PubkeyRegistrationParams({ // pubkeyG1: defaultPubKey, // pubkeyG2: defaultPubKeyG2, // pubkeySignature: defaultPubKeySignature // }); - ISlashingRegistryCoordinator.OperatorKickParam[] memory operatorKickParams = new ISlashingRegistryCoordinator.OperatorKickParam[](1); - operatorKickParams[0] = ISlashingRegistryCoordinator.OperatorKickParam({ + ISlashingRegistryCoordinatorTypes.OperatorKickParam[] memory operatorKickParams = + new ISlashingRegistryCoordinatorTypes.OperatorKickParam[](1); + operatorKickParams[0] = ISlashingRegistryCoordinatorTypes.OperatorKickParam({ operator: address(0x1), quorumNumber: 0 }); @@ -2434,7 +2635,7 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT // Encode with RegistrationType.CHURN bytes memory data = abi.encode( - ISlashingRegistryCoordinator.RegistrationType.CHURN, + ISlashingRegistryCoordinatorTypes.RegistrationType.CHURN, socket, params, operatorKickParams, @@ -2450,17 +2651,18 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT vm.skip(true); _deployMockEigenLayerAndAVS(0); - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: defaultMaxOperatorCount, kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); strategyParams[0] = - IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10_000}); + IStakeRegistryTypes.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10000}); cheats.prank(registryCoordinatorOwner); registryCoordinator.createTotalDelegatedStakeQuorum( @@ -2479,17 +2681,18 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT registryCoordinator.enableOperatorSets(); // Create quorum params - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); strategyParams[0] = - IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10_000}); + IStakeRegistryTypes.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10000}); // Create total delegated stake quorum cheats.prank(registryCoordinatorOwner); @@ -2500,20 +2703,17 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT operatorSetIds[0] = 0; string memory socket = "socket"; - IBLSApkRegistry.PubkeyRegistrationParams memory params; + IBLSApkRegistryTypes.PubkeyRegistrationParams memory params; // TODO: - // params = IBLSApkRegistry.PubkeyRegistrationParams({ + // params = IBLSApkRegistryTypes.PubkeyRegistrationParams({ // pubkeyG1: defaultPubKey, // pubkeyG2: defaultPubKeyG2, // pubkeySignature: defaultPubKeySignature // }); // Encode with RegistrationType.NORMAL - bytes memory data = abi.encode( - ISlashingRegistryCoordinator.RegistrationType.NORMAL, - socket, - params - ); + bytes memory data = + abi.encode(ISlashingRegistryCoordinatorTypes.RegistrationType.NORMAL, socket, params); cheats.startPrank(address(registryCoordinator.allocationManager())); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); @@ -2531,44 +2731,38 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT registryCoordinator.enableOperatorSets(); // Create quorum params - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); strategyParams[0] = - IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10_000}); + IStakeRegistryTypes.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10000}); // Create total delegated stake quorum cheats.prank(registryCoordinatorOwner); - registryCoordinator.createTotalDelegatedStakeQuorum( - operatorSetParams, - 0, - strategyParams - ); + registryCoordinator.createTotalDelegatedStakeQuorum(operatorSetParams, 0, strategyParams); uint32[] memory operatorSetIds = new uint32[](1); operatorSetIds[0] = 0; string memory socket = "socket"; - IBLSApkRegistry.PubkeyRegistrationParams memory params; + IBLSApkRegistryTypes.PubkeyRegistrationParams memory params; // TODO: - // params = IBLSApkRegistry.PubkeyRegistrationParams({ + // params = IBLSApkRegistryTypes.PubkeyRegistrationParams({ // pubkeyG1: defaultPubKey, // pubkeyG2: defaultPubKeyG2, // pubkeySignature: defaultPubKeySignature // }); // Encode with RegistrationType.NORMAL - bytes memory data = abi.encode( - ISlashingRegistryCoordinator.RegistrationType.NORMAL, - socket, - params - ); + bytes memory data = + abi.encode(ISlashingRegistryCoordinatorTypes.RegistrationType.NORMAL, socket, params); vm.expectRevert(); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); @@ -2581,23 +2775,21 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT cheats.prank(registryCoordinatorOwner); registryCoordinator.enableOperatorSets(); - assertTrue( - registryCoordinator.operatorSetsEnabled(), - "operatorSetsEnabled should be true" - ); + assertTrue(registryCoordinator.operatorSetsEnabled(), "operatorSetsEnabled should be true"); // Create quorum params - ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ + ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: 10, kickBIPsOfOperatorStake: 1000, kickBIPsOfTotalStake: 100 }); uint96 minimumStake = 100; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); strategyParams[0] = - IStakeRegistry.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10_000}); + IStakeRegistryTypes.StrategyParams({strategy: IStrategy(address(1)), multiplier: 10000}); // Create total delegated stake quorum cheats.prank(registryCoordinatorOwner); @@ -2608,19 +2800,16 @@ contract RegistryCoordinatorUnitTests_AfterMigration is RegistryCoordinatorUnitT operatorSetIds[0] = 0; string memory socket = "socket"; - IBLSApkRegistry.PubkeyRegistrationParams memory params; + IBLSApkRegistryTypes.PubkeyRegistrationParams memory params; // TODO: - // params = IBLSApkRegistry.PubkeyRegistrationParams({ + // params = IBLSApkRegistryTypes.PubkeyRegistrationParams({ // pubkeyG1: defaultPubKey, // pubkeyG2: defaultPubKeyG2, // pubkeySignature: defaultPubKeySignature // }); - bytes memory data = abi.encode( - ISlashingRegistryCoordinator.RegistrationType.NORMAL, - socket, - params - ); + bytes memory data = + abi.encode(ISlashingRegistryCoordinatorTypes.RegistrationType.NORMAL, socket, params); cheats.prank(address(registryCoordinator.allocationManager())); registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); diff --git a/test/unit/ServiceManagerBase.t.sol b/test/unit/ServiceManagerBase.t.sol index d293f088..d9647ce8 100644 --- a/test/unit/ServiceManagerBase.t.sol +++ b/test/unit/ServiceManagerBase.t.sol @@ -24,7 +24,7 @@ contract ServiceManagerBase_UnitTests is MockAVSDeployer, IServiceManagerBaseEve uint32 MAX_REWARDS_DURATION = 70 days; uint32 MAX_RETROACTIVE_LENGTH = 84 days; uint32 MAX_FUTURE_LENGTH = 28 days; - uint32 GENESIS_REWARDS_TIMESTAMP = 1_712_188_800; + uint32 GENESIS_REWARDS_TIMESTAMP = 1712188800; uint256 MAX_REWARDS_AMOUNT = 1e38 - 1; uint32 OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP = 0; /// TODO: what values should these have diff --git a/test/unit/SlashingRegistryCoordinatorUnit.t.sol b/test/unit/SlashingRegistryCoordinatorUnit.t.sol index 52d12ed8..844aa6e9 100644 --- a/test/unit/SlashingRegistryCoordinatorUnit.t.sol +++ b/test/unit/SlashingRegistryCoordinatorUnit.t.sol @@ -7,7 +7,6 @@ // import {BitmapUtils} from "../../src/libraries/BitmapUtils.sol"; // import {console} from "forge-std/console.sol"; - // contract RegistryCoordinatorUnitTests is MockAVSDeployer { // using BN254 for BN254.G1Point; @@ -47,7 +46,7 @@ // // emitted when an operator's index in the orderd operator list for the quorum with number `quorumNumber` is updated // event QuorumIndexUpdate(bytes32 indexed operatorId, uint8 quorumNumber, uint32 newIndex); -// event OperatorSetParamsUpdated(uint8 indexed quorumNumber, ISlashingRegistryCoordinator.OperatorSetParam operatorSetParams); +// event OperatorSetParamsUpdated(uint8 indexed quorumNumber, ISlashingRegistryCoordinatorTypes.OperatorSetParam operatorSetParams); // event ChurnApproverUpdated(address prevChurnApprover, address newChurnApprover); @@ -204,9 +203,9 @@ // } // function test_createQuorum_revert_notOwner() public { -// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams; +// ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams; // uint96 minimumStake; -// IStakeRegistry.StrategyParams[] memory strategyParams; +// IStakeRegistryTypes.StrategyParams[] memory strategyParams; // cheats.expectRevert("Ownable: caller is not the owner"); // cheats.prank(defaultOperator); @@ -218,16 +217,16 @@ // // this is necessary since the default setup already configures the max number of quorums, preventing adding more // _deployMockEigenLayerAndAVS(0); -// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = -// ISlashingRegistryCoordinator.OperatorSetParam({ +// ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = +// ISlashingRegistryCoordinatorTypes.OperatorSetParam({ // maxOperatorCount: defaultMaxOperatorCount, // kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, // kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake // }); // uint96 minimumStake = 1; -// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); +// IStakeRegistryTypes.StrategyParams[] memory strategyParams = new IStakeRegistryTypes.StrategyParams[](1); // strategyParams[0] = -// IStakeRegistry.StrategyParams({ +// IStakeRegistryTypes.StrategyParams({ // strategy: IStrategy(address(1000)), // multiplier: 1e16 // }); @@ -333,7 +332,7 @@ // assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(quorumBitmap), // updateBlockNumber: uint32(block.number), // nextUpdateBlockNumber: 0 @@ -390,7 +389,7 @@ // assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(quorumBitmap), // updateBlockNumber: uint32(block.number), // nextUpdateBlockNumber: 0 @@ -441,7 +440,7 @@ // assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers)), // updateBlockNumber: uint32(registrationBlockNumber), // nextUpdateBlockNumber: uint32(nextRegistrationBlockNumber) @@ -449,7 +448,7 @@ // ); // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(quorumBitmap), // updateBlockNumber: uint32(nextRegistrationBlockNumber), // nextUpdateBlockNumber: 0 @@ -570,7 +569,7 @@ // assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), quorumBitmap); // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(quorumBitmap), // updateBlockNumber: uint32(block.number), // nextUpdateBlockNumber: 0 @@ -663,7 +662,7 @@ // assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(quorumBitmap), // updateBlockNumber: registrationBlockNumber, // nextUpdateBlockNumber: deregistrationBlockNumber @@ -718,7 +717,7 @@ // assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(quorumBitmap), // updateBlockNumber: registrationBlockNumber, // nextUpdateBlockNumber: deregistrationBlockNumber @@ -794,7 +793,7 @@ // // check that the quorum bitmap history is as expected // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(registrationQuorumBitmap), // updateBlockNumber: registrationBlockNumber, // nextUpdateBlockNumber: deregistrationBlockNumber @@ -804,7 +803,7 @@ // if (deregistrationQuorumBitmap != registrationQuorumBitmap) { // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(expectedQuorumBitmap), // updateBlockNumber: deregistrationBlockNumber, // nextUpdateBlockNumber: 0 @@ -880,7 +879,7 @@ // assertEq(registryCoordinator.getCurrentQuorumBitmap(defaultOperatorId), 0); // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToDeregisterId, 0))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(operatorToDeregisterQuorumBitmap), // updateBlockNumber: registrationBlockNumber, // nextUpdateBlockNumber: deregistrationBlockNumber @@ -930,7 +929,7 @@ // uint historyLength = registryCoordinator.getQuorumBitmapHistoryLength(defaultOperatorId); // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, historyLength - 1))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(quorumBitmap), // updateBlockNumber: uint32(reregistrationBlockNumber), // nextUpdateBlockNumber: 0 @@ -1109,7 +1108,7 @@ // // check that the quorum bitmap history is as expected // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(registrationQuorumBitmap), // updateBlockNumber: registrationBlockNumber, // nextUpdateBlockNumber: deregistrationBlockNumber @@ -1119,7 +1118,7 @@ // if (deregistrationQuorumBitmap != registrationQuorumBitmap) { // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(expectedQuorumBitmap), // updateBlockNumber: deregistrationBlockNumber, // nextUpdateBlockNumber: 0 @@ -1393,7 +1392,6 @@ // cheats.expectEmit(true, true, true, true, address(indexRegistry)); // emit QuorumIndexUpdate(operatorToRegisterId, defaultQuorumNumber, numOperators); - // cheats.expectEmit(true, true, true, true, address(registryCoordinator)); // emit OperatorDeregistered(operatorKickParams[0].operator, operatorToKickId); // cheats.expectEmit(true, true, true, true, address(blsApkRegistry)); @@ -1437,7 +1435,7 @@ // ); // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(operatorToKickId, 0))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(quorumBitmap), // updateBlockNumber: kickRegistrationBlockNumber, // nextUpdateBlockNumber: registrationBlockNumber @@ -1487,7 +1485,6 @@ // ) = _test_registerOperatorWithChurn_SetUp(pseudoRandomNumber, quorumNumbers, operatorToKickStake); // bytes32 operatorToRegisterId = BN254.hashG1Point(operatorToRegisterPubKey); - // // set the stake of the operator to register to the defaultKickBIPsOfOperatorStake multiple of the operatorToKickStake // _setOperatorWeight(operatorToRegister, defaultQuorumNumber, operatorToKickStake * defaultKickBIPsOfOperatorStake / 10000 + 1); @@ -1834,7 +1831,7 @@ // registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(newBitmap), // updateBlockNumber: uint32(block.number), // nextUpdateBlockNumber: 0 @@ -1850,7 +1847,7 @@ // registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(newBitmap), // updateBlockNumber: uint32(block.number), // nextUpdateBlockNumber: 0 @@ -1870,7 +1867,7 @@ // registryCoordinator._updateOperatorBitmapExternal(defaultOperatorId, newBitmap); // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 0))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(pastBitmap), // updateBlockNumber: uint32(previousBlockNumber), // nextUpdateBlockNumber: uint32(block.number) @@ -1878,7 +1875,7 @@ // ); // assertEq( // keccak256(abi.encode(registryCoordinator.getQuorumBitmapUpdateByIndex(defaultOperatorId, 1))), -// keccak256(abi.encode(ISlashingRegistryCoordinator.QuorumBitmapUpdate({ +// keccak256(abi.encode(ISlashingRegistryCoordinatorTypes.QuorumBitmapUpdate({ // quorumBitmap: uint192(newBitmap), // updateBlockNumber: uint32(block.number), // nextUpdateBlockNumber: 0 @@ -1905,14 +1902,14 @@ // function test_CreateTotalDelegatedStakeQuorum() public { // _deployMockEigenLayerAndAVS(0); // // Set up test params -// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinatorTypes.OperatorSetParam({ // maxOperatorCount: 10, // kickBIPsOfOperatorStake: 0, // kickBIPsOfTotalStake: 0 // }); // uint96 minimumStake = 100; -// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); -// strategyParams[0] = IStakeRegistry.StrategyParams({ +// IStakeRegistryTypes.StrategyParams[] memory strategyParams = new IStakeRegistryTypes.StrategyParams[](1); +// strategyParams[0] = IStakeRegistryTypes.StrategyParams({ // strategy: IStrategy(address(0x1)), // multiplier: 1000 // }); @@ -1932,7 +1929,7 @@ // assertEq(registryCoordinator.quorumCount(), initialQuorumCount + 1); // // Verify quorum params were set correctly -// ISlashingRegistryCoordinator.OperatorSetParam memory storedParams = registryCoordinator.getOperatorSetParams(initialQuorumCount); +// ISlashingRegistryCoordinatorTypes.OperatorSetParam memory storedParams = registryCoordinator.getOperatorSetParams(initialQuorumCount); // assertEq(storedParams.maxOperatorCount, operatorSetParams.maxOperatorCount); // assertEq(storedParams.kickBIPsOfOperatorStake, operatorSetParams.kickBIPsOfOperatorStake); // assertEq(storedParams.kickBIPsOfTotalStake, operatorSetParams.kickBIPsOfTotalStake); @@ -1940,14 +1937,14 @@ // function test_CreateSlashableStakeQuorum_Reverts() public { // _deployMockEigenLayerAndAVS(0); -// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinatorTypes.OperatorSetParam({ // maxOperatorCount: 10, // kickBIPsOfOperatorStake: 0, // kickBIPsOfTotalStake: 0 // }); // uint96 minimumStake = 100; -// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); -// strategyParams[0] = IStakeRegistry.StrategyParams({ +// IStakeRegistryTypes.StrategyParams[] memory strategyParams = new IStakeRegistryTypes.StrategyParams[](1); +// strategyParams[0] = IStakeRegistryTypes.StrategyParams({ // strategy: IStrategy(address(0x1)), // multiplier: 1000 // }); @@ -1992,7 +1989,7 @@ // expiry: 0 // }); -// IBLSApkRegistry.PubkeyRegistrationParams memory operatorRegisterApkParams = IBLSApkRegistry.PubkeyRegistrationParams({ +// IBLSApkRegistryTypes.PubkeyRegistrationParams memory operatorRegisterApkParams = IBLSApkRegistryTypes.PubkeyRegistrationParams({ // pubkeyRegistrationSignature: BN254.G1Point({ // X: 0, // Y: 0 @@ -2041,7 +2038,7 @@ // bytes memory quorumNumbers = new bytes(1); // quorumNumbers[0] = bytes1(uint8(0)); -// IBLSApkRegistry.PubkeyRegistrationParams memory params; +// IBLSApkRegistryTypes.PubkeyRegistrationParams memory params; // ISignatureUtils.SignatureWithSaltAndExpiry memory operatorSignature; // cheats.expectRevert(); @@ -2062,14 +2059,14 @@ // registryCoordinator.enableOperatorSets(); // // Create quorum params -// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinatorTypes.OperatorSetParam({ // maxOperatorCount: 10, // kickBIPsOfOperatorStake: 1000, // kickBIPsOfTotalStake: 100 // }); // uint96 minimumStake = 100; -// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); -// strategyParams[0] = IStakeRegistry.StrategyParams({ +// IStakeRegistryTypes.StrategyParams[] memory strategyParams = new IStakeRegistryTypes.StrategyParams[](1); +// strategyParams[0] = IStakeRegistryTypes.StrategyParams({ // strategy: IStrategy(address(1)), // multiplier: 1 // }); @@ -2094,14 +2091,14 @@ // registryCoordinator.enableOperatorSets(); // // Create quorum params -// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinatorTypes.OperatorSetParam({ // maxOperatorCount: 10, // kickBIPsOfOperatorStake: 1000, // kickBIPsOfTotalStake: 100 // }); // uint96 minimumStake = 100; -// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); -// strategyParams[0] = IStakeRegistry.StrategyParams({ +// IStakeRegistryTypes.StrategyParams[] memory strategyParams = new IStakeRegistryTypes.StrategyParams[](1); +// strategyParams[0] = IStakeRegistryTypes.StrategyParams({ // strategy: IStrategy(address(1)), // multiplier: 10000 // }); @@ -2124,15 +2121,15 @@ // registryCoordinator.enableOperatorSets(); // // Create quorum params -// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinatorTypes.OperatorSetParam({ // maxOperatorCount: 10, // kickBIPsOfOperatorStake: 1000, // kickBIPsOfTotalStake: 100 // }); // uint96 minimumStake = 100; -// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); -// strategyParams[0] = IStakeRegistry.StrategyParams({ +// IStakeRegistryTypes.StrategyParams[] memory strategyParams = new IStakeRegistryTypes.StrategyParams[](1); +// strategyParams[0] = IStakeRegistryTypes.StrategyParams({ // strategy: IStrategy(address(1)), // multiplier: 10000 // }); @@ -2145,14 +2142,13 @@ // strategyParams // ); - // uint32[] memory operatorSetIds = new uint32[](1); // operatorSetIds[0] = 0; // string memory socket = "socket"; -// IBLSApkRegistry.PubkeyRegistrationParams memory params; +// IBLSApkRegistryTypes.PubkeyRegistrationParams memory params; // // TODO: -// // params = IBLSApkRegistry.PubkeyRegistrationParams({ +// // params = IBLSApkRegistryTypes.PubkeyRegistrationParams({ // // pubkeyG1: defaultPubKey, // // pubkeyG2: defaultPubKeyG2, // // pubkeySignature: defaultPubKeySignature @@ -2171,15 +2167,15 @@ // registryCoordinator.enableOperatorSets(); // // Create quorum params -// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinatorTypes.OperatorSetParam({ // maxOperatorCount: 10, // kickBIPsOfOperatorStake: 1000, // kickBIPsOfTotalStake: 100 // }); // uint96 minimumStake = 100; -// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); -// strategyParams[0] = IStakeRegistry.StrategyParams({ +// IStakeRegistryTypes.StrategyParams[] memory strategyParams = new IStakeRegistryTypes.StrategyParams[](1); +// strategyParams[0] = IStakeRegistryTypes.StrategyParams({ // strategy: IStrategy(address(1)), // multiplier: 10000 // }); @@ -2196,9 +2192,9 @@ // operatorSetIds[0] = 0; // string memory socket = "socket"; -// IBLSApkRegistry.PubkeyRegistrationParams memory params; +// IBLSApkRegistryTypes.PubkeyRegistrationParams memory params; // // TODO: -// // params = IBLSApkRegistry.PubkeyRegistrationParams({ +// // params = IBLSApkRegistryTypes.PubkeyRegistrationParams({ // // pubkeyG1: defaultPubKey, // // pubkeyG2: defaultPubKeyG2, // // pubkeySignature: defaultPubKeySignature @@ -2230,15 +2226,15 @@ // vm.skip(true); // _deployMockEigenLayerAndAVS(0); -// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinatorTypes.OperatorSetParam({ // maxOperatorCount: defaultMaxOperatorCount, // kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, // kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake // }); // uint96 minimumStake = 100; -// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); -// strategyParams[0] = IStakeRegistry.StrategyParams({ +// IStakeRegistryTypes.StrategyParams[] memory strategyParams = new IStakeRegistryTypes.StrategyParams[](1); +// strategyParams[0] = IStakeRegistryTypes.StrategyParams({ // strategy: IStrategy(address(1)), // multiplier: 10000 // }); @@ -2263,15 +2259,15 @@ // registryCoordinator.enableOperatorSets(); // // Create quorum params -// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinatorTypes.OperatorSetParam({ // maxOperatorCount: 10, // kickBIPsOfOperatorStake: 1000, // kickBIPsOfTotalStake: 100 // }); // uint96 minimumStake = 100; -// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); -// strategyParams[0] = IStakeRegistry.StrategyParams({ +// IStakeRegistryTypes.StrategyParams[] memory strategyParams = new IStakeRegistryTypes.StrategyParams[](1); +// strategyParams[0] = IStakeRegistryTypes.StrategyParams({ // strategy: IStrategy(address(1)), // multiplier: 10000 // }); @@ -2289,9 +2285,9 @@ // operatorSetIds[0] = 0; // string memory socket = "socket"; -// IBLSApkRegistry.PubkeyRegistrationParams memory params; +// IBLSApkRegistryTypes.PubkeyRegistrationParams memory params; // // TODO: -// // params = IBLSApkRegistry.PubkeyRegistrationParams({ +// // params = IBLSApkRegistryTypes.PubkeyRegistrationParams({ // // pubkeyG1: defaultPubKey, // // pubkeyG2: defaultPubKeyG2, // // pubkeySignature: defaultPubKeySignature @@ -2299,7 +2295,6 @@ // bytes memory data = abi.encode(socket, params); - // cheats.startPrank(address(registryCoordinator.allocationManager())); // registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); @@ -2316,15 +2311,15 @@ // registryCoordinator.enableOperatorSets(); // // Create quorum params -// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinatorTypes.OperatorSetParam({ // maxOperatorCount: 10, // kickBIPsOfOperatorStake: 1000, // kickBIPsOfTotalStake: 100 // }); // uint96 minimumStake = 100; -// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); -// strategyParams[0] = IStakeRegistry.StrategyParams({ +// IStakeRegistryTypes.StrategyParams[] memory strategyParams = new IStakeRegistryTypes.StrategyParams[](1); +// strategyParams[0] = IStakeRegistryTypes.StrategyParams({ // strategy: IStrategy(address(1)), // multiplier: 10000 // }); @@ -2337,14 +2332,13 @@ // strategyParams // ); - // uint32[] memory operatorSetIds = new uint32[](1); // operatorSetIds[0] = 0; // string memory socket = "socket"; -// IBLSApkRegistry.PubkeyRegistrationParams memory params; +// IBLSApkRegistryTypes.PubkeyRegistrationParams memory params; // // TODO: -// // params = IBLSApkRegistry.PubkeyRegistrationParams({ +// // params = IBLSApkRegistryTypes.PubkeyRegistrationParams({ // // pubkeyG1: defaultPubKey, // // pubkeyG2: defaultPubKeyG2, // // pubkeySignature: defaultPubKeySignature @@ -2364,15 +2358,15 @@ // registryCoordinator.enableOperatorSets(); // // Create quorum params -// ISlashingRegistryCoordinator.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinator.OperatorSetParam({ +// ISlashingRegistryCoordinatorTypes.OperatorSetParam memory operatorSetParams = ISlashingRegistryCoordinatorTypes.OperatorSetParam({ // maxOperatorCount: 10, // kickBIPsOfOperatorStake: 1000, // kickBIPsOfTotalStake: 100 // }); // uint96 minimumStake = 100; -// IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](1); -// strategyParams[0] = IStakeRegistry.StrategyParams({ +// IStakeRegistryTypes.StrategyParams[] memory strategyParams = new IStakeRegistryTypes.StrategyParams[](1); +// strategyParams[0] = IStakeRegistryTypes.StrategyParams({ // strategy: IStrategy(address(1)), // multiplier: 10000 // }); @@ -2390,9 +2384,9 @@ // operatorSetIds[0] = 0; // string memory socket = "socket"; -// IBLSApkRegistry.PubkeyRegistrationParams memory params; +// IBLSApkRegistryTypes.PubkeyRegistrationParams memory params; // // TODO: -// // params = IBLSApkRegistry.PubkeyRegistrationParams({ +// // params = IBLSApkRegistryTypes.PubkeyRegistrationParams({ // // pubkeyG1: defaultPubKey, // // pubkeyG2: defaultPubKeyG2, // // pubkeySignature: defaultPubKeySignature @@ -2400,7 +2394,6 @@ // bytes memory data = abi.encode(socket, params); - // cheats.prank(address(registryCoordinator.allocationManager())); // registryCoordinator.registerOperator(defaultOperator, operatorSetIds, data); // cheats.stopPrank(); diff --git a/test/unit/StakeRegistryUnit.t.sol b/test/unit/StakeRegistryUnit.t.sol index 2352dfeb..bd3ea670 100644 --- a/test/unit/StakeRegistryUnit.t.sol +++ b/test/unit/StakeRegistryUnit.t.sol @@ -56,7 +56,10 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { ); stakeRegistryImplementation = new StakeRegistryHarness( - ISlashingRegistryCoordinator(address(registryCoordinator)), delegationMock, avsDirectoryMock, allocationManager + ISlashingRegistryCoordinator(address(registryCoordinator)), + delegationMock, + avsDirectoryMock, + allocationManager ); stakeRegistry = StakeRegistryHarness( @@ -95,9 +98,9 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { ) internal { uint8 quorumNumber = nextQuorum; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = IStakeRegistry.StrategyParams( + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); + strategyParams[0] = IStakeRegistryTypes.StrategyParams( IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(quorumNumber)))))), uint96(WEIGHTING_DIVISOR) ); @@ -107,8 +110,12 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { cheats.prank(address(registryCoordinator)); stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); - StakeType stakeType = stakeRegistry.stakeTypePerQuorum(quorumNumber); - assertEq(uint8(stakeType), uint8(StakeType.TOTAL_DELEGATED), "invalid stake type"); + IStakeRegistryTypes.StakeType stakeType = stakeRegistry.stakeTypePerQuorum(quorumNumber); + assertEq( + uint8(stakeType), + uint8(IStakeRegistryTypes.StakeType.TOTAL_DELEGATED), + "invalid stake type" + ); // Mark quorum initialized for other tests initializedQuorumBitmap = uint192(initializedQuorumBitmap.setBit(quorumNumber)); @@ -123,10 +130,10 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { function _initializeQuorum(uint96 minimumStake, uint256 numStrats) internal returns (uint8) { uint8 quorumNumber = nextQuorum; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](numStrats); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](numStrats); for (uint256 i = 0; i < strategyParams.length; i++) { - strategyParams[i] = IStakeRegistry.StrategyParams( + strategyParams[i] = IStakeRegistryTypes.StrategyParams( IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(quorumNumber, i)))))), uint96(WEIGHTING_DIVISOR) ); @@ -583,7 +590,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { function testFuzz_initializeQuorum_Revert_WhenNotRegistryCoordinator( uint8 quorumNumber, uint96 minimumStake, - IStakeRegistry.StrategyParams[] memory strategyParams + IStakeRegistryTypes.StrategyParams[] memory strategyParams ) public { cheats.expectRevert(IStakeRegistryErrors.OnlySlashingRegistryCoordinator.selector); stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); @@ -592,7 +599,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { function testFuzz_initializeQuorum_Revert_WhenQuorumAlreadyExists( uint8 quorumNumber, uint96 minimumStake, - IStakeRegistry.StrategyParams[] memory strategyParams + IStakeRegistryTypes.StrategyParams[] memory strategyParams ) public fuzzOnlyInitializedQuorums(quorumNumber) { cheats.expectRevert(IStakeRegistryErrors.QuorumAlreadyExists.selector); cheats.prank(address(registryCoordinator)); @@ -604,15 +611,15 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint96 minimumStake ) public { cheats.assume(quorumNumber >= nextQuorum); - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](0); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](0); cheats.expectRevert(IStakeRegistryErrors.InputArrayLengthZero.selector); cheats.prank(address(registryCoordinator)); stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); - strategyParams = new IStakeRegistry.StrategyParams[](MAX_WEIGHING_FUNCTION_LENGTH + 1); + strategyParams = new IStakeRegistryTypes.StrategyParams[](MAX_WEIGHING_FUNCTION_LENGTH + 1); for (uint256 i = 0; i < strategyParams.length; i++) { - strategyParams[i] = IStakeRegistry.StrategyParams( + strategyParams[i] = IStakeRegistryTypes.StrategyParams( IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(i)))))), uint96(1) ); } @@ -621,46 +628,54 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); } - event StakeTypeSet(StakeType newStakeType); + event StakeTypeSet(IStakeRegistryTypes.StakeType newStakeType); function test_initializeDelegatedStakeQuorum() public { uint8 quorumNumber = nextQuorum; uint96 minimumStake = 0; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = IStakeRegistry.StrategyParams( + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); + strategyParams[0] = IStakeRegistryTypes.StrategyParams( IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(quorumNumber)))))), uint96(WEIGHTING_DIVISOR) ); cheats.prank(address(registryCoordinator)); cheats.expectEmit(true, true, true, true); - emit StakeTypeSet(StakeType.TOTAL_DELEGATED); + emit StakeTypeSet(IStakeRegistryTypes.StakeType.TOTAL_DELEGATED); stakeRegistry.initializeDelegatedStakeQuorum(quorumNumber, minimumStake, strategyParams); - StakeType stakeType = stakeRegistry.stakeTypePerQuorum(quorumNumber); - assertEq(uint8(stakeType), uint8(StakeType.TOTAL_DELEGATED), "invalid stake type"); + IStakeRegistryTypes.StakeType stakeType = stakeRegistry.stakeTypePerQuorum(quorumNumber); + assertEq( + uint8(stakeType), + uint8(IStakeRegistryTypes.StakeType.TOTAL_DELEGATED), + "invalid stake type" + ); } function test_initializeSlashableStakeQuorum() public { uint8 quorumNumber = nextQuorum; uint96 minimumStake = 0; - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); - strategyParams[0] = IStakeRegistry.StrategyParams( + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](1); + strategyParams[0] = IStakeRegistryTypes.StrategyParams( IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(quorumNumber)))))), uint96(WEIGHTING_DIVISOR) ); cheats.prank(address(registryCoordinator)); cheats.expectEmit(true, true, true, true); - emit StakeTypeSet(StakeType.TOTAL_SLASHABLE); + emit StakeTypeSet(IStakeRegistryTypes.StakeType.TOTAL_SLASHABLE); stakeRegistry.initializeSlashableStakeQuorum( quorumNumber, minimumStake, 7 days, strategyParams ); - StakeType stakeType = stakeRegistry.stakeTypePerQuorum(quorumNumber); - assertEq(uint8(stakeType), uint8(StakeType.TOTAL_SLASHABLE), "invalid stake type"); + IStakeRegistryTypes.StakeType stakeType = stakeRegistry.stakeTypePerQuorum(quorumNumber); + assertEq( + uint8(stakeType), + uint8(IStakeRegistryTypes.StakeType.TOTAL_SLASHABLE), + "invalid stake type" + ); } /** @@ -674,11 +689,11 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { ) public { cheats.assume(quorumNumber >= nextQuorum); cheats.assume(0 < multipliers.length && multipliers.length <= MAX_WEIGHING_FUNCTION_LENGTH); - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](multipliers.length); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](multipliers.length); for (uint256 i = 0; i < strategyParams.length; i++) { cheats.assume(multipliers[i] > 0); - strategyParams[i] = IStakeRegistry.StrategyParams( + strategyParams[i] = IStakeRegistryTypes.StrategyParams( IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(i)))))), multipliers[i] ); } @@ -764,7 +779,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { */ function testFuzz_addStrategies_Revert_WhenNotRegistryCoordinatorOwner( uint8 quorumNumber, - IStakeRegistry.StrategyParams[] memory strategyParams + IStakeRegistryTypes.StrategyParams[] memory strategyParams ) public fuzzOnlyInitializedQuorums(quorumNumber) { cheats.expectRevert(IStakeRegistryErrors.OnlySlashingRegistryCoordinatorOwner.selector); stakeRegistry.addStrategies(quorumNumber, strategyParams); @@ -772,7 +787,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { function testFuzz_addStrategies_Revert_WhenInvalidQuorum( uint8 quorumNumber, - IStakeRegistry.StrategyParams[] memory strategyParams + IStakeRegistryTypes.StrategyParams[] memory strategyParams ) public { // quorums [0,nextQuorum) are initialized, so use an invalid quorumNumber cheats.assume(quorumNumber >= nextQuorum); @@ -786,10 +801,10 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { IStrategy strat = IStrategy(address(uint160(uint256(keccak256(abi.encodePacked("duplicate strat")))))); - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](2); - strategyParams[0] = IStakeRegistry.StrategyParams(strat, uint96(WEIGHTING_DIVISOR)); - strategyParams[1] = IStakeRegistry.StrategyParams(strat, uint96(WEIGHTING_DIVISOR)); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](2); + strategyParams[0] = IStakeRegistryTypes.StrategyParams(strat, uint96(WEIGHTING_DIVISOR)); + strategyParams[1] = IStakeRegistryTypes.StrategyParams(strat, uint96(WEIGHTING_DIVISOR)); cheats.expectRevert(IStakeRegistryErrors.InputDuplicateStrategy.selector); cheats.prank(registryCoordinatorOwner); @@ -801,9 +816,9 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { IStrategy strat = IStrategy(address(uint160(uint256(keccak256(abi.encodePacked("duplicate strat")))))); - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](2); - strategyParams[0] = IStakeRegistry.StrategyParams(strat, 0); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](2); + strategyParams[0] = IStakeRegistryTypes.StrategyParams(strat, 0); cheats.expectRevert(IStakeRegistryErrors.InputMultiplierZero.selector); cheats.prank(registryCoordinatorOwner); @@ -828,11 +843,11 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { cheats.assume(multipliers[i] > 0); } // Expected events emitted - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](multipliers.length); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](multipliers.length); for (uint256 i = 0; i < strategyParams.length; i++) { IStrategy strat = IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(i)))))); - strategyParams[i] = IStakeRegistry.StrategyParams(strat, multipliers[i]); + strategyParams[i] = IStakeRegistryTypes.StrategyParams(strat, multipliers[i]); cheats.expectEmit(true, true, true, true, address(stakeRegistry)); emit StrategyAddedToQuorum(quorumNumber, strat); @@ -1878,7 +1893,7 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { "failed to remove delta from total stake" ); assertEq(newOperatorStake.stake, 0, "operator stake should now be zero"); - // Quorum should be added to return bitmap + // IECDSAStakeRegistryTypes.Quorum should be added to return bitmap assertTrue( quorumsToRemove.isSet(quorumNumber), "quorum should be in removal bitmap" ); @@ -2091,7 +2106,7 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { ); // assertEq(prevTotalStake.stake - stakeRemoved, newTotalStake.stake, "failed to remove delta from total stake"); assertEq(newOperatorStake.stake, 0, "operator stake should now be zero"); - // Quorum should be added to return bitmap + // IECDSAStakeRegistryTypes.Quorum should be added to return bitmap assertTrue( quorumsToRemove.isSet(quorumNumber), "quorum should be in removal bitmap" ); @@ -2167,8 +2182,8 @@ contract StakeRegistryUnitTests_weightOfOperatorForQuorum is StakeRegistryUnitTe // Initialize quorum with strategies of fuzzed multipliers. // Bound multipliers and shares max values to prevent overflows - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](3); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](3); for (uint256 i = 0; i < strategyParams.length; i++) { multipliers[i] = uint96( _randUint({ @@ -2182,8 +2197,9 @@ contract StakeRegistryUnitTests_weightOfOperatorForQuorum is StakeRegistryUnitTe IStrategy strat = IStrategy( address(uint160(uint256(keccak256(abi.encodePacked("Voteweighing test", i))))) ); - strategyParams[i] = - IStakeRegistry.StrategyParams(strat, uint96(WEIGHTING_DIVISOR) + multipliers[i]); + strategyParams[i] = IStakeRegistryTypes.StrategyParams( + strat, uint96(WEIGHTING_DIVISOR) + multipliers[i] + ); } cheats.prank(address(registryCoordinator)); uint8 quorumNumber = nextQuorum; @@ -2219,18 +2235,18 @@ contract StakeRegistryUnitTests_weightOfOperatorForQuorum is StakeRegistryUnitTe ) public { // 3 LST Strat multipliers, rETH, stETH, ETH uint96[] memory multipliers = new uint96[](3); - multipliers[0] = uint96(1_070_136_092_289_993_178); - multipliers[1] = uint96(1_071_364_636_818_145_808); - multipliers[2] = uint96(1_000_000_000_000_000_000); + multipliers[0] = uint96(1070136092289993178); + multipliers[1] = uint96(1071364636818145808); + multipliers[2] = uint96(1000000000000000000); - IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](3); + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](3); for (uint256 i = 0; i < strategyParams.length; i++) { shares[i] = uint96(_randUint({rand: bytes32(uint256(shares[i])), min: 0, max: 1e24})); IStrategy strat = IStrategy( address(uint160(uint256(keccak256(abi.encodePacked("Voteweighing test", i))))) ); - strategyParams[i] = IStakeRegistry.StrategyParams(strat, multipliers[i]); + strategyParams[i] = IStakeRegistryTypes.StrategyParams(strat, multipliers[i]); } // create a valid quorum diff --git a/test/utils/BLSMockAVSDeployer.sol b/test/utils/BLSMockAVSDeployer.sol index 84890944..701fd320 100644 --- a/test/utils/BLSMockAVSDeployer.sol +++ b/test/utils/BLSMockAVSDeployer.sol @@ -31,23 +31,23 @@ contract BLSMockAVSDeployer is MockAVSDeployer { function _setAggregatePublicKeysAndSignature() internal { // aggSignerPrivKey*g2 aggSignerApkG2.X[1] = - 19_101_821_850_089_705_274_637_533_855_249_918_363_070_101_489_527_618_151_493_230_256_975_900_223_847; + 19101821850089705274637533855249918363070101489527618151493230256975900223847; aggSignerApkG2.X[0] = - 5_334_410_886_741_819_556_325_359_147_377_682_006_012_228_123_419_628_681_352_847_439_302_316_235_957; + 5334410886741819556325359147377682006012228123419628681352847439302316235957; aggSignerApkG2.Y[1] = - 354_176_189_041_917_478_648_604_979_334_478_067_325_821_134_838_555_150_300_539_079_146_482_658_331; + 354176189041917478648604979334478067325821134838555150300539079146482658331; aggSignerApkG2.Y[0] = - 4_185_483_097_059_047_421_902_184_823_581_361_466_320_657_066_600_218_863_748_375_739_772_335_928_910; + 4185483097059047421902184823581361466320657066600218863748375739772335928910; // 100*aggSignerPrivKey*g2 oneHundredQuorumApkG2.X[1] = - 6_187_649_255_575_786_743_153_792_867_265_230_878_737_103_598_736_372_524_337_965_086_852_090_105_771; + 6187649255575786743153792867265230878737103598736372524337965086852090105771; oneHundredQuorumApkG2.X[0] = - 5_334_877_400_925_935_887_383_922_877_430_837_542_135_722_474_116_902_175_395_820_705_628_447_222_839; + 5334877400925935887383922877430837542135722474116902175395820705628447222839; oneHundredQuorumApkG2.Y[1] = - 4_668_116_328_019_846_503_695_710_811_760_363_536_142_902_258_271_850_958_815_598_072_072_236_299_223; + 4668116328019846503695710811760363536142902258271850958815598072072236299223; oneHundredQuorumApkG2.Y[0] = - 21_446_056_442_597_180_561_077_194_011_672_151_329_458_819_211_586_246_807_143_487_001_691_968_661_015; + 21446056442597180561077194011672151329458819211586246807143487001691968661015; sigma = BN254.hashToG1(msgHash).scalar_mul(aggSignerPrivKey); } diff --git a/test/utils/MockAVSDeployer.sol b/test/utils/MockAVSDeployer.sol index 20bdbb1d..eb5ac6a7 100644 --- a/test/utils/MockAVSDeployer.sol +++ b/test/utils/MockAVSDeployer.sol @@ -16,12 +16,16 @@ import {RegistryCoordinator} from "../../src/RegistryCoordinator.sol"; import {RegistryCoordinatorHarness} from "../harnesses/RegistryCoordinatorHarness.t.sol"; import {BLSApkRegistry} from "../../src/BLSApkRegistry.sol"; import {ServiceManagerMock} from "../mocks/ServiceManagerMock.sol"; -import {StakeRegistry, StakeType} from "../../src/StakeRegistry.sol"; +import {StakeRegistry, IStakeRegistryTypes} from "../../src/StakeRegistry.sol"; import {IndexRegistry} from "../../src/IndexRegistry.sol"; import {IBLSApkRegistry} from "../../src/interfaces/IBLSApkRegistry.sol"; import {IStakeRegistry} from "../../src/interfaces/IStakeRegistry.sol"; import {IIndexRegistry} from "../../src/interfaces/IIndexRegistry.sol"; import {IRegistryCoordinator} from "../../src/interfaces/IRegistryCoordinator.sol"; +import { + ISlashingRegistryCoordinatorTypes, + ISlashingRegistryCoordinatorTypes +} from "../../src/interfaces/ISlashingRegistryCoordinator.sol"; import {ISlashingRegistryCoordinator} from "../../src/interfaces/ISlashingRegistryCoordinator.sol"; import {IServiceManager} from "../../src/interfaces/IServiceManager.sol"; @@ -106,19 +110,19 @@ contract MockAVSDeployer is Test { address defaultOperator = address(uint160(uint256(keccak256("defaultOperator")))); bytes32 defaultOperatorId; BN254.G1Point internal defaultPubKey = BN254.G1Point( - 18_260_007_818_883_133_054_078_754_218_619_977_578_772_505_796_600_400_998_181_738_095_793_040_006_897, - 3_432_351_341_799_135_763_167_709_827_653_955_074_218_841_517_684_851_694_584_291_831_827_675_065_899 + 18260007818883133054078754218619977578772505796600400998181738095793040006897, + 3432351341799135763167709827653955074218841517684851694584291831827675065899 ); string defaultSocket = "69.69.69.69:420"; uint96 defaultStake = 1 ether; uint8 defaultQuorumNumber = 0; uint32 defaultMaxOperatorCount = 10; - uint16 defaultKickBIPsOfOperatorStake = 15_000; + uint16 defaultKickBIPsOfOperatorStake = 15000; uint16 defaultKickBIPsOfTotalStake = 150; uint8 numQuorums = 192; - ISlashingRegistryCoordinator.OperatorSetParam[] operatorSetParams; + ISlashingRegistryCoordinatorTypes.OperatorSetParam[] operatorSetParams; uint8 maxQuorumsToRegisterFor = 4; uint256 maxOperatorsToRegister = 4; @@ -211,8 +215,12 @@ contract MockAVSDeployer is Test { cheats.startPrank(proxyAdminOwner); - stakeRegistryImplementation = - new StakeRegistryHarness(ISlashingRegistryCoordinator(registryCoordinator), delegationMock, avsDirectory, allocationManagerMock); + stakeRegistryImplementation = new StakeRegistryHarness( + ISlashingRegistryCoordinator(registryCoordinator), + delegationMock, + avsDirectory, + allocationManagerMock + ); proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(stakeRegistry))), address(stakeRegistryImplementation) @@ -270,11 +278,12 @@ contract MockAVSDeployer is Test { } // setup the dummy quorum strategies - IStakeRegistry.StrategyParams[][] memory quorumStrategiesConsideredAndMultipliers = - new IStakeRegistry.StrategyParams[][](numQuorumsToAdd); + IStakeRegistryTypes.StrategyParams[][] memory quorumStrategiesConsideredAndMultipliers = + new IStakeRegistryTypes.StrategyParams[][](numQuorumsToAdd); for (uint256 i = 0; i < quorumStrategiesConsideredAndMultipliers.length; i++) { - quorumStrategiesConsideredAndMultipliers[i] = new IStakeRegistry.StrategyParams[](1); - quorumStrategiesConsideredAndMultipliers[i][0] = IStakeRegistry.StrategyParams( + quorumStrategiesConsideredAndMultipliers[i] = + new IStakeRegistryTypes.StrategyParams[](1); + quorumStrategiesConsideredAndMultipliers[i][0] = IStakeRegistryTypes.StrategyParams( IStrategy(address(uint160(i))), uint96(WEIGHTING_DIVISOR) ); } @@ -307,7 +316,7 @@ contract MockAVSDeployer is Test { for (uint256 i = 0; i < numQuorumsToAdd; i++) { // hard code these for now operatorSetParams.push( - ISlashingRegistryCoordinator.OperatorSetParam({ + ISlashingRegistryCoordinatorTypes.OperatorSetParam({ maxOperatorCount: defaultMaxOperatorCount, kickBIPsOfOperatorStake: defaultKickBIPsOfOperatorStake, kickBIPsOfTotalStake: defaultKickBIPsOfTotalStake @@ -326,7 +335,6 @@ contract MockAVSDeployer is Test { quorumStrategiesConsideredAndMultipliers[i] ); } - } operatorStateRetriever = new OperatorStateRetriever(); From ce65f851bb2b2f0c83588ee5d60e85226d89f912 Mon Sep 17 00:00:00 2001 From: steven Date: Mon, 27 Jan 2025 19:06:55 -0500 Subject: [PATCH 49/52] chore: forge fmt --- src/EjectionManager.sol | 28 +++---- src/RegistryCoordinator.sol | 1 - src/ServiceManagerBase.sol | 77 ++++++------------- src/SlashingRegistryCoordinator.sol | 5 +- src/SocketRegistry.sol | 25 ++++-- src/interfaces/ISocketRegistry.sol | 4 +- src/unaudited/ECDSAServiceManagerBase.sol | 62 ++++++--------- .../RegistryCoordinatorHarness.t.sol | 1 - test/integration/IntegrationDeployer.t.sol | 5 +- test/unit/EjectionManagerUnit.t.sol | 46 +++++++---- test/unit/SocketRegistryUnit.t.sol | 10 +-- test/unit/StakeRegistryUnit.t.sol | 1 - 12 files changed, 121 insertions(+), 144 deletions(-) diff --git a/src/EjectionManager.sol b/src/EjectionManager.sol index c3c8c3a4..2d695f27 100644 --- a/src/EjectionManager.sol +++ b/src/EjectionManager.sol @@ -51,16 +51,17 @@ contract EjectionManager is OwnableUpgradeable, EjectionManagerStorage { uint32 ejectedOperators; bool ratelimitHit; - if(amountEjectable > 0 || msg.sender == owner()){ - for(uint8 j = 0; j < operatorIds[i].length; ++j) { - uint256 operatorStake = stakeRegistry.getCurrentStake(operatorIds[i][j], quorumNumber); + if (amountEjectable > 0 || msg.sender == owner()) { + for (uint8 j = 0; j < operatorIds[i].length; ++j) { + uint256 operatorStake = + stakeRegistry.getCurrentStake(operatorIds[i][j], quorumNumber); //if caller is ejector enforce ratelimit - if( - isEjector[msg.sender] && - quorumEjectionParams[quorumNumber].rateLimitWindow > 0 && - stakeForEjection + operatorStake > amountEjectable - ){ + if ( + isEjector[msg.sender] + && quorumEjectionParams[quorumNumber].rateLimitWindow > 0 + && stakeForEjection + operatorStake > amountEjectable + ) { ratelimitHit = true; stakeForEjection += operatorStake; @@ -89,11 +90,10 @@ contract EjectionManager is OwnableUpgradeable, EjectionManagerStorage { } //record the stake ejected if ejector and ratelimit enforced - if(isEjector[msg.sender] && stakeForEjection > 0){ - stakeEjectedForQuorum[quorumNumber].push(StakeEjection({ - timestamp: block.timestamp, - stakeEjected: stakeForEjection - })); + if (isEjector[msg.sender] && stakeForEjection > 0) { + stakeEjectedForQuorum[quorumNumber].push( + StakeEjection({timestamp: block.timestamp, stakeEjected: stakeForEjection}) + ); } emit QuorumEjection(ejectedOperators, ratelimitHit); @@ -162,4 +162,4 @@ contract EjectionManager is OwnableUpgradeable, EjectionManagerStorage { } return totalEjectable - totalEjected; } -} \ No newline at end of file +} diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 392807a9..325722ad 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -11,7 +11,6 @@ import {IServiceManager} from "./interfaces/IServiceManager.sol"; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; import {ISocketRegistry} from "./interfaces/ISocketRegistry.sol"; - import {BitmapUtils} from "./libraries/BitmapUtils.sol"; import {SlashingRegistryCoordinator} from "./SlashingRegistryCoordinator.sol"; import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index 5e043040..5b2ca775 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -154,13 +154,10 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { // transfer token to ServiceManager and approve RewardsCoordinator to transfer again // in createAVSRewardsSubmission() call rewardsSubmissions[i].token.safeTransferFrom( - msg.sender, - address(this), - rewardsSubmissions[i].amount + msg.sender, address(this), rewardsSubmissions[i].amount ); rewardsSubmissions[i].token.safeIncreaseAllowance( - address(_rewardsCoordinator), - rewardsSubmissions[i].amount + address(_rewardsCoordinator), rewardsSubmissions[i].amount ); } @@ -182,43 +179,30 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { * smaller array of submissions if necessary. */ function createOperatorDirectedAVSRewardsSubmission( - IRewardsCoordinator.OperatorDirectedRewardsSubmission[] - calldata operatorDirectedRewardsSubmissions + IRewardsCoordinator.OperatorDirectedRewardsSubmission[] calldata + operatorDirectedRewardsSubmissions ) public virtual onlyRewardsInitiator { - for ( - uint256 i = 0; - i < operatorDirectedRewardsSubmissions.length; - ++i - ) { + for (uint256 i = 0; i < operatorDirectedRewardsSubmissions.length; ++i) { // Calculate total amount of token to transfer uint256 totalAmount = 0; for ( - uint256 j = 0; - j < - operatorDirectedRewardsSubmissions[i].operatorRewards.length; - ++j + uint256 j = 0; j < operatorDirectedRewardsSubmissions[i].operatorRewards.length; ++j ) { - totalAmount += operatorDirectedRewardsSubmissions[i] - .operatorRewards[j] - .amount; + totalAmount += operatorDirectedRewardsSubmissions[i].operatorRewards[j].amount; } // Transfer token to ServiceManager and approve RewardsCoordinator to transfer again // in createOperatorDirectedAVSRewardsSubmission() call operatorDirectedRewardsSubmissions[i].token.safeTransferFrom( - msg.sender, - address(this), - totalAmount + msg.sender, address(this), totalAmount ); operatorDirectedRewardsSubmissions[i].token.safeIncreaseAllowance( - address(_rewardsCoordinator), - totalAmount + address(_rewardsCoordinator), totalAmount ); } _rewardsCoordinator.createOperatorDirectedAVSRewardsSubmission( - address(this), - operatorDirectedRewardsSubmissions + address(this), operatorDirectedRewardsSubmissions ); } @@ -227,7 +211,9 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { * @param claimer The address of the entity that can call `processClaim` on behalf of the earner * @dev Only callable by the owner. */ - function setClaimerFor(address claimer) public virtual onlyOwner { + function setClaimerFor( + address claimer + ) public virtual onlyOwner { _rewardsCoordinator.setClaimerFor(claimer); } @@ -289,12 +275,7 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { * @dev No guarantee is made on uniqueness of each element in the returned array. * The off-chain service should do that validation separately */ - function getRestakeableStrategies() - external - view - virtual - returns (address[] memory) - { + function getRestakeableStrategies() external view virtual returns (address[] memory) { uint256 quorumCount = _registryCoordinator.quorumCount(); if (quorumCount == 0) { @@ -309,13 +290,10 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { address[] memory restakedStrategies = new address[](strategyCount); uint256 index = 0; for (uint256 i = 0; i < _registryCoordinator.quorumCount(); i++) { - uint256 strategyParamsLength = _stakeRegistry.strategyParamsLength( - uint8(i) - ); + uint256 strategyParamsLength = _stakeRegistry.strategyParamsLength(uint8(i)); for (uint256 j = 0; j < strategyParamsLength; j++) { - restakedStrategies[index] = address( - _stakeRegistry.strategyParamsByIndex(uint8(i), j).strategy - ); + restakedStrategies[index] = + address(_stakeRegistry.strategyParamsByIndex(uint8(i), j).strategy); index++; } } @@ -333,23 +311,17 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { address operator ) external view virtual returns (address[] memory) { bytes32 operatorId = _registryCoordinator.getOperatorId(operator); - uint192 operatorBitmap = _registryCoordinator.getCurrentQuorumBitmap( - operatorId - ); + uint192 operatorBitmap = _registryCoordinator.getCurrentQuorumBitmap(operatorId); if (operatorBitmap == 0 || _registryCoordinator.quorumCount() == 0) { return new address[](0); } // Get number of strategies for each quorum in operator bitmap - bytes memory operatorRestakedQuorums = BitmapUtils.bitmapToBytesArray( - operatorBitmap - ); + bytes memory operatorRestakedQuorums = BitmapUtils.bitmapToBytesArray(operatorBitmap); uint256 strategyCount; for (uint256 i = 0; i < operatorRestakedQuorums.length; i++) { - strategyCount += _stakeRegistry.strategyParamsLength( - uint8(operatorRestakedQuorums[i]) - ); + strategyCount += _stakeRegistry.strategyParamsLength(uint8(operatorRestakedQuorums[i])); } // Get strategies for each quorum in operator bitmap @@ -357,13 +329,10 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { uint256 index = 0; for (uint256 i = 0; i < operatorRestakedQuorums.length; i++) { uint8 quorum = uint8(operatorRestakedQuorums[i]); - uint256 strategyParamsLength = _stakeRegistry.strategyParamsLength( - quorum - ); + uint256 strategyParamsLength = _stakeRegistry.strategyParamsLength(quorum); for (uint256 j = 0; j < strategyParamsLength; j++) { - restakedStrategies[index] = address( - _stakeRegistry.strategyParamsByIndex(quorum, j).strategy - ); + restakedStrategies[index] = + address(_stakeRegistry.strategyParamsByIndex(quorum, j).strategy); index++; } } diff --git a/src/SlashingRegistryCoordinator.sol b/src/SlashingRegistryCoordinator.sol index a8a931ec..101fad15 100644 --- a/src/SlashingRegistryCoordinator.sol +++ b/src/SlashingRegistryCoordinator.sol @@ -16,7 +16,6 @@ import {IIndexRegistry} from "./interfaces/IIndexRegistry.sol"; import {ISlashingRegistryCoordinator} from "./interfaces/ISlashingRegistryCoordinator.sol"; import {ISocketRegistry} from "./interfaces/ISocketRegistry.sol"; - import {BitmapUtils} from "./libraries/BitmapUtils.sol"; import {BN254} from "./libraries/BN254.sol"; import {SignatureCheckerLib} from "./libraries/SignatureCheckerLib.sol"; @@ -341,7 +340,9 @@ contract SlashingRegistryCoordinator is * @notice Updates the socket of the msg.sender given they are a registered operator * @param socket is the new socket of the operator */ - function updateSocket(string memory socket) external { + function updateSocket( + string memory socket + ) external { require(_operatorInfo[msg.sender].status == OperatorStatus.REGISTERED, NotRegistered()); _setOperatorSocket(_operatorInfo[msg.sender].operatorId, socket); } diff --git a/src/SocketRegistry.sol b/src/SocketRegistry.sol index 8ede8dda..e0668782 100644 --- a/src/SocketRegistry.sol +++ b/src/SocketRegistry.sol @@ -9,7 +9,6 @@ import {ISocketRegistry} from "./interfaces/ISocketRegistry.sol"; * @author Layr Labs, Inc. */ contract SocketRegistry is ISocketRegistry { - /// @notice The address of the RegistryCoordinator address public immutable registryCoordinator; @@ -18,28 +17,40 @@ contract SocketRegistry is ISocketRegistry { /// @notice A modifier that only allows the RegistryCoordinator to call a function modifier onlyRegistryCoordinator() { - require(msg.sender == address(registryCoordinator), "SocketRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator"); + require( + msg.sender == address(registryCoordinator), + "SocketRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator" + ); _; } /// @notice A modifier that only allows the owner of the RegistryCoordinator to call a function modifier onlyCoordinatorOwner() { - require(msg.sender == IRegistryCoordinator(registryCoordinator).owner(), "SocketRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator"); + require( + msg.sender == IRegistryCoordinator(registryCoordinator).owner(), + "SocketRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator" + ); _; } - constructor(IRegistryCoordinator _registryCoordinator) { + constructor( + IRegistryCoordinator _registryCoordinator + ) { registryCoordinator = address(_registryCoordinator); } /// @notice sets the socket for an operator only callable by the RegistryCoordinator - function setOperatorSocket(bytes32 _operatorId, string memory _socket) external onlyRegistryCoordinator { + function setOperatorSocket( + bytes32 _operatorId, + string memory _socket + ) external onlyRegistryCoordinator { operatorIdToSocket[_operatorId] = _socket; } /// @notice gets the stored socket for an operator - function getOperatorSocket(bytes32 _operatorId) external view returns (string memory) { + function getOperatorSocket( + bytes32 _operatorId + ) external view returns (string memory) { return operatorIdToSocket[_operatorId]; } - } diff --git a/src/interfaces/ISocketRegistry.sol b/src/interfaces/ISocketRegistry.sol index 136a345b..c456a4f9 100644 --- a/src/interfaces/ISocketRegistry.sol +++ b/src/interfaces/ISocketRegistry.sol @@ -6,5 +6,7 @@ interface ISocketRegistry { function setOperatorSocket(bytes32 _operatorId, string memory _socket) external; /// @notice gets the stored socket for an operator - function getOperatorSocket(bytes32 _operatorId) external view returns (string memory); + function getOperatorSocket( + bytes32 _operatorId + ) external view returns (string memory); } diff --git a/src/unaudited/ECDSAServiceManagerBase.sol b/src/unaudited/ECDSAServiceManagerBase.sol index 585cf34c..d5bf2c55 100644 --- a/src/unaudited/ECDSAServiceManagerBase.sol +++ b/src/unaudited/ECDSAServiceManagerBase.sol @@ -20,10 +20,7 @@ import {IAVSRegistrar} from "eigenlayer-contracts/src/contracts/interfaces/IAVSR import {IAllocationManager} from "eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; -abstract contract ECDSAServiceManagerBase is - IServiceManager, - OwnableUpgradeable -{ +abstract contract ECDSAServiceManagerBase is IServiceManager, OwnableUpgradeable { using SafeERC20 for IERC20; /// @notice Address of the stake registry contract, which manages registration and stake recording. @@ -115,15 +112,15 @@ abstract contract ECDSAServiceManagerBase is } function createOperatorDirectedAVSRewardsSubmission( - IRewardsCoordinator.OperatorDirectedRewardsSubmission[] - calldata operatorDirectedRewardsSubmissions - ) external virtual onlyRewardsInitiator { - _createOperatorDirectedAVSRewardsSubmission( + IRewardsCoordinator.OperatorDirectedRewardsSubmission[] calldata operatorDirectedRewardsSubmissions - ); + ) external virtual onlyRewardsInitiator { + _createOperatorDirectedAVSRewardsSubmission(operatorDirectedRewardsSubmissions); } - function setClaimerFor(address claimer) external virtual onlyOwner { + function setClaimerFor( + address claimer + ) external virtual onlyOwner { _setClaimerFor(claimer); } @@ -199,13 +196,10 @@ abstract contract ECDSAServiceManagerBase is ) internal virtual { for (uint256 i = 0; i < rewardsSubmissions.length; ++i) { rewardsSubmissions[i].token.safeTransferFrom( - msg.sender, - address(this), - rewardsSubmissions[i].amount + msg.sender, address(this), rewardsSubmissions[i].amount ); rewardsSubmissions[i].token.safeIncreaseAllowance( - rewardsCoordinator, - rewardsSubmissions[i].amount + rewardsCoordinator, rewardsSubmissions[i].amount ); } @@ -218,52 +212,40 @@ abstract contract ECDSAServiceManagerBase is * @param operatorDirectedRewardsSubmissions The operator-directed rewards submissions being created. */ function _createOperatorDirectedAVSRewardsSubmission( - IRewardsCoordinator.OperatorDirectedRewardsSubmission[] - calldata operatorDirectedRewardsSubmissions + IRewardsCoordinator.OperatorDirectedRewardsSubmission[] calldata + operatorDirectedRewardsSubmissions ) internal virtual { - for ( - uint256 i = 0; - i < operatorDirectedRewardsSubmissions.length; - ++i - ) { + for (uint256 i = 0; i < operatorDirectedRewardsSubmissions.length; ++i) { // Calculate total amount of token to transfer uint256 totalAmount = 0; for ( - uint256 j = 0; - j < - operatorDirectedRewardsSubmissions[i].operatorRewards.length; - ++j + uint256 j = 0; j < operatorDirectedRewardsSubmissions[i].operatorRewards.length; ++j ) { - totalAmount += operatorDirectedRewardsSubmissions[i] - .operatorRewards[j] - .amount; + totalAmount += operatorDirectedRewardsSubmissions[i].operatorRewards[j].amount; } // Transfer token to ServiceManager and approve RewardsCoordinator to transfer again // in createOperatorDirectedAVSRewardsSubmission() call operatorDirectedRewardsSubmissions[i].token.safeTransferFrom( - msg.sender, - address(this), - totalAmount + msg.sender, address(this), totalAmount ); operatorDirectedRewardsSubmissions[i].token.safeIncreaseAllowance( - rewardsCoordinator, - totalAmount + rewardsCoordinator, totalAmount ); } - IRewardsCoordinator(rewardsCoordinator) - .createOperatorDirectedAVSRewardsSubmission( - address(this), - operatorDirectedRewardsSubmissions - ); + IRewardsCoordinator(rewardsCoordinator).createOperatorDirectedAVSRewardsSubmission( + address(this), operatorDirectedRewardsSubmissions + ); } /** * @notice Forwards a call to Eigenlayer's RewardsCoordinator contract to set the address of the entity that can call `processClaim` on behalf of this contract. * @param claimer The address of the entity that can call `processClaim` on behalf of the earner. */ - function _setClaimerFor(address claimer) internal virtual { + function _setClaimerFor( + address claimer + ) internal virtual { IRewardsCoordinator(rewardsCoordinator).setClaimerFor(claimer); } diff --git a/test/harnesses/RegistryCoordinatorHarness.t.sol b/test/harnesses/RegistryCoordinatorHarness.t.sol index 9274b688..050fae43 100644 --- a/test/harnesses/RegistryCoordinatorHarness.t.sol +++ b/test/harnesses/RegistryCoordinatorHarness.t.sol @@ -5,7 +5,6 @@ import "../../src/RegistryCoordinator.sol"; import {ISocketRegistry} from "../../src/interfaces/ISocketRegistry.sol"; - import "forge-std/Test.sol"; // wrapper around the RegistryCoordinator contract that exposes the internal functions for unit testing. diff --git a/test/integration/IntegrationDeployer.t.sol b/test/integration/IntegrationDeployer.t.sol index d6c6a085..3e38d697 100644 --- a/test/integration/IntegrationDeployer.t.sol +++ b/test/integration/IntegrationDeployer.t.sol @@ -364,9 +364,8 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { permissionController, allocationManager ); - SocketRegistry socketRegistryImplementation = new SocketRegistry( - IRegistryCoordinator(registryCoordinator) - ); + SocketRegistry socketRegistryImplementation = + new SocketRegistry(IRegistryCoordinator(registryCoordinator)); proxyAdmin.upgrade( TransparentUpgradeableProxy(payable(address(stakeRegistry))), diff --git a/test/unit/EjectionManagerUnit.t.sol b/test/unit/EjectionManagerUnit.t.sol index 1a9c20c8..ac557c62 100644 --- a/test/unit/EjectionManagerUnit.t.sol +++ b/test/unit/EjectionManagerUnit.t.sol @@ -205,17 +205,21 @@ contract EjectionManagerUnitTests is MockAVSDeployer { bytes32[][] memory operatorIds = new bytes32[][](numQuorums); for (uint8 i = 0; i < numQuorums; i++) { operatorIds[i] = new bytes32[](operatorsToEject); - for (uint j = 0; j < operatorsToEject; j++) { - operatorIds[i][j] = registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); + for (uint256 j = 0; j < operatorsToEject; j++) { + operatorIds[i][j] = + registryCoordinator.getOperatorId(_incrementAddress(defaultOperator, j)); } } - for(uint8 i = 0; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED)); + for (uint8 i = 0; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED) + ); } - for(uint8 i = 0; i < numQuorums; i++) { - for(uint8 j = 0; j < operatorsCanEject; j++) { + for (uint8 i = 0; i < numQuorums; i++) { + for (uint8 j = 0; j < operatorsCanEject; j++) { cheats.expectEmit(true, true, true, true, address(ejectionManager)); emit OperatorEjected(operatorIds[i][j], i); } @@ -224,23 +228,35 @@ contract EjectionManagerUnitTests is MockAVSDeployer { cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsCanEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsCanEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED) + ); } - for(uint8 i = operatorsCanEject; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED)); + for (uint8 i = operatorsCanEject; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED) + ); } cheats.prank(ejector); ejectionManager.ejectOperators(operatorIds); - for(uint8 i = 0; i < operatorsCanEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED)); + for (uint8 i = 0; i < operatorsCanEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.DEREGISTERED) + ); } - for(uint8 i = operatorsCanEject; i < operatorsToEject; i++) { - assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED)); + for (uint8 i = operatorsCanEject; i < operatorsToEject; i++) { + assertEq( + uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), + uint8(ISlashingRegistryCoordinatorTypes.OperatorStatus.REGISTERED) + ); } } @@ -525,4 +541,4 @@ contract EjectionManagerUnitTests is MockAVSDeployer { _registerOperatorWithCoordinator(operator, MAX_QUORUM_BITMAP, pubKey, stake); } } -} \ No newline at end of file +} diff --git a/test/unit/SocketRegistryUnit.t.sol b/test/unit/SocketRegistryUnit.t.sol index af5be131..834b3977 100644 --- a/test/unit/SocketRegistryUnit.t.sol +++ b/test/unit/SocketRegistryUnit.t.sol @@ -7,8 +7,7 @@ import {IRegistryCoordinator} from "../../src/interfaces/IRegistryCoordinator.so import "../utils/MockAVSDeployer.sol"; contract SocketRegistryUnitTests is MockAVSDeployer { - - function setUp() virtual public { + function setUp() public virtual { _deployMockEigenLayerAndAVS(); } @@ -20,8 +19,9 @@ contract SocketRegistryUnitTests is MockAVSDeployer { function test_setOperatorSocket_revert_notRegistryCoordinator() public { vm.startPrank(address(0)); - vm.expectRevert("SocketRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator"); + vm.expectRevert( + "SocketRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator" + ); socketRegistry.setOperatorSocket(defaultOperatorId, "testSocket"); } - -} \ No newline at end of file +} diff --git a/test/unit/StakeRegistryUnit.t.sol b/test/unit/StakeRegistryUnit.t.sol index 58614ea6..34399fc9 100644 --- a/test/unit/StakeRegistryUnit.t.sol +++ b/test/unit/StakeRegistryUnit.t.sol @@ -10,7 +10,6 @@ import {IStakeRegistry, IStakeRegistryErrors} from "src/interfaces/IStakeRegistr import {IStakeRegistryEvents} from "test/events/IStakeRegistryEvents.sol"; import {ISocketRegistry} from "src/interfaces/ISocketRegistry.sol"; - import "../utils/MockAVSDeployer.sol"; contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { From c558283a3c801a3f868a8aa377bff8c7f6ded3be Mon Sep 17 00:00:00 2001 From: steven Date: Mon, 27 Jan 2025 19:14:08 -0500 Subject: [PATCH 50/52] feat: storage gap on socket registry --- src/SocketRegistry.sol | 13 +++---------- src/SocketRegistryStorage.sol | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 src/SocketRegistryStorage.sol diff --git a/src/SocketRegistry.sol b/src/SocketRegistry.sol index e0668782..691af84b 100644 --- a/src/SocketRegistry.sol +++ b/src/SocketRegistry.sol @@ -3,18 +3,13 @@ pragma solidity ^0.8.12; import {IRegistryCoordinator} from "./interfaces/IRegistryCoordinator.sol"; import {ISocketRegistry} from "./interfaces/ISocketRegistry.sol"; +import {SocketRegistryStorage} from "./SocketRegistryStorage.sol"; /** * @title A `Registry` that keeps track of operator sockets. * @author Layr Labs, Inc. */ -contract SocketRegistry is ISocketRegistry { - /// @notice The address of the RegistryCoordinator - address public immutable registryCoordinator; - - /// @notice A mapping from operator IDs to their sockets - mapping(bytes32 => string) public operatorIdToSocket; - +contract SocketRegistry is ISocketRegistry, SocketRegistryStorage { /// @notice A modifier that only allows the RegistryCoordinator to call a function modifier onlyRegistryCoordinator() { require( @@ -35,9 +30,7 @@ contract SocketRegistry is ISocketRegistry { constructor( IRegistryCoordinator _registryCoordinator - ) { - registryCoordinator = address(_registryCoordinator); - } + ) SocketRegistryStorage(address(_registryCoordinator)) {} /// @notice sets the socket for an operator only callable by the RegistryCoordinator function setOperatorSocket( diff --git a/src/SocketRegistryStorage.sol b/src/SocketRegistryStorage.sol new file mode 100644 index 00000000..4f700173 --- /dev/null +++ b/src/SocketRegistryStorage.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.12; + +/** + * @title Storage contract for SocketRegistry + * @author Layr Labs, Inc. + */ +contract SocketRegistryStorage { + /// @notice The address of the RegistryCoordinator + address public immutable registryCoordinator; + + /// @notice A mapping from operator IDs to their sockets + mapping(bytes32 => string) public operatorIdToSocket; + + constructor( + address _registryCoordinator + ) { + registryCoordinator = _registryCoordinator; + } + + uint256[48] private __GAP; +} From 650024ae01a997e9f6e3156d40d7225e78601a02 Mon Sep 17 00:00:00 2001 From: Yash Patil <40046473+ypatil12@users.noreply.github.com> Date: Mon, 27 Jan 2025 19:15:58 -0500 Subject: [PATCH 51/52] chore: remove unused storage; update bindings --- .../ServiceManagerBaseStorage.md | 19 +++++++++++++++++++ docs/storage-report/SocketRegistry.md | 0 docs/storage-report/SocketRegistryStorage.md | 0 src/ServiceManagerBase.sol | 2 -- src/ServiceManagerBaseStorage.sol | 14 +------------- 5 files changed, 20 insertions(+), 15 deletions(-) create mode 100644 docs/storage-report/SocketRegistry.md create mode 100644 docs/storage-report/SocketRegistryStorage.md diff --git a/docs/storage-report/ServiceManagerBaseStorage.md b/docs/storage-report/ServiceManagerBaseStorage.md index e69de29b..16e40d2d 100644 --- a/docs/storage-report/ServiceManagerBaseStorage.md +++ b/docs/storage-report/ServiceManagerBaseStorage.md @@ -0,0 +1,19 @@ + +╭------------------+-------------+------+--------+-------+-------------------------------------------------------------╮ +| Name | Type | Slot | Offset | Bytes | Contract | ++======================================================================================================================+ +| _initialized | uint8 | 0 | 0 | 1 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| _initializing | bool | 0 | 1 | 1 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| __gap | uint256[50] | 1 | 0 | 1600 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| _owner | address | 51 | 0 | 20 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| __gap | uint256[49] | 52 | 0 | 1568 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| rewardsInitiator | address | 101 | 0 | 20 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +|------------------+-------------+------+--------+-------+-------------------------------------------------------------| +| __GAP | uint256[49] | 102 | 0 | 1568 | src/ServiceManagerBaseStorage.sol:ServiceManagerBaseStorage | +╰------------------+-------------+------+--------+-------+-------------------------------------------------------------╯ + diff --git a/docs/storage-report/SocketRegistry.md b/docs/storage-report/SocketRegistry.md new file mode 100644 index 00000000..e69de29b diff --git a/docs/storage-report/SocketRegistryStorage.md b/docs/storage-report/SocketRegistryStorage.md new file mode 100644 index 00000000..e69de29b diff --git a/src/ServiceManagerBase.sol b/src/ServiceManagerBase.sol index 5b2ca775..d11e7197 100644 --- a/src/ServiceManagerBase.sol +++ b/src/ServiceManagerBase.sol @@ -35,8 +35,6 @@ abstract contract ServiceManagerBase is ServiceManagerBaseStorage { using SafeERC20 for IERC20; using BitmapUtils for *; - uint256 public constant SLASHER_PROPOSAL_DELAY = 7 days; - /// @notice when applied to a function, only allows the RegistryCoordinator to call it modifier onlyRegistryCoordinator() { require(msg.sender == address(_registryCoordinator), OnlyRegistryCoordinator()); diff --git a/src/ServiceManagerBaseStorage.sol b/src/ServiceManagerBaseStorage.sol index e3e25f58..4fdd0039 100644 --- a/src/ServiceManagerBaseStorage.sol +++ b/src/ServiceManagerBaseStorage.sol @@ -44,18 +44,6 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab /// @notice The address of the entity that can initiate rewards address public rewardsInitiator; - /// @notice The address of the slasher account - address public slasher; - - /// @notice The address of the proposed slasher account - address public proposedSlasher; - - /// @notice The timestamp when the slasher was proposed - uint256 public slasherProposalTimestamp; - - /// @notice Boolean indicating if the migration has been finalized - bool public migrationFinalized; - /// @notice Sets the (immutable) `_avsDirectory`, `_rewardsCoordinator`, `_registryCoordinator`, `_stakeRegistry`, and `_allocationManager` addresses constructor( IAVSDirectory __avsDirectory, @@ -74,5 +62,5 @@ abstract contract ServiceManagerBaseStorage is IServiceManager, OwnableUpgradeab } // storage gap for upgradeability - uint256[45] private __GAP; + uint256[49] private __GAP; } From 2015201b176edcea9e9a1993d34fff33ecdf7819 Mon Sep 17 00:00:00 2001 From: steven Date: Mon, 27 Jan 2025 19:18:54 -0500 Subject: [PATCH 52/52] chore: nuke storage report script for now on ci --- .github/bin/storage-report.sh | 45 -------------------------- .github/workflows/storage-report.yml | 48 ---------------------------- 2 files changed, 93 deletions(-) delete mode 100644 .github/bin/storage-report.sh delete mode 100644 .github/workflows/storage-report.yml diff --git a/.github/bin/storage-report.sh b/.github/bin/storage-report.sh deleted file mode 100644 index 4c34d5ac..00000000 --- a/.github/bin/storage-report.sh +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/sh - -# Default output directory -OUTPUT_DIR=${1:-docs/storage-report} - -# Function to print messages -log() { - echo "$(date '+%Y-%m-%d %H:%M:%S') [INFO] $1" -} - -# Function to print error messages -error() { - echo "$(date '+%Y-%m-%d %H:%M:%S') [ERROR] $1" >&2 -} - -log "Starting the storage report generation." - -# Create the output directory if it doesn't exist -if ! mkdir -p "$OUTPUT_DIR"; then - error "Failed to create output directory: $OUTPUT_DIR" - exit 1 -fi - -log "Output directory is set to: $OUTPUT_DIR" - -# Loop through Solidity files and generate storage report -# NOTE: Ignores `src/interfaces` & `src/libraries` since they "should" not contain storage logic. -for file in $(find src/ -name "*.sol" ! -path "*/interfaces/*" ! -path "*/libraries/*"); do - contract_name=$(basename "$file" .sol) - - # Check if the file exists and is readable - if [ ! -r "$file" ]; then - error "Cannot read file: $file" - continue - fi - - log "Processing contract: $contract_name" - - # Run forge inspect and capture errors - if ! forge inspect "$contract_name" storage > "$OUTPUT_DIR/$contract_name.md"; then - error "Failed to generate storage report for contract: $contract_name" - else - log "Storage report generated for contract: $contract_name" - fi -done \ No newline at end of file diff --git a/.github/workflows/storage-report.yml b/.github/workflows/storage-report.yml deleted file mode 100644 index 5d7f50d3..00000000 --- a/.github/workflows/storage-report.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Storage Layout - -on: - push: - branches: - - master - - mainnet - - testnet-goerli - - dev - pull_request: - -jobs: - check_storage: - name: CI - runs-on: "ubuntu-latest" - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - - name: Install Foundry - uses: foundry-rs/foundry-toolchain@v1 - with: - version: nightly - - - name: "Generate and prepare the storage reports for current branch" - run: | - bash .github/bin/storage-report.sh pr - - - name: Checkout dev - env: - TARGET: ${{ github.event.pull_request.base.sha }} - run: | - git fetch origin $TARGET - git checkout $TARGET - - - name: "Generate and prepare the storage reports for target branch" - run: | - bash .github/bin/storage-report.sh target - - - name: Compare outputs - run: | - if diff --unified pr target; then - echo "No differences found" - else - echo "::error::Differences found between PR and target branch storage layouts" - exit 1 - fi \ No newline at end of file