diff --git a/src/StakeRegistry.sol b/src/StakeRegistry.sol index 87e04fdf..929b67d9 100644 --- a/src/StakeRegistry.sol +++ b/src/StakeRegistry.sol @@ -24,20 +24,17 @@ contract StakeRegistry is StakeRegistryStorage { using BitmapUtils for *; modifier onlyRegistryCoordinator() { - require( - msg.sender == address(registryCoordinator), - "StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator" - ); + _checkRegistryCoordinator(); _; } modifier onlyCoordinatorOwner() { - require(msg.sender == IRegistryCoordinator(registryCoordinator).owner(), "StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator"); + _checkRegistryCoordinatorOwner(); _; } modifier quorumExists(uint8 quorumNumber) { - require(_quorumExists(quorumNumber), "StakeRegistry.quorumExists: quorum does not exist"); + _checkQuorumExists(quorumNumber); _; } @@ -74,7 +71,7 @@ contract StakeRegistry is StakeRegistryStorage { for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); - require(_quorumExists(quorumNumber), "StakeRegistry.registerOperator: quorum does not exist"); + _checkQuorumExists(quorumNumber); // Retrieve the operator's current weighted stake for the quorum, reverting if they have not met // the minimum. @@ -121,7 +118,7 @@ contract StakeRegistry is StakeRegistryStorage { */ for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); - require(_quorumExists(quorumNumber), "StakeRegistry.deregisterOperator: quorum does not exist"); + _checkQuorumExists(quorumNumber); // Update the operator's stake for the quorum and retrieve the shares removed int256 stakeDelta = _recordOperatorStakeUpdate({ @@ -161,7 +158,7 @@ contract StakeRegistry is StakeRegistryStorage { */ for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); - require(_quorumExists(quorumNumber), "StakeRegistry.updateOperatorStake: quorum does not exist"); + _checkQuorumExists(quorumNumber); // Fetch the operator's current stake, applying weighting parameters and checking // against the minimum stake requirements for the quorum. @@ -697,7 +694,7 @@ contract StakeRegistry is StakeRegistryStorage { uint32[] memory indices = new uint32[](quorumNumbers.length); for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); - require(_quorumExists(quorumNumber), "StakeRegistry.getTotalStakeIndicesAtBlockNumber: quorum does not exist"); + _checkQuorumExists(quorumNumber); require( _totalStakeHistory[quorumNumber][0].updateBlockNumber <= blockNumber, "StakeRegistry.getTotalStakeIndicesAtBlockNumber: quorum has no stake history at blockNumber" @@ -712,4 +709,19 @@ contract StakeRegistry is StakeRegistryStorage { } return indices; } + + function _checkRegistryCoordinator() internal view { + require( + msg.sender == address(registryCoordinator), + "StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator" + ); + } + + function _checkRegistryCoordinatorOwner() internal view { + require(msg.sender == IRegistryCoordinator(registryCoordinator).owner(), "StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator"); + } + + function _checkQuorumExists(uint8 quorumNumber) internal view { + require(_quorumExists(quorumNumber), "StakeRegistry.quorumExists: quorum does not exist"); + } } diff --git a/test/unit/OperatorStateRetrieverUnit.t.sol b/test/unit/OperatorStateRetrieverUnit.t.sol index 89a9d94a..ba4fe75e 100644 --- a/test/unit/OperatorStateRetrieverUnit.t.sol +++ b/test/unit/OperatorStateRetrieverUnit.t.sol @@ -6,15 +6,18 @@ import "../utils/MockAVSDeployer.sol"; contract OperatorStateRetrieverUnitTests is MockAVSDeployer { using BN254 for BN254.G1Point; - - function setUp() virtual public { + function setUp() public virtual { numQuorums = 8; _deployMockEigenLayerAndAVS(numQuorums); } function test_getOperatorState_revert_neverRegistered() public { - cheats.expectRevert("RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number"); - operatorStateRetriever.getOperatorState(registryCoordinator, defaultOperatorId, uint32(block.number)); + cheats.expectRevert( + "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number" + ); + operatorStateRetriever.getOperatorState( + registryCoordinator, defaultOperatorId, uint32(block.number) + ); } function test_getOperatorState_revert_registeredFirstAfterReferenceBlockNumber() public { @@ -22,8 +25,12 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { _registerOperatorWithCoordinator(defaultOperator, 1, defaultPubKey); // 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"); - operatorStateRetriever.getOperatorState(registryCoordinator, defaultOperatorId, registrationBlockNumber - 1); + cheats.expectRevert( + "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number" + ); + operatorStateRetriever.getOperatorState( + registryCoordinator, defaultOperatorId, registrationBlockNumber - 1 + ); } function test_getOperatorState_deregisteredBeforeReferenceBlockNumber() public { @@ -35,7 +42,10 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { cheats.prank(defaultOperator); registryCoordinator.deregisterOperator(BitmapUtils.bitmapToBytesArray(quorumBitmap)); - (uint256 fetchedQuorumBitmap, OperatorStateRetriever.Operator[][] memory operators) = operatorStateRetriever.getOperatorState(registryCoordinator, defaultOperatorId, uint32(block.number)); + (uint256 fetchedQuorumBitmap, OperatorStateRetriever.Operator[][] memory operators) = + operatorStateRetriever.getOperatorState( + registryCoordinator, defaultOperatorId, uint32(block.number) + ); assertEq(fetchedQuorumBitmap, 0); assertEq(operators.length, 0); } @@ -45,7 +55,10 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { cheats.roll(registrationBlockNumber); _registerOperatorWithCoordinator(defaultOperator, quorumBitmap, defaultPubKey); - (uint256 fetchedQuorumBitmap, OperatorStateRetriever.Operator[][] memory operators) = operatorStateRetriever.getOperatorState(registryCoordinator, defaultOperatorId, uint32(block.number)); + (uint256 fetchedQuorumBitmap, OperatorStateRetriever.Operator[][] memory operators) = + operatorStateRetriever.getOperatorState( + registryCoordinator, defaultOperatorId, uint32(block.number) + ); assertEq(fetchedQuorumBitmap, 1); assertEq(operators.length, 1); assertEq(operators[0].length, 1); @@ -55,31 +68,41 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { } function test_getOperatorState_revert_quorumNotCreatedAtCallTime() public { - cheats.expectRevert("IndexRegistry._operatorCountAtBlockNumber: quorum did not exist at given block number"); - operatorStateRetriever.getOperatorState(registryCoordinator, BitmapUtils.bitmapToBytesArray(1 << numQuorums), uint32(block.number)); + cheats.expectRevert( + "IndexRegistry._operatorCountAtBlockNumber: quorum did not exist at given block number" + ); + operatorStateRetriever.getOperatorState( + registryCoordinator, + BitmapUtils.bitmapToBytesArray(1 << numQuorums), + uint32(block.number) + ); } function test_getOperatorState_revert_quorumNotCreatedAtReferenceBlockNumber() public { cheats.roll(registrationBlockNumber); - 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}); cheats.prank(registryCoordinator.owner()); registryCoordinator.createQuorum(operatorSetParams, minimumStake, strategyParams); - cheats.expectRevert("IndexRegistry._operatorCountAtBlockNumber: quorum did not exist at given block number"); - operatorStateRetriever.getOperatorState(registryCoordinator, BitmapUtils.bitmapToBytesArray(1 << numQuorums), uint32(registrationBlockNumber - 1)); + cheats.expectRevert( + "IndexRegistry._operatorCountAtBlockNumber: quorum did not exist at given block number" + ); + operatorStateRetriever.getOperatorState( + registryCoordinator, + BitmapUtils.bitmapToBytesArray(1 << numQuorums), + uint32(registrationBlockNumber - 1) + ); } function test_getOperatorState_returnsCorrect() public { @@ -91,9 +114,16 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { address otherOperator = _incrementAddress(defaultOperator, 1); BN254.G1Point memory otherPubKey = BN254.G1Point(1, 2); bytes32 otherOperatorId = BN254.hashG1Point(otherPubKey); - _registerOperatorWithCoordinator(otherOperator, quorumBitmapThree, otherPubKey, defaultStake -1); + _registerOperatorWithCoordinator( + otherOperator, quorumBitmapThree, otherPubKey, defaultStake - 1 + ); - OperatorStateRetriever.Operator[][] memory operators = operatorStateRetriever.getOperatorState(registryCoordinator, BitmapUtils.bitmapToBytesArray(quorumBitmapThree), uint32(block.number)); + OperatorStateRetriever.Operator[][] memory operators = operatorStateRetriever + .getOperatorState( + registryCoordinator, + BitmapUtils.bitmapToBytesArray(quorumBitmapThree), + uint32(block.number) + ); assertEq(operators.length, 2); assertEq(operators[0].length, 2); assertEq(operators[1].length, 1); @@ -112,11 +142,20 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { bytes32[] memory nonSignerOperatorIds = new bytes32[](1); nonSignerOperatorIds[0] = defaultOperatorId; - cheats.expectRevert("RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number"); - operatorStateRetriever.getCheckSignaturesIndices(registryCoordinator, uint32(block.number), BitmapUtils.bitmapToBytesArray(1), nonSignerOperatorIds); + cheats.expectRevert( + "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number" + ); + operatorStateRetriever.getCheckSignaturesIndices( + registryCoordinator, + uint32(block.number), + BitmapUtils.bitmapToBytesArray(1), + nonSignerOperatorIds + ); } - function test_getCheckSignaturesIndices_revert_registeredFirstAfterReferenceBlockNumber() public { + function test_getCheckSignaturesIndices_revert_registeredFirstAfterReferenceBlockNumber() + public + { bytes32[] memory nonSignerOperatorIds = new bytes32[](1); nonSignerOperatorIds[0] = defaultOperatorId; @@ -124,8 +163,15 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { _registerOperatorWithCoordinator(defaultOperator, 1, defaultPubKey); // 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"); - operatorStateRetriever.getCheckSignaturesIndices(registryCoordinator, registrationBlockNumber - 1, BitmapUtils.bitmapToBytesArray(1), nonSignerOperatorIds); + cheats.expectRevert( + "RegistryCoordinator.getQuorumBitmapIndexAtBlockNumber: no bitmap update found for operatorId at block number" + ); + operatorStateRetriever.getCheckSignaturesIndices( + registryCoordinator, + registrationBlockNumber - 1, + BitmapUtils.bitmapToBytesArray(1), + nonSignerOperatorIds + ); } function test_getCheckSignaturesIndices_revert_deregisteredAtReferenceBlockNumber() public { @@ -140,8 +186,15 @@ 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"); - operatorStateRetriever.getCheckSignaturesIndices(registryCoordinator, uint32(block.number), BitmapUtils.bitmapToBytesArray(1), nonSignerOperatorIds); + cheats.expectRevert( + "OperatorStateRetriever.getCheckSignaturesIndices: operator must be registered at blocknumber" + ); + operatorStateRetriever.getCheckSignaturesIndices( + registryCoordinator, + uint32(block.number), + BitmapUtils.bitmapToBytesArray(1), + nonSignerOperatorIds + ); } function test_getCheckSignaturesIndices_revert_quorumNotCreatedAtCallTime() public { @@ -150,11 +203,18 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { _registerOperatorWithCoordinator(defaultOperator, 1, defaultPubKey); - cheats.expectRevert("StakeRegistry.getTotalStakeIndicesAtBlockNumber: quorum does not exist"); - operatorStateRetriever.getCheckSignaturesIndices(registryCoordinator, uint32(block.number), BitmapUtils.bitmapToBytesArray(1 << numQuorums), nonSignerOperatorIds); + cheats.expectRevert("StakeRegistry.quorumExists: quorum does not exist"); + operatorStateRetriever.getCheckSignaturesIndices( + registryCoordinator, + uint32(block.number), + BitmapUtils.bitmapToBytesArray(1 << numQuorums), + nonSignerOperatorIds + ); } - function test_getCheckSignaturesIndices_revert_quorumNotCreatedAtReferenceBlockNumber() public { + function test_getCheckSignaturesIndices_revert_quorumNotCreatedAtReferenceBlockNumber() + public + { cheats.roll(registrationBlockNumber); _registerOperatorWithCoordinator(defaultOperator, 1, defaultPubKey); @@ -162,25 +222,30 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { bytes32[] memory nonSignerOperatorIds = new bytes32[](1); nonSignerOperatorIds[0] = defaultOperatorId; - 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}); cheats.prank(registryCoordinator.owner()); registryCoordinator.createQuorum(operatorSetParams, minimumStake, strategyParams); - cheats.expectRevert("StakeRegistry.getTotalStakeIndicesAtBlockNumber: quorum has no stake history at blockNumber"); - operatorStateRetriever.getCheckSignaturesIndices(registryCoordinator, registrationBlockNumber + 5, BitmapUtils.bitmapToBytesArray(1 << numQuorums), nonSignerOperatorIds); + cheats.expectRevert( + "StakeRegistry.getTotalStakeIndicesAtBlockNumber: quorum has no stake history at blockNumber" + ); + operatorStateRetriever.getCheckSignaturesIndices( + registryCoordinator, + registrationBlockNumber + 5, + BitmapUtils.bitmapToBytesArray(1 << numQuorums), + nonSignerOperatorIds + ); } function test_getCheckSignaturesIndices_returnsCorrect() public { @@ -195,7 +260,9 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { address otherOperator = _incrementAddress(defaultOperator, 1); BN254.G1Point memory otherPubKey = BN254.G1Point(1, 2); bytes32 otherOperatorId = BN254.hashG1Point(otherPubKey); - _registerOperatorWithCoordinator(otherOperator, quorumBitmapThree, otherPubKey, defaultStake -1); + _registerOperatorWithCoordinator( + otherOperator, quorumBitmapThree, otherPubKey, defaultStake - 1 + ); cheats.roll(registrationBlockNumber + 15); cheats.prank(defaultOperator); @@ -209,13 +276,21 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { registryCoordinator.deregisterOperator(BitmapUtils.bitmapToBytesArray(quorumBitmapTwo)); cheats.roll(registrationBlockNumber + 30); - _registerOperatorWithCoordinator(otherOperator, quorumBitmapTwo, otherPubKey, defaultStake - 2); + _registerOperatorWithCoordinator( + otherOperator, quorumBitmapTwo, otherPubKey, defaultStake - 2 + ); bytes32[] memory nonSignerOperatorIds = new bytes32[](2); nonSignerOperatorIds[0] = defaultOperatorId; nonSignerOperatorIds[1] = otherOperatorId; - OperatorStateRetriever.CheckSignaturesIndices memory checkSignaturesIndices = operatorStateRetriever.getCheckSignaturesIndices(registryCoordinator, uint32(block.number), BitmapUtils.bitmapToBytesArray(quorumBitmapThree), nonSignerOperatorIds); + OperatorStateRetriever.CheckSignaturesIndices memory checkSignaturesIndices = + operatorStateRetriever.getCheckSignaturesIndices( + registryCoordinator, + uint32(block.number), + BitmapUtils.bitmapToBytesArray(quorumBitmapThree), + nonSignerOperatorIds + ); // we're querying for 2 operators, so there should be 2 nonSignerQuorumBitmapIndices assertEq(checkSignaturesIndices.nonSignerQuorumBitmapIndices.length, 2); // the first operator (0) registered for quorum 1, (1) deregistered from quorum 1, and (2) registered for quorum 2 @@ -250,7 +325,12 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { nonSignerOperatorIds = new bytes32[](1); nonSignerOperatorIds[0] = otherOperatorId; // taking only the deregistration into account - checkSignaturesIndices = operatorStateRetriever.getCheckSignaturesIndices(registryCoordinator, registrationBlockNumber + 15, BitmapUtils.bitmapToBytesArray(quorumBitmapThree), nonSignerOperatorIds); + checkSignaturesIndices = operatorStateRetriever.getCheckSignaturesIndices( + registryCoordinator, + registrationBlockNumber + 15, + BitmapUtils.bitmapToBytesArray(quorumBitmapThree), + nonSignerOperatorIds + ); // we're querying for 1 operator, so there should be 1 nonSignerQuorumBitmapIndices assertEq(checkSignaturesIndices.nonSignerQuorumBitmapIndices.length, 1); // the second operator (0) registered for quorum 1 and 2 @@ -286,44 +366,47 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { uint256[][] memory expectedOperatorOverallIndices ) = _registerRandomOperators(pseudoRandomNumber); - for (uint i = 0; i < operatorMetadatas.length; i++) { + for (uint256 i = 0; i < operatorMetadatas.length; i++) { uint32 blockNumber = uint32(registrationBlockNumber + blocksBetweenRegistrations * i); uint256 gasBefore = gasleft(); // retrieve the ordered list of operators for each quorum along with their id and stake - (uint256 quorumBitmap, OperatorStateRetriever.Operator[][] memory operators) = - operatorStateRetriever.getOperatorState(registryCoordinator, operatorMetadatas[i].operatorId, blockNumber); + (uint256 quorumBitmap, OperatorStateRetriever.Operator[][] memory operators) = + operatorStateRetriever.getOperatorState( + registryCoordinator, operatorMetadatas[i].operatorId, blockNumber + ); uint256 gasAfter = gasleft(); emit log_named_uint("gasUsed", gasBefore - gasAfter); assertEq(operatorMetadatas[i].quorumBitmap, quorumBitmap); bytes memory quorumNumbers = BitmapUtils.bitmapToBytesArray(quorumBitmap); - + // assert that the operators returned are the expected ones _assertExpectedOperators( - quorumNumbers, - operators, - expectedOperatorOverallIndices, - operatorMetadatas + quorumNumbers, operators, expectedOperatorOverallIndices, operatorMetadatas ); } // choose a random operator to deregister uint256 operatorIndexToDeregister = pseudoRandomNumber % maxOperatorsToRegister; - bytes memory quorumNumbersToDeregister = BitmapUtils.bitmapToBytesArray(operatorMetadatas[operatorIndexToDeregister].quorumBitmap); + bytes memory quorumNumbersToDeregister = BitmapUtils.bitmapToBytesArray( + operatorMetadatas[operatorIndexToDeregister].quorumBitmap + ); - uint32 deregistrationBlockNumber = registrationBlockNumber + blocksBetweenRegistrations * (uint32(operatorMetadatas.length) + 1); + uint32 deregistrationBlockNumber = registrationBlockNumber + + blocksBetweenRegistrations * (uint32(operatorMetadatas.length) + 1); cheats.roll(deregistrationBlockNumber); cheats.prank(_incrementAddress(defaultOperator, operatorIndexToDeregister)); registryCoordinator.deregisterOperator(quorumNumbersToDeregister); // modify expectedOperatorOverallIndices by moving th operatorIdsToSwap to the index where the operatorIndexToDeregister was - for (uint i = 0; i < quorumNumbersToDeregister.length; i++) { + for (uint256 i = 0; i < quorumNumbersToDeregister.length; i++) { uint8 quorumNumber = uint8(quorumNumbersToDeregister[i]); // loop through indices till we find operatorIndexToDeregister, then move that last operator into that index - for (uint j = 0; j < expectedOperatorOverallIndices[quorumNumber].length; j++) { + for (uint256 j = 0; j < expectedOperatorOverallIndices[quorumNumber].length; j++) { if (expectedOperatorOverallIndices[quorumNumber][j] == operatorIndexToDeregister) { - expectedOperatorOverallIndices[quorumNumber][j] = expectedOperatorOverallIndices[quorumNumber][expectedOperatorOverallIndices[quorumNumber].length - 1]; + expectedOperatorOverallIndices[quorumNumber][j] = expectedOperatorOverallIndices[quorumNumber][expectedOperatorOverallIndices[quorumNumber] + .length - 1]; break; } } @@ -334,10 +417,12 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { for (uint8 i = 0; i < allQuorumNumbers.length; i++) { allQuorumNumbers[i] = bytes1(i); } - + _assertExpectedOperators( allQuorumNumbers, - operatorStateRetriever.getOperatorState(registryCoordinator, allQuorumNumbers, deregistrationBlockNumber), + operatorStateRetriever.getOperatorState( + registryCoordinator, allQuorumNumbers, deregistrationBlockNumber + ), expectedOperatorOverallIndices, operatorMetadatas ); @@ -349,7 +434,8 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { uint256[][] memory expectedOperatorOverallIndices ) = _registerRandomOperators(pseudoRandomNumber); - uint32 cumulativeBlockNumber = registrationBlockNumber + blocksBetweenRegistrations * uint32(operatorMetadatas.length); + uint32 cumulativeBlockNumber = + registrationBlockNumber + blocksBetweenRegistrations * uint32(operatorMetadatas.length); // get the quorum bitmap for which there is at least 1 operator uint256 allInclusiveQuorumBitmap = 0; @@ -357,28 +443,53 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { allInclusiveQuorumBitmap |= operatorMetadatas[i].quorumBitmap; } - bytes memory allInclusiveQuorumNumbers = BitmapUtils.bitmapToBytesArray(allInclusiveQuorumBitmap); + bytes memory allInclusiveQuorumNumbers = + BitmapUtils.bitmapToBytesArray(allInclusiveQuorumBitmap); bytes32[] memory nonSignerOperatorIds = new bytes32[](0); OperatorStateRetriever.CheckSignaturesIndices memory checkSignaturesIndices = - operatorStateRetriever.getCheckSignaturesIndices( - registryCoordinator, - cumulativeBlockNumber, - allInclusiveQuorumNumbers, - nonSignerOperatorIds - ); + operatorStateRetriever.getCheckSignaturesIndices( + registryCoordinator, + cumulativeBlockNumber, + allInclusiveQuorumNumbers, + nonSignerOperatorIds + ); - assertEq(checkSignaturesIndices.nonSignerQuorumBitmapIndices.length, 0, "nonSignerQuorumBitmapIndices should be empty if no nonsigners"); - assertEq(checkSignaturesIndices.quorumApkIndices.length, allInclusiveQuorumNumbers.length, "quorumApkIndices should be the number of quorums queried for"); - assertEq(checkSignaturesIndices.totalStakeIndices.length, allInclusiveQuorumNumbers.length, "totalStakeIndices should be the number of quorums queried for"); - assertEq(checkSignaturesIndices.nonSignerStakeIndices.length, allInclusiveQuorumNumbers.length, "nonSignerStakeIndices should be the number of quorums queried for"); + assertEq( + checkSignaturesIndices.nonSignerQuorumBitmapIndices.length, + 0, + "nonSignerQuorumBitmapIndices should be empty if no nonsigners" + ); + assertEq( + checkSignaturesIndices.quorumApkIndices.length, + allInclusiveQuorumNumbers.length, + "quorumApkIndices should be the number of quorums queried for" + ); + assertEq( + checkSignaturesIndices.totalStakeIndices.length, + allInclusiveQuorumNumbers.length, + "totalStakeIndices should be the number of quorums queried for" + ); + assertEq( + checkSignaturesIndices.nonSignerStakeIndices.length, + allInclusiveQuorumNumbers.length, + "nonSignerStakeIndices should be the number of quorums queried for" + ); // assert the indices are the number of registered operators for the quorum minus 1 for (uint8 i = 0; i < allInclusiveQuorumNumbers.length; i++) { uint8 quorumNumber = uint8(allInclusiveQuorumNumbers[i]); - assertEq(checkSignaturesIndices.quorumApkIndices[i], expectedOperatorOverallIndices[quorumNumber].length, "quorumApkIndex should be the number of registered operators for the quorum"); - assertEq(checkSignaturesIndices.totalStakeIndices[i], expectedOperatorOverallIndices[quorumNumber].length, "totalStakeIndex should be the number of registered operators for the quorum"); + assertEq( + checkSignaturesIndices.quorumApkIndices[i], + expectedOperatorOverallIndices[quorumNumber].length, + "quorumApkIndex should be the number of registered operators for the quorum" + ); + assertEq( + checkSignaturesIndices.totalStakeIndices[i], + expectedOperatorOverallIndices[quorumNumber].length, + "totalStakeIndex should be the number of registered operators for the quorum" + ); } } @@ -388,7 +499,8 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { uint256[][] memory expectedOperatorOverallIndices ) = _registerRandomOperators(pseudoRandomNumber); - uint32 cumulativeBlockNumber = registrationBlockNumber + blocksBetweenRegistrations * uint32(operatorMetadatas.length); + uint32 cumulativeBlockNumber = + registrationBlockNumber + blocksBetweenRegistrations * uint32(operatorMetadatas.length); // get the quorum bitmap for which there is at least 1 operator uint256 allInclusiveQuorumBitmap = 0; @@ -396,41 +508,78 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { allInclusiveQuorumBitmap |= operatorMetadatas[i].quorumBitmap; } - bytes memory allInclusiveQuorumNumbers = BitmapUtils.bitmapToBytesArray(allInclusiveQuorumBitmap); - - bytes32[] memory nonSignerOperatorIds = new bytes32[](pseudoRandomNumber % (operatorMetadatas.length - 1) + 1); - uint256 randomIndex = uint256(keccak256(abi.encodePacked("nonSignerOperatorIds", pseudoRandomNumber))) % operatorMetadatas.length; - for (uint i = 0; i < nonSignerOperatorIds.length; i++) { - nonSignerOperatorIds[i] = operatorMetadatas[(randomIndex + i) % operatorMetadatas.length].operatorId; + bytes memory allInclusiveQuorumNumbers = + BitmapUtils.bitmapToBytesArray(allInclusiveQuorumBitmap); + + bytes32[] memory nonSignerOperatorIds = + new bytes32[](pseudoRandomNumber % (operatorMetadatas.length - 1) + 1); + uint256 randomIndex = uint256( + keccak256(abi.encodePacked("nonSignerOperatorIds", pseudoRandomNumber)) + ) % operatorMetadatas.length; + for (uint256 i = 0; i < nonSignerOperatorIds.length; i++) { + nonSignerOperatorIds[i] = + operatorMetadatas[(randomIndex + i) % operatorMetadatas.length].operatorId; } OperatorStateRetriever.CheckSignaturesIndices memory checkSignaturesIndices = - operatorStateRetriever.getCheckSignaturesIndices( - registryCoordinator, - cumulativeBlockNumber, - allInclusiveQuorumNumbers, - nonSignerOperatorIds - ); + operatorStateRetriever.getCheckSignaturesIndices( + registryCoordinator, + cumulativeBlockNumber, + allInclusiveQuorumNumbers, + nonSignerOperatorIds + ); - assertEq(checkSignaturesIndices.nonSignerQuorumBitmapIndices.length, nonSignerOperatorIds.length, "nonSignerQuorumBitmapIndices should be the number of nonsigners"); - assertEq(checkSignaturesIndices.quorumApkIndices.length, allInclusiveQuorumNumbers.length, "quorumApkIndices should be the number of quorums queried for"); - assertEq(checkSignaturesIndices.totalStakeIndices.length, allInclusiveQuorumNumbers.length, "totalStakeIndices should be the number of quorums queried for"); - assertEq(checkSignaturesIndices.nonSignerStakeIndices.length, allInclusiveQuorumNumbers.length, "nonSignerStakeIndices should be the number of quorums queried for"); + assertEq( + checkSignaturesIndices.nonSignerQuorumBitmapIndices.length, + nonSignerOperatorIds.length, + "nonSignerQuorumBitmapIndices should be the number of nonsigners" + ); + assertEq( + checkSignaturesIndices.quorumApkIndices.length, + allInclusiveQuorumNumbers.length, + "quorumApkIndices should be the number of quorums queried for" + ); + assertEq( + checkSignaturesIndices.totalStakeIndices.length, + allInclusiveQuorumNumbers.length, + "totalStakeIndices should be the number of quorums queried for" + ); + assertEq( + checkSignaturesIndices.nonSignerStakeIndices.length, + allInclusiveQuorumNumbers.length, + "nonSignerStakeIndices should be the number of quorums queried for" + ); // assert the indices are the number of registered operators for the quorum minus 1 for (uint8 i = 0; i < allInclusiveQuorumNumbers.length; i++) { uint8 quorumNumber = uint8(allInclusiveQuorumNumbers[i]); - assertEq(checkSignaturesIndices.quorumApkIndices[i], expectedOperatorOverallIndices[quorumNumber].length, "quorumApkIndex should be the number of registered operators for the quorum"); - assertEq(checkSignaturesIndices.totalStakeIndices[i], expectedOperatorOverallIndices[quorumNumber].length, "totalStakeIndex should be the number of registered operators for the quorum"); + assertEq( + checkSignaturesIndices.quorumApkIndices[i], + expectedOperatorOverallIndices[quorumNumber].length, + "quorumApkIndex should be the number of registered operators for the quorum" + ); + assertEq( + checkSignaturesIndices.totalStakeIndices[i], + expectedOperatorOverallIndices[quorumNumber].length, + "totalStakeIndex should be the number of registered operators for the quorum" + ); } // assert the quorum bitmap and stake indices are zero because there have been no kicks or stake updates - for (uint i = 0; i < nonSignerOperatorIds.length; i++) { - assertEq(checkSignaturesIndices.nonSignerQuorumBitmapIndices[i], 0, "nonSignerQuorumBitmapIndices should be zero because there have been no kicks"); + for (uint256 i = 0; i < nonSignerOperatorIds.length; i++) { + assertEq( + checkSignaturesIndices.nonSignerQuorumBitmapIndices[i], + 0, + "nonSignerQuorumBitmapIndices should be zero because there have been no kicks" + ); } - for (uint i = 0; i < checkSignaturesIndices.nonSignerStakeIndices.length; i++) { - for (uint j = 0; j < checkSignaturesIndices.nonSignerStakeIndices[i].length; j++) { - assertEq(checkSignaturesIndices.nonSignerStakeIndices[i][j], 0, "nonSignerStakeIndices should be zero because there have been no stake updates past the first one"); + for (uint256 i = 0; i < checkSignaturesIndices.nonSignerStakeIndices.length; i++) { + for (uint256 j = 0; j < checkSignaturesIndices.nonSignerStakeIndices[i].length; j++) { + assertEq( + checkSignaturesIndices.nonSignerStakeIndices[i][j], + 0, + "nonSignerStakeIndices should be zero because there have been no stake updates past the first one" + ); } } } @@ -444,12 +593,16 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { address otherOperator = _incrementAddress(defaultOperator, 1); BN254.G1Point memory otherPubKey = BN254.G1Point(1, 2); bytes32 otherOperatorId = BN254.hashG1Point(otherPubKey); - _registerOperatorWithCoordinator(otherOperator, quorumBitmapThree, otherPubKey, defaultStake -1); + _registerOperatorWithCoordinator( + otherOperator, quorumBitmapThree, otherPubKey, defaultStake - 1 + ); bytes32[] memory operatorIds = new bytes32[](2); operatorIds[0] = defaultOperatorId; operatorIds[1] = otherOperatorId; - uint256[] memory quorumBitmaps = operatorStateRetriever.getQuorumBitmapsAtBlockNumber(registryCoordinator, operatorIds, uint32(block.number)); + uint256[] memory quorumBitmaps = operatorStateRetriever.getQuorumBitmapsAtBlockNumber( + registryCoordinator, operatorIds, uint32(block.number) + ); assertEq(quorumBitmaps.length, 2); assertEq(quorumBitmaps[0], quorumBitmapOne); @@ -463,11 +616,14 @@ contract OperatorStateRetrieverUnitTests is MockAVSDeployer { OperatorMetadata[] memory operatorMetadatas ) internal { // for each quorum - for (uint j = 0; j < quorumNumbers.length; j++) { + for (uint256 j = 0; j < quorumNumbers.length; j++) { // make sure the each operator id and stake is correct - for (uint k = 0; k < operators[j].length; k++) { + for (uint256 k = 0; k < operators[j].length; k++) { uint8 quorumNumber = uint8(quorumNumbers[j]); - assertEq(operators[j][k].operatorId, operatorMetadatas[expectedOperatorOverallIndices[quorumNumber][k]].operatorId); + assertEq( + operators[j][k].operatorId, + operatorMetadatas[expectedOperatorOverallIndices[quorumNumber][k]].operatorId + ); // using assertApprox to account for rounding errors assertApproxEqAbs( operators[j][k].stake, diff --git a/test/unit/StakeRegistryUnit.t.sol b/test/unit/StakeRegistryUnit.t.sol index bc9d46f6..ed53225c 100644 --- a/test/unit/StakeRegistryUnit.t.sol +++ b/test/unit/StakeRegistryUnit.t.sol @@ -38,7 +38,7 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { _; } - function setUp() virtual public { + function setUp() public virtual { // Deploy contracts but with 0 quorums initialized, will initializeQuorums afterwards _deployMockEigenLayerAndAVS(0); @@ -52,36 +52,35 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { ); stakeRegistryImplementation = new StakeRegistryHarness( - IRegistryCoordinator(address(registryCoordinator)), - delegationMock + IRegistryCoordinator(address(registryCoordinator)), delegationMock ); stakeRegistry = StakeRegistryHarness( address( new TransparentUpgradeableProxy( - address(stakeRegistryImplementation), - address(proxyAdmin), - "" + address(stakeRegistryImplementation), address(proxyAdmin), "" ) ) ); cheats.stopPrank(); // Initialize several quorums with varying minimum stakes - _initializeQuorum({ minimumStake: uint96(type(uint16).max) }); - _initializeQuorum({ minimumStake: uint96(type(uint24).max) }); - _initializeQuorum({ minimumStake: uint96(type(uint32).max) }); - _initializeQuorum({ minimumStake: uint96(type(uint64).max) }); + _initializeQuorum({minimumStake: uint96(type(uint16).max)}); + _initializeQuorum({minimumStake: uint96(type(uint24).max)}); + _initializeQuorum({minimumStake: uint96(type(uint32).max)}); + _initializeQuorum({minimumStake: uint96(type(uint64).max)}); - _initializeQuorum({ minimumStake: uint96(type(uint16).max) + 1 }); - _initializeQuorum({ minimumStake: uint96(type(uint24).max) + 1 }); - _initializeQuorum({ minimumStake: uint96(type(uint32).max) + 1 }); - _initializeQuorum({ minimumStake: uint96(type(uint64).max) + 1 }); + _initializeQuorum({minimumStake: uint96(type(uint16).max) + 1}); + _initializeQuorum({minimumStake: uint96(type(uint24).max) + 1}); + _initializeQuorum({minimumStake: uint96(type(uint32).max) + 1}); + _initializeQuorum({minimumStake: uint96(type(uint64).max) + 1}); } - /******************************************************************************* - initializers - *******************************************************************************/ + /** + * + * initializers + * + */ /** * @dev Initialize a new quorum with `minimumStake` @@ -91,7 +90,7 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { uint8 quorumNumber = nextQuorum; IStakeRegistry.StrategyParams[] memory strategyParams = - new IStakeRegistry.StrategyParams[](1); + new IStakeRegistry.StrategyParams[](1); strategyParams[0] = IStakeRegistry.StrategyParams( IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(quorumNumber)))))), uint96(WEIGHTING_DIVISOR) @@ -107,15 +106,16 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { initializedQuorumBytes = initializedQuorumBitmap.bitmapToBytesArray(); } - /** + /** * @dev Initialize a new quorum with `minimumStake` and `numStrats` - * Create `numStrats` dummy strategies with multiplier of 1 for each. + * Create `numStrats` dummy strategies with multiplier of 1 for each. * Returns quorumNumber that was just initialized */ function _initializeQuorum(uint96 minimumStake, uint256 numStrats) internal returns (uint8) { uint8 quorumNumber = nextQuorum; - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](numStrats); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](numStrats); for (uint256 i = 0; i < strategyParams.length; i++) { strategyParams[i] = IStakeRegistry.StrategyParams( IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(quorumNumber, i)))))), @@ -145,10 +145,11 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { return (operator, operatorId); } - /******************************************************************************* - test setup methods - *******************************************************************************/ - + /** + * + * test setup methods + * + */ struct RegisterSetup { address operator; bytes32 operatorId; @@ -162,20 +163,25 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { /// @dev Utility function set up a new operator to be registered for some quorums /// The operator's weight is set to the quorum's minimum, plus fuzzy_addtlStake (overflows are skipped) /// This function guarantees at least one quorum, and any quorums returned are initialized - function _fuzz_setupRegisterOperator(uint192 fuzzy_Bitmap, uint16 fuzzy_addtlStake) internal returns (RegisterSetup memory) { + function _fuzz_setupRegisterOperator( + uint192 fuzzy_Bitmap, + uint16 fuzzy_addtlStake + ) internal returns (RegisterSetup memory) { // Select an unused operator to register (address operator, bytes32 operatorId) = _selectNewOperator(); - + // Pick quorums to register for and get each quorum's minimum stake - ( , bytes memory quorumNumbers) = _fuzz_getQuorums(fuzzy_Bitmap); + (, bytes memory quorumNumbers) = _fuzz_getQuorums(fuzzy_Bitmap); uint96[] memory minimumStakes = _getMinimumStakes(quorumNumbers); // For each quorum, set the operator's weight as the minimum + addtlStake uint96[] memory operatorWeights = new uint96[](quorumNumbers.length); - for (uint i = 0; i < quorumNumbers.length; i++) { + for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); - unchecked { operatorWeights[i] = minimumStakes[i] + fuzzy_addtlStake; } + unchecked { + operatorWeights[i] = minimumStakes[i] + fuzzy_addtlStake; + } cheats.assume(operatorWeights[i] >= minimumStakes[i]); cheats.assume(operatorWeights[i] >= fuzzy_addtlStake); @@ -183,11 +189,13 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { } /// Get starting state - IStakeRegistry.StakeUpdate[] memory prevOperatorStakes = _getLatestStakeUpdates(operatorId, quorumNumbers); - IStakeRegistry.StakeUpdate[] memory prevTotalStakes = _getLatestTotalStakeUpdates(quorumNumbers); + IStakeRegistry.StakeUpdate[] memory prevOperatorStakes = + _getLatestStakeUpdates(operatorId, quorumNumbers); + IStakeRegistry.StakeUpdate[] memory prevTotalStakes = + _getLatestTotalStakeUpdates(quorumNumbers); // Ensure that the operator has not previously registered - for (uint i = 0; i < quorumNumbers.length; i++) { + for (uint256 i = 0; i < quorumNumbers.length; i++) { assertTrue(prevOperatorStakes[i].updateBlockNumber == 0, "operator already registered"); assertTrue(prevOperatorStakes[i].stake == 0, "operator already has stake"); } @@ -203,10 +211,14 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { }); } - function _fuzz_setupRegisterOperators(uint192 fuzzy_Bitmap, uint16 fuzzy_addtlStake, uint numOperators) internal returns (RegisterSetup[] memory) { + function _fuzz_setupRegisterOperators( + uint192 fuzzy_Bitmap, + uint16 fuzzy_addtlStake, + uint256 numOperators + ) internal returns (RegisterSetup[] memory) { RegisterSetup[] memory setups = new RegisterSetup[](numOperators); - for (uint i = 0; i < numOperators; i++) { + for (uint256 i = 0; i < numOperators; i++) { setups[i] = _fuzz_setupRegisterOperator(fuzzy_Bitmap, fuzzy_addtlStake); } @@ -229,21 +241,27 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { /// The operator's weight is set to the quorum's minimum, plus fuzzy_addtlStake (overflows are skipped) /// This function guarantees at least one quorum, and any quorums returned are initialized function _fuzz_setupDeregisterOperator( - uint192 registeredFor, - uint192 fuzzy_toRemove, + uint192 registeredFor, + uint192 fuzzy_toRemove, uint16 fuzzy_addtlStake ) internal returns (DeregisterSetup memory) { - RegisterSetup memory registerSetup = _fuzz_setupRegisterOperator(registeredFor, fuzzy_addtlStake); + RegisterSetup memory registerSetup = + _fuzz_setupRegisterOperator(registeredFor, fuzzy_addtlStake); // registerOperator cheats.prank(address(registryCoordinator)); - stakeRegistry.registerOperator(registerSetup.operator, registerSetup.operatorId, registerSetup.quorumNumbers); + stakeRegistry.registerOperator( + registerSetup.operator, registerSetup.operatorId, registerSetup.quorumNumbers + ); // Get state after registering: - IStakeRegistry.StakeUpdate[] memory operatorStakes = _getLatestStakeUpdates(registerSetup.operatorId, registerSetup.quorumNumbers); - IStakeRegistry.StakeUpdate[] memory totalStakes = _getLatestTotalStakeUpdates(registerSetup.quorumNumbers); - - (uint192 quorumsToRemoveBitmap, bytes memory quorumsToRemove) = _fuzz_getQuorums(fuzzy_toRemove); + IStakeRegistry.StakeUpdate[] memory operatorStakes = + _getLatestStakeUpdates(registerSetup.operatorId, registerSetup.quorumNumbers); + IStakeRegistry.StakeUpdate[] memory totalStakes = + _getLatestTotalStakeUpdates(registerSetup.quorumNumbers); + + (uint192 quorumsToRemoveBitmap, bytes memory quorumsToRemove) = + _fuzz_getQuorums(fuzzy_toRemove); return DeregisterSetup({ operator: registerSetup.operator, @@ -257,15 +275,16 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { } function _fuzz_setupDeregisterOperators( - uint192 registeredFor, - uint192 fuzzy_toRemove, - uint16 fuzzy_addtlStake, - uint numOperators + uint192 registeredFor, + uint192 fuzzy_toRemove, + uint16 fuzzy_addtlStake, + uint256 numOperators ) internal returns (DeregisterSetup[] memory) { DeregisterSetup[] memory setups = new DeregisterSetup[](numOperators); - for (uint i = 0; i < numOperators; i++) { - setups[i] = _fuzz_setupDeregisterOperator(registeredFor, fuzzy_toRemove, fuzzy_addtlStake); + for (uint256 i = 0; i < numOperators; i++) { + setups[i] = + _fuzz_setupDeregisterOperator(registeredFor, fuzzy_toRemove, fuzzy_addtlStake); } return setups; @@ -286,37 +305,52 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { /// After registering, and before returning, `fuzzy_Delta` is applied to the operator's weight /// to place the operator's weight above or below the minimum stake. (or unchanged!) /// The next time `updateOperatorStake` is called, this new weight will be used. - function _fuzz_setupUpdateOperatorStake(uint192 registeredFor, int8 fuzzy_Delta) internal returns (UpdateSetup memory) { + function _fuzz_setupUpdateOperatorStake( + uint192 registeredFor, + int8 fuzzy_Delta + ) internal returns (UpdateSetup memory) { RegisterSetup memory registerSetup = _fuzz_setupRegisterOperator(registeredFor, 0); // registerOperator cheats.prank(address(registryCoordinator)); - stakeRegistry.registerOperator(registerSetup.operator, registerSetup.operatorId, registerSetup.quorumNumbers); + stakeRegistry.registerOperator( + registerSetup.operator, registerSetup.operatorId, registerSetup.quorumNumbers + ); uint96[] memory minimumStakes = _getMinimumStakes(registerSetup.quorumNumbers); uint96[] memory endingWeights = new uint96[](minimumStakes.length); - for (uint i = 0; i < minimumStakes.length; i++) { + for (uint256 i = 0; i < minimumStakes.length; i++) { uint8 quorumNumber = uint8(registerSetup.quorumNumbers[i]); endingWeights[i] = _applyDelta(minimumStakes[i], int256(fuzzy_Delta)); // Sanity-check setup: if (fuzzy_Delta > 0) { - assertGt(endingWeights[i], minimumStakes[i], "_fuzz_setupUpdateOperatorStake: overflow during setup"); + assertGt( + endingWeights[i], + minimumStakes[i], + "_fuzz_setupUpdateOperatorStake: overflow during setup" + ); } else if (fuzzy_Delta < 0) { - assertLt(endingWeights[i], minimumStakes[i], "_fuzz_setupUpdateOperatorStake: underflow during setup"); + assertLt( + endingWeights[i], + minimumStakes[i], + "_fuzz_setupUpdateOperatorStake: underflow during setup" + ); } else { - assertEq(endingWeights[i], minimumStakes[i], "_fuzz_setupUpdateOperatorStake: invalid delta during setup"); + assertEq( + endingWeights[i], + minimumStakes[i], + "_fuzz_setupUpdateOperatorStake: invalid delta during setup" + ); } // Set operator weights. The next time we call `updateOperatorStake`, these new weights will be used _setOperatorWeight(registerSetup.operator, quorumNumber, endingWeights[i]); } - uint96 stakeDeltaAbs = - fuzzy_Delta < 0 ? - uint96(-int96(fuzzy_Delta)) : - uint96(int96(fuzzy_Delta)); + uint96 stakeDeltaAbs = + fuzzy_Delta < 0 ? uint96(-int96(fuzzy_Delta)) : uint96(int96(fuzzy_Delta)); return UpdateSetup({ operator: registerSetup.operator, @@ -328,19 +362,25 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { }); } - function _fuzz_setupUpdateOperatorStakes(uint8 numOperators, uint192 registeredFor, int8 fuzzy_Delta) internal returns (UpdateSetup[] memory) { + function _fuzz_setupUpdateOperatorStakes( + uint8 numOperators, + uint192 registeredFor, + int8 fuzzy_Delta + ) internal returns (UpdateSetup[] memory) { UpdateSetup[] memory setups = new UpdateSetup[](numOperators); - for (uint i = 0; i < numOperators; i++) { + for (uint256 i = 0; i < numOperators; i++) { setups[i] = _fuzz_setupUpdateOperatorStake(registeredFor, fuzzy_Delta); } return setups; } - /******************************************************************************* - helpful getters - *******************************************************************************/ + /** + * + * helpful getters + * + */ /// @notice Given a fuzzed bitmap input, returns a bitmap and array of quorum numbers /// that are guaranteed to be initialized. @@ -355,7 +395,7 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { /// @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) { - uint length = _randUint({ rand: rand, min: 1, max: initializedQuorumBytes.length + 1 }); + uint256 length = _randUint({rand: rand, min: 1, max: initializedQuorumBytes.length + 1}); bytes memory invalidQuorums = new bytes(length); // Create an invalid quorum number by incrementing the last initialized quorum @@ -364,7 +404,9 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { // Select real quorums up to the length, then insert an invalid quorum for (uint8 quorum = 0; quorum < length - 1; quorum++) { // sanity check test setup - assertTrue(initializedQuorumBitmap.isSet(quorum), "_fuzz_getInvalidQuorums: invalid quorum"); + assertTrue( + initializedQuorumBitmap.isSet(quorum), "_fuzz_getInvalidQuorums: invalid quorum" + ); invalidQuorums[quorum] = bytes1(quorum); } @@ -374,21 +416,24 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { /// @notice Returns true iff two StakeUpdates are identical function _isUnchanged( - IStakeRegistry.StakeUpdate memory prev, + IStakeRegistry.StakeUpdate memory prev, IStakeRegistry.StakeUpdate memory cur ) internal pure returns (bool) { return ( - prev.stake == cur.stake && - prev.updateBlockNumber == cur.updateBlockNumber && - prev.nextUpdateBlockNumber == cur.nextUpdateBlockNumber + prev.stake == cur.stake && prev.updateBlockNumber == cur.updateBlockNumber + && prev.nextUpdateBlockNumber == cur.nextUpdateBlockNumber ); } /// @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 (uint i = 0; i < quorumNumbers.length; i++) { + + for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); minimumStakes[i] = stakeRegistry.minimumStakeForQuorum(quorumNumber); } @@ -398,13 +443,13 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { /// @dev Return the most recent stake update history entries for an operator function _getLatestStakeUpdates( - bytes32 operatorId, + bytes32 operatorId, bytes memory quorumNumbers ) internal view returns (IStakeRegistry.StakeUpdate[] memory) { - IStakeRegistry.StakeUpdate[] memory stakeUpdates = + IStakeRegistry.StakeUpdate[] memory stakeUpdates = new IStakeRegistry.StakeUpdate[](quorumNumbers.length); - - for (uint i = 0; i < quorumNumbers.length; i++) { + + for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); stakeUpdates[i] = stakeRegistry.getLatestStakeUpdate(operatorId, quorumNumber); } @@ -413,17 +458,20 @@ 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) { - IStakeRegistry.StakeUpdate[] memory stakeUpdates = + function _getLatestTotalStakeUpdates(bytes memory quorumNumbers) + internal + view + returns (IStakeRegistry.StakeUpdate[] memory) + { + IStakeRegistry.StakeUpdate[] memory stakeUpdates = new IStakeRegistry.StakeUpdate[](quorumNumbers.length); - - for (uint i = 0; i < quorumNumbers.length; i++) { + + for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); - uint historyLength = stakeRegistry.getTotalStakeHistoryLength(quorumNumber); - stakeUpdates[i] = stakeRegistry.getTotalStakeUpdateAtIndex(quorumNumber, historyLength - 1); + uint256 historyLength = stakeRegistry.getTotalStakeHistoryLength(quorumNumber); + stakeUpdates[i] = + stakeRegistry.getTotalStakeUpdateAtIndex(quorumNumber, historyLength - 1); } return stakeUpdates; @@ -439,16 +487,19 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); - operatorStakeHistoryLengths[i] = stakeRegistry.getStakeHistoryLength(operatorId, quorumNumber); + operatorStakeHistoryLengths[i] = + stakeRegistry.getStakeHistoryLength(operatorId, quorumNumber); } return operatorStakeHistoryLengths; } /// @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++) { @@ -461,30 +512,24 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { } function _calculateDelta(uint96 prev, uint96 cur) internal view returns (int256) { - return stakeRegistry.calculateDelta({ - prev: prev, - cur: cur - }); + return stakeRegistry.calculateDelta({prev: prev, cur: cur}); } function _applyDelta(uint96 value, int256 delta) internal view returns (uint96) { - return stakeRegistry.applyDelta({ - value: value, - delta: delta - }); + return stakeRegistry.applyDelta({value: value, delta: delta}); } /// @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; @@ -492,8 +537,8 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { // 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) { @@ -506,9 +551,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) { uint256 l = arr.length; - for(uint256 i = 0; i < l; i++) { - for(uint256 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]) { uint256 temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; @@ -521,17 +566,19 @@ contract StakeRegistryUnitTests is MockAVSDeployer, IStakeRegistryEvents { /// @notice Tests for any nonstandard/permissioned methods contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { - - /******************************************************************************* - initializeQuorum - *******************************************************************************/ - + /** + * + * initializeQuorum + * + */ function testFuzz_initializeQuorum_Revert_WhenNotRegistryCoordinator( uint8 quorumNumber, uint96 minimumStake, IStakeRegistry.StrategyParams[] memory strategyParams ) public { - cheats.expectRevert("StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator"); + cheats.expectRevert( + "StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator" + ); stakeRegistry.initializeQuorum(quorumNumber, minimumStake, strategyParams); } @@ -550,7 +597,8 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint96 minimumStake ) public { cheats.assume(quorumNumber >= nextQuorum); - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](0); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](0); cheats.expectRevert("StakeRegistry._addStrategyParams: no strategies provided"); cheats.prank(address(registryCoordinator)); stakeRegistry.initializeQuorum(quorumNumber, minimumStake, strategyParams); @@ -558,8 +606,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { strategyParams = new IStakeRegistry.StrategyParams[](MAX_WEIGHING_FUNCTION_LENGTH + 1); for (uint256 i = 0; i < strategyParams.length; i++) { strategyParams[i] = IStakeRegistry.StrategyParams( - IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(i)))))), - uint96(1) + IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(i)))))), uint96(1) ); } cheats.expectRevert("StakeRegistry._addStrategyParams: exceed MAX_WEIGHING_FUNCTION_LENGTH"); @@ -569,7 +616,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { /** * @dev Initializes a quorum with StrategyParams with fuzzed multipliers inputs and corresponding - * strategy addresses. + * strategy addresses. */ function testFuzz_initializeQuorum( uint8 quorumNumber, @@ -578,41 +625,63 @@ 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); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](multipliers.length); for (uint256 i = 0; i < strategyParams.length; i++) { cheats.assume(multipliers[i] > 0); strategyParams[i] = IStakeRegistry.StrategyParams( - IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(i)))))), - multipliers[i] + IStrategy(address(uint160(uint256(keccak256(abi.encodePacked(i)))))), multipliers[i] ); } quorumNumber = nextQuorum; cheats.prank(address(registryCoordinator)); stakeRegistry.initializeQuorum(quorumNumber, minimumStake, strategyParams); - IStakeRegistry.StakeUpdate memory initialStakeUpdate = stakeRegistry.getTotalStakeUpdateAtIndex(quorumNumber, 0); - assertEq(stakeRegistry.minimumStakeForQuorum(quorumNumber), minimumStake, "invalid minimum stake"); - assertEq(stakeRegistry.getTotalStakeHistoryLength(quorumNumber), 1, "invalid total stake history length"); + IStakeRegistry.StakeUpdate memory initialStakeUpdate = + stakeRegistry.getTotalStakeUpdateAtIndex(quorumNumber, 0); + assertEq( + stakeRegistry.minimumStakeForQuorum(quorumNumber), minimumStake, "invalid minimum stake" + ); + assertEq( + stakeRegistry.getTotalStakeHistoryLength(quorumNumber), + 1, + "invalid total stake history length" + ); assertEq(initialStakeUpdate.stake, 0, "invalid stake update"); - assertEq(initialStakeUpdate.updateBlockNumber, uint32(block.number), "invalid updateBlockNumber stake update"); - assertEq(initialStakeUpdate.nextUpdateBlockNumber, 0, "invalid nextUpdateBlockNumber stake update"); - assertEq(stakeRegistry.strategyParamsLength(quorumNumber), strategyParams.length, "invalid strategy params length"); + assertEq( + initialStakeUpdate.updateBlockNumber, + uint32(block.number), + "invalid updateBlockNumber stake update" + ); + assertEq( + initialStakeUpdate.nextUpdateBlockNumber, + 0, + "invalid nextUpdateBlockNumber stake update" + ); + assertEq( + stakeRegistry.strategyParamsLength(quorumNumber), + strategyParams.length, + "invalid strategy params length" + ); for (uint256 i = 0; i < strategyParams.length; i++) { - (IStrategy strategy , uint96 multiplier) = stakeRegistry.strategyParams(quorumNumber, i); + (IStrategy strategy, uint96 multiplier) = stakeRegistry.strategyParams(quorumNumber, i); assertEq(address(strategy), address(strategyParams[i].strategy), "invalid strategy"); assertEq(multiplier, strategyParams[i].multiplier, "invalid multiplier"); } } - /******************************************************************************* - setMinimumStakeForQuorum - *******************************************************************************/ - + /** + * + * setMinimumStakeForQuorum + * + */ function testFuzz_setMinimumStakeForQuorum_Revert_WhenNotRegistryCoordinatorOwner( uint8 quorumNumber, uint96 minimumStakeForQuorum ) public fuzzOnlyInitializedQuorums(quorumNumber) { - cheats.expectRevert("StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator"); + cheats.expectRevert( + "StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator" + ); stakeRegistry.setMinimumStakeForQuorum(quorumNumber, minimumStakeForQuorum); } @@ -626,7 +695,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { cheats.prank(registryCoordinatorOwner); stakeRegistry.setMinimumStakeForQuorum(quorumNumber, minimumStakeForQuorum); } - + /// @dev Fuzzes initialized quorum numbers and minimum stakes to set to function testFuzz_setMinimumStakeForQuorum( uint8 quorumNumber, @@ -634,18 +703,25 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { ) public fuzzOnlyInitializedQuorums(quorumNumber) { cheats.prank(registryCoordinatorOwner); stakeRegistry.setMinimumStakeForQuorum(quorumNumber, minimumStakeForQuorum); - assertEq(stakeRegistry.minimumStakeForQuorum(quorumNumber), minimumStakeForQuorum, "invalid minimum stake"); + assertEq( + stakeRegistry.minimumStakeForQuorum(quorumNumber), + minimumStakeForQuorum, + "invalid minimum stake" + ); } - /******************************************************************************* - addStrategies - *******************************************************************************/ - + /** + * + * addStrategies + * + */ function testFuzz_addStrategies_Revert_WhenNotRegistryCoordinatorOwner( uint8 quorumNumber, IStakeRegistry.StrategyParams[] memory strategyParams ) public fuzzOnlyInitializedQuorums(quorumNumber) { - cheats.expectRevert("StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator"); + cheats.expectRevert( + "StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator" + ); stakeRegistry.addStrategies(quorumNumber, strategyParams); } @@ -663,16 +739,12 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { function test_addStrategies_Revert_WhenDuplicateStrategies() public { uint8 quorumNumber = _initializeQuorum(uint96(type(uint16).max), 1); - 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) - ); + 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)); cheats.expectRevert("StakeRegistry._addStrategyParams: cannot add same strategy 2x"); cheats.prank(registryCoordinatorOwner); @@ -682,14 +754,15 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { function test_addStrategies_Revert_WhenZeroWeight() public { uint8 quorumNumber = _initializeQuorum(uint96(type(uint16).max), 1); - 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 - ); + 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); - cheats.expectRevert("StakeRegistry._addStrategyParams: cannot add strategy with zero weight"); + cheats.expectRevert( + "StakeRegistry._addStrategyParams: cannot add strategy with zero weight" + ); cheats.prank(registryCoordinatorOwner); stakeRegistry.addStrategies(quorumNumber, strategyParams); } @@ -704,18 +777,19 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { ) public fuzzOnlyInitializedQuorums(quorumNumber) { uint256 currNumStrategies = stakeRegistry.strategyParamsLength(quorumNumber); // Assume nonzero multipliers, and total added strategies length is less than MAX_WEIGHING_FUNCTION_LENGTH - cheats.assume(0 < multipliers.length && multipliers.length <= MAX_WEIGHING_FUNCTION_LENGTH - currNumStrategies); + cheats.assume( + 0 < multipliers.length + && multipliers.length <= MAX_WEIGHING_FUNCTION_LENGTH - currNumStrategies + ); for (uint256 i = 0; i < multipliers.length; i++) { cheats.assume(multipliers[i] > 0); } // Expected events emitted - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](multipliers.length); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.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] = IStakeRegistry.StrategyParams(strat, multipliers[i]); cheats.expectEmit(true, true, true, true, address(stakeRegistry)); emit StrategyAddedToQuorum(quorumNumber, strat); @@ -726,22 +800,31 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { // addStrategies() call and expected assertions cheats.prank(registryCoordinatorOwner); stakeRegistry.addStrategies(quorumNumber, strategyParams); - assertEq(stakeRegistry.strategyParamsLength(quorumNumber), strategyParams.length + 1, "invalid strategy params length"); + assertEq( + stakeRegistry.strategyParamsLength(quorumNumber), + strategyParams.length + 1, + "invalid strategy params length" + ); for (uint256 i = 0; i < strategyParams.length; i++) { - (IStrategy strategy , uint96 multiplier) = stakeRegistry.strategyParams(quorumNumber, i + 1); + (IStrategy strategy, uint96 multiplier) = + stakeRegistry.strategyParams(quorumNumber, i + 1); assertEq(address(strategy), address(strategyParams[i].strategy), "invalid strategy"); assertEq(multiplier, strategyParams[i].multiplier, "invalid multiplier"); } } - /******************************************************************************* - removeStrategies - *******************************************************************************/ + /** + * + * removeStrategies + * + */ function testFuzz_removeStrategies_Revert_WhenNotRegistryCoordinatorOwner( uint8 quorumNumber, uint256[] memory indicesToRemove ) public fuzzOnlyInitializedQuorums(quorumNumber) { - cheats.expectRevert("StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator"); + cheats.expectRevert( + "StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator" + ); stakeRegistry.removeStrategies(quorumNumber, indicesToRemove); } @@ -802,7 +885,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { // Create array of indicesToRemove, sort desc, and assume no duplicates uint256[] memory indicesToRemove = new uint256[](numStrategiesToRemove); for (uint256 i = 0; i < numStrategiesToRemove; i++) { - indicesToRemove[i] = _randUint({ rand: bytes32(i), min: 0, max: numStrategiesToAdd - 1 }); + indicesToRemove[i] = _randUint({rand: bytes32(i), min: 0, max: numStrategiesToAdd - 1}); } indicesToRemove = _sortArrayDesc(indicesToRemove); uint256 prevIndex = indicesToRemove[0]; @@ -815,7 +898,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { // Expected events emitted for (uint256 i = 0; i < indicesToRemove.length; i++) { - (IStrategy strategy, ) = stakeRegistry.strategyParams(quorumNumber, indicesToRemove[i]); + (IStrategy strategy,) = stakeRegistry.strategyParams(quorumNumber, indicesToRemove[i]); cheats.expectEmit(true, true, true, true, address(stakeRegistry)); emit StrategyRemovedFromQuorum(quorumNumber, strategy); cheats.expectEmit(true, true, true, true, address(stakeRegistry)); @@ -832,16 +915,20 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { ); } - /******************************************************************************* - modifyStrategyParams - *******************************************************************************/ + /** + * + * modifyStrategyParams + * + */ function testFuzz_modifyStrategyParams_Revert_WhenNotRegistryCoordinatorOwner( uint8 quorumNumber, uint256[] calldata strategyIndices, uint96[] calldata newMultipliers ) public fuzzOnlyInitializedQuorums(quorumNumber) { - cheats.expectRevert("StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator"); - stakeRegistry.modifyStrategyParams(quorumNumber, strategyIndices, newMultipliers); + cheats.expectRevert( + "StakeRegistry.onlyCoordinatorOwner: caller is not the owner of the registryCoordinator" + ); + stakeRegistry.modifyStrategyParams(quorumNumber, strategyIndices, newMultipliers); } function testFuzz_modifyStrategyParams_Revert_WhenInvalidQuorum( @@ -855,10 +942,11 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { cheats.prank(registryCoordinatorOwner); 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("StakeRegistry.modifyStrategyParams: no strategy indices provided"); @@ -875,7 +963,7 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { cheats.assume(strategyIndices.length > 0); cheats.expectRevert("StakeRegistry.modifyStrategyParams: input length mismatch"); cheats.prank(registryCoordinatorOwner); - stakeRegistry.modifyStrategyParams(quorumNumber, strategyIndices, newMultipliers); + stakeRegistry.modifyStrategyParams(quorumNumber, strategyIndices, newMultipliers); } /** @@ -893,8 +981,8 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { uint96[] memory newMultipliers = new uint96[](numStrategiesToModify); // create array of indices to modify, assume no duplicates, and create array of multipliers for each index for (uint256 i = 0; i < numStrategiesToModify; i++) { - strategyIndices[i] = _randUint({ rand: bytes32(i), min: 0, max: numStrategiesToAdd - 1 }); - newMultipliers[i] = uint96(_randUint({ rand: bytes32(i), min: 1, max: type(uint96).max })); + strategyIndices[i] = _randUint({rand: bytes32(i), min: 0, max: numStrategiesToAdd - 1}); + newMultipliers[i] = uint96(_randUint({rand: bytes32(i), min: 1, max: type(uint96).max})); // ensure no duplicate indices if (i == 0) { prevIndex = strategyIndices[0]; @@ -905,9 +993,9 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { } // Expected events emitted - uint8 quorumNumber = _initializeQuorum(0 /* minimumStake */, numStrategiesToAdd); + uint8 quorumNumber = _initializeQuorum(0, /* minimumStake */ numStrategiesToAdd); for (uint256 i = 0; i < strategyIndices.length; i++) { - (IStrategy strategy, ) = stakeRegistry.strategyParams(quorumNumber, strategyIndices[i]); + (IStrategy strategy,) = stakeRegistry.strategyParams(quorumNumber, strategyIndices[i]); cheats.expectEmit(true, true, true, true, address(stakeRegistry)); emit StrategyMultiplierUpdated(quorumNumber, strategy, newMultipliers[i]); } @@ -924,15 +1012,17 @@ contract StakeRegistryUnitTests_Config is StakeRegistryUnitTests { /// @notice Tests for StakeRegistry.registerOperator contract StakeRegistryUnitTests_Register is StakeRegistryUnitTests { - - /******************************************************************************* - registerOperator - *******************************************************************************/ - + /** + * + * registerOperator + * + */ function test_registerOperator_Revert_WhenNotRegistryCoordinator() public { (address operator, bytes32 operatorId) = _selectNewOperator(); - cheats.expectRevert("StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator"); + cheats.expectRevert( + "StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator" + ); stakeRegistry.registerOperator(operator, operatorId, initializedQuorumBytes); } @@ -942,28 +1032,31 @@ 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.registerOperator: quorum does not exist"); + cheats.expectRevert("StakeRegistry.quorumExists: quorum does not exist"); cheats.prank(address(registryCoordinator)); stakeRegistry.registerOperator(setup.operator, setup.operatorId, invalidQuorums); } /// @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); // Set the operator's weight to the minimum stake for each quorum // ... except the failing quorum, which gets minimum stake - 1 - for (uint i = 0; i < quorumNumbers.length; i++) { + for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); uint96 operatorWeight; if (quorumNumber == failingQuorum) { - unchecked { operatorWeight = minimumStakes[i] - 1; } + unchecked { + operatorWeight = minimumStakes[i] - 1; + } assertTrue(operatorWeight < minimumStakes[i], "minimum stake underflow"); } else { operatorWeight = minimumStakes[i]; @@ -973,7 +1066,9 @@ contract StakeRegistryUnitTests_Register is StakeRegistryUnitTests { } // Attempt to register - cheats.expectRevert("StakeRegistry.registerOperator: Operator does not meet minimum stake requirement for quorum"); + cheats.expectRevert( + "StakeRegistry.registerOperator: Operator does not meet minimum stake requirement for quorum" + ); cheats.prank(address(registryCoordinator)); stakeRegistry.registerOperator(operator, operatorId, quorumNumbers); } @@ -993,31 +1088,57 @@ contract StakeRegistryUnitTests_Register is StakeRegistryUnitTests { /// registerOperator cheats.prank(address(registryCoordinator)); - (uint96[] memory resultingStakes, uint96[] memory totalStakes) = + (uint96[] memory resultingStakes, uint96[] memory totalStakes) = stakeRegistry.registerOperator(setup.operator, setup.operatorId, setup.quorumNumbers); /// Read ending state - IStakeRegistry.StakeUpdate[] memory newOperatorStakes = _getLatestStakeUpdates(setup.operatorId, setup.quorumNumbers); - IStakeRegistry.StakeUpdate[] memory newTotalStakes = _getLatestTotalStakeUpdates(setup.quorumNumbers); - uint256[] memory operatorStakeHistoryLengths = _getStakeHistoryLengths(setup.operatorId, setup.quorumNumbers); + IStakeRegistry.StakeUpdate[] memory newOperatorStakes = + _getLatestStakeUpdates(setup.operatorId, setup.quorumNumbers); + IStakeRegistry.StakeUpdate[] memory newTotalStakes = + _getLatestTotalStakeUpdates(setup.quorumNumbers); + uint256[] memory operatorStakeHistoryLengths = + _getStakeHistoryLengths(setup.operatorId, setup.quorumNumbers); /// Check results - assertTrue(resultingStakes.length == setup.quorumNumbers.length, "invalid return length for operator stakes"); - assertTrue(totalStakes.length == setup.quorumNumbers.length, "invalid return length for total stakes"); + assertTrue( + resultingStakes.length == setup.quorumNumbers.length, + "invalid return length for operator stakes" + ); + assertTrue( + totalStakes.length == setup.quorumNumbers.length, + "invalid return length for total stakes" + ); - for (uint i = 0; i < setup.quorumNumbers.length; i++) { + for (uint256 i = 0; i < setup.quorumNumbers.length; i++) { IStakeRegistry.StakeUpdate memory newOperatorStake = newOperatorStakes[i]; IStakeRegistry.StakeUpdate memory newTotalStake = newTotalStakes[i]; // Check return value against weights, latest state read, and minimum stake - assertEq(resultingStakes[i], setup.operatorWeights[i], "stake registry did not return correct stake"); - assertEq(resultingStakes[i], newOperatorStake.stake, "invalid latest operator stake update"); + assertEq( + resultingStakes[i], + setup.operatorWeights[i], + "stake registry did not return correct stake" + ); + assertEq( + resultingStakes[i], newOperatorStake.stake, "invalid latest operator stake update" + ); assertTrue(resultingStakes[i] != 0, "registered operator with zero stake"); - assertTrue(resultingStakes[i] >= setup.minimumStakes[i], "stake registry did not return correct stake"); - + assertTrue( + resultingStakes[i] >= setup.minimumStakes[i], + "stake registry did not return correct stake" + ); + // Check stake increase from fuzzed input - assertEq(resultingStakes[i], newOperatorStake.stake, "did not add additional stake to operator correctly"); - assertEq(resultingStakes[i], newTotalStake.stake, "did not add additional stake to total correctly"); + assertEq( + resultingStakes[i], + newOperatorStake.stake, + "did not add additional stake to operator correctly" + ); + assertEq( + resultingStakes[i], + newTotalStake.stake, + "did not add additional stake to total correctly" + ); // Check that we had an update this block assertEq(newOperatorStake.updateBlockNumber, uint32(block.number), ""); @@ -1046,36 +1167,60 @@ contract StakeRegistryUnitTests_Register is StakeRegistryUnitTests { ) public { cheats.assume(numOperators > 1 && numOperators < 20); - RegisterSetup[] memory setups = _fuzz_setupRegisterOperators(quorumBitmap, additionalStake, numOperators); + RegisterSetup[] memory setups = + _fuzz_setupRegisterOperators(quorumBitmap, additionalStake, numOperators); // Register each operator one at a time, and check results: - for (uint i = 0; i < numOperators; i++) { + for (uint256 i = 0; i < numOperators; i++) { RegisterSetup memory setup = setups[i]; cheats.prank(address(registryCoordinator)); - (uint96[] memory resultingStakes, uint96[] memory totalStakes) = - stakeRegistry.registerOperator(setup.operator, setup.operatorId, setup.quorumNumbers); - + (uint96[] memory resultingStakes, uint96[] memory totalStakes) = stakeRegistry + .registerOperator(setup.operator, setup.operatorId, setup.quorumNumbers); + /// Read ending state - IStakeRegistry.StakeUpdate[] memory newOperatorStakes = _getLatestStakeUpdates(setup.operatorId, setup.quorumNumbers); - uint256[] memory operatorStakeHistoryLengths = _getStakeHistoryLengths(setup.operatorId, setup.quorumNumbers); + IStakeRegistry.StakeUpdate[] memory newOperatorStakes = + _getLatestStakeUpdates(setup.operatorId, setup.quorumNumbers); + uint256[] memory operatorStakeHistoryLengths = + _getStakeHistoryLengths(setup.operatorId, setup.quorumNumbers); // Sum stakes in `_totalStakeAdded` to be checked later _tallyTotalStakeAdded(setup.quorumNumbers, resultingStakes); /// Check results - assertTrue(resultingStakes.length == setup.quorumNumbers.length, "invalid return length for operator stakes"); - assertTrue(totalStakes.length == setup.quorumNumbers.length, "invalid return length for total stakes"); - for (uint j = 0; j < setup.quorumNumbers.length; j++) { + assertTrue( + resultingStakes.length == setup.quorumNumbers.length, + "invalid return length for operator stakes" + ); + assertTrue( + totalStakes.length == setup.quorumNumbers.length, + "invalid return length for total stakes" + ); + for (uint256 j = 0; j < setup.quorumNumbers.length; j++) { // Check result against weights and latest state read - assertEq(resultingStakes[j], setup.operatorWeights[j], "stake registry did not return correct stake"); - assertEq(resultingStakes[j], newOperatorStakes[j].stake, "invalid latest operator stake update"); + assertEq( + resultingStakes[j], + setup.operatorWeights[j], + "stake registry did not return correct stake" + ); + assertEq( + resultingStakes[j], + newOperatorStakes[j].stake, + "invalid latest operator stake update" + ); assertTrue(resultingStakes[j] != 0, "registered operator with zero stake"); // Check result against minimum stake - assertTrue(resultingStakes[j] >= setup.minimumStakes[j], "stake registry did not return correct stake"); - + assertTrue( + resultingStakes[j] >= setup.minimumStakes[j], + "stake registry did not return correct stake" + ); + // Check stake increase from fuzzed input - assertEq(resultingStakes[j], newOperatorStakes[j].stake, "did not add additional stake to operator correctly"); + assertEq( + resultingStakes[j], + newOperatorStakes[j].stake, + "did not add additional stake to operator correctly" + ); // Check this is the first entry in the operator stake history assertEq(operatorStakeHistoryLengths[j], 1, "invalid total stake history length"); } @@ -1083,12 +1228,25 @@ contract StakeRegistryUnitTests_Register is StakeRegistryUnitTests { // Check total stake results bytes memory quorumNumbers = initializedQuorumBytes; - IStakeRegistry.StakeUpdate[] memory newTotalStakes = _getLatestTotalStakeUpdates(quorumNumbers); - for (uint i = 0; i < quorumNumbers.length; i++) { + IStakeRegistry.StakeUpdate[] memory newTotalStakes = + _getLatestTotalStakeUpdates(quorumNumbers); + for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); - assertEq(newTotalStakes[i].stake, _totalStakeAdded[quorumNumber], "incorrect latest total stake"); - assertEq(newTotalStakes[i].nextUpdateBlockNumber, 0, "incorrect total stake next update block"); - assertEq(newTotalStakes[i].updateBlockNumber, uint32(block.number), "incorrect total stake next update block"); + assertEq( + newTotalStakes[i].stake, + _totalStakeAdded[quorumNumber], + "incorrect latest total stake" + ); + assertEq( + newTotalStakes[i].nextUpdateBlockNumber, + 0, + "incorrect total stake next update block" + ); + assertEq( + newTotalStakes[i].updateBlockNumber, + uint32(block.number), + "incorrect total stake next update block" + ); } } @@ -1111,56 +1269,89 @@ contract StakeRegistryUnitTests_Register is StakeRegistryUnitTests { cheats.assume(operatorsPerBlock >= 1 && operatorsPerBlock <= 4); cheats.assume(totalBlocks >= 2 && totalBlocks <= 5); - uint startBlock = block.number; - for (uint i = 1; i <= totalBlocks; i++) { + uint256 startBlock = block.number; + for (uint256 i = 1; i <= totalBlocks; i++) { // Move to current block number - uint currBlock = startBlock + i; + uint256 currBlock = startBlock + i; cheats.roll(currBlock); - RegisterSetup[] memory setups = - _fuzz_setupRegisterOperators(initializedQuorumBitmap, additionalStake, operatorsPerBlock); + RegisterSetup[] memory setups = _fuzz_setupRegisterOperators( + initializedQuorumBitmap, additionalStake, operatorsPerBlock + ); // Get prior total stake updates bytes memory quorumNumbers = setups[0].quorumNumbers; - uint[] memory prevHistoryLengths = _getTotalStakeHistoryLengths(quorumNumbers); - - for (uint j = 0; j < operatorsPerBlock; j++) { + uint256[] memory prevHistoryLengths = _getTotalStakeHistoryLengths(quorumNumbers); + + for (uint256 j = 0; j < operatorsPerBlock; j++) { RegisterSetup memory setup = setups[j]; cheats.prank(address(registryCoordinator)); - (uint96[] memory resultingStakes, ) = - stakeRegistry.registerOperator(setup.operator, setup.operatorId, setup.quorumNumbers); - + (uint96[] memory resultingStakes,) = stakeRegistry.registerOperator( + setup.operator, setup.operatorId, setup.quorumNumbers + ); + // Sum stakes in `_totalStakeAdded` to be checked later _tallyTotalStakeAdded(setup.quorumNumbers, resultingStakes); } // Get new total stake updates - uint[] memory newHistoryLengths = _getTotalStakeHistoryLengths(quorumNumbers); - IStakeRegistry.StakeUpdate[] memory newTotalStakes = _getLatestTotalStakeUpdates(quorumNumbers); + uint256[] memory newHistoryLengths = _getTotalStakeHistoryLengths(quorumNumbers); + IStakeRegistry.StakeUpdate[] memory newTotalStakes = + _getLatestTotalStakeUpdates(quorumNumbers); - for (uint j = 0; j < quorumNumbers.length; j++) { + for (uint256 j = 0; j < quorumNumbers.length; j++) { uint8 quorumNumber = uint8(quorumNumbers[j]); // Check that we've added 1 to total stake history length - assertEq(prevHistoryLengths[j] + 1, newHistoryLengths[j], "total history should have a new entry"); + assertEq( + prevHistoryLengths[j] + 1, + newHistoryLengths[j], + "total history should have a new entry" + ); // Validate latest entry correctness - assertEq(newTotalStakes[j].stake, _totalStakeAdded[quorumNumber], "latest update should match total stake added"); - assertEq(newTotalStakes[j].updateBlockNumber, currBlock, "latest update should be from current block"); - assertEq(newTotalStakes[j].nextUpdateBlockNumber, 0, "latest update should not have next update block"); + assertEq( + newTotalStakes[j].stake, + _totalStakeAdded[quorumNumber], + "latest update should match total stake added" + ); + assertEq( + newTotalStakes[j].updateBlockNumber, + currBlock, + "latest update should be from current block" + ); + assertEq( + newTotalStakes[j].nextUpdateBlockNumber, + 0, + "latest update should not have next update block" + ); // Validate previous entry was updated correctly - IStakeRegistry.StakeUpdate memory prevUpdate = - stakeRegistry.getTotalStakeUpdateAtIndex(quorumNumber, prevHistoryLengths[j]-1); - assertTrue(prevUpdate.stake < newTotalStakes[j].stake, "previous update should have lower stake than latest"); - assertEq(prevUpdate.updateBlockNumber + 1, newTotalStakes[j].updateBlockNumber, "prev entry should be from last block"); - assertEq(prevUpdate.nextUpdateBlockNumber, newTotalStakes[j].updateBlockNumber, "prev entry.next should be latest.cur"); + IStakeRegistry.StakeUpdate memory prevUpdate = stakeRegistry + .getTotalStakeUpdateAtIndex(quorumNumber, prevHistoryLengths[j] - 1); + assertTrue( + prevUpdate.stake < newTotalStakes[j].stake, + "previous update should have lower stake than latest" + ); + assertEq( + prevUpdate.updateBlockNumber + 1, + newTotalStakes[j].updateBlockNumber, + "prev entry should be from last block" + ); + assertEq( + prevUpdate.nextUpdateBlockNumber, + newTotalStakes[j].updateBlockNumber, + "prev entry.next should be latest.cur" + ); } } } - function _tallyTotalStakeAdded(bytes memory quorumNumbers, uint96[] memory stakeAdded) internal { - for (uint i = 0; i < quorumNumbers.length; i++) { + function _tallyTotalStakeAdded( + bytes memory quorumNumbers, + uint96[] memory stakeAdded + ) internal { + for (uint256 i = 0; i < quorumNumbers.length; i++) { uint8 quorumNumber = uint8(quorumNumbers[i]); _totalStakeAdded[quorumNumber] += stakeAdded[i]; } @@ -1169,13 +1360,13 @@ contract StakeRegistryUnitTests_Register is StakeRegistryUnitTests { /// @notice Tests for StakeRegistry.deregisterOperator contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { - using BitmapUtils for *; - /******************************************************************************* - deregisterOperator - *******************************************************************************/ - + /** + * + * deregisterOperator + * + */ function test_deregisterOperator_Revert_WhenNotRegistryCoordinator() public { DeregisterSetup memory setup = _fuzz_setupDeregisterOperator({ registeredFor: initializedQuorumBitmap, @@ -1183,7 +1374,9 @@ contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { fuzzy_addtlStake: 0 }); - cheats.expectRevert("StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator"); + cheats.expectRevert( + "StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator" + ); stakeRegistry.deregisterOperator(setup.operatorId, setup.quorumsToRemove); } @@ -1194,11 +1387,11 @@ contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { fuzzy_toRemove: initializedQuorumBitmap, fuzzy_addtlStake: 0 }); - + // Get a list of valid quorums ending in an invalid quorum number bytes memory invalidQuorums = _fuzz_getInvalidQuorums(rand); - cheats.expectRevert("StakeRegistry.registerOperator: quorum does not exist"); + cheats.expectRevert("StakeRegistry.quorumExists: quorum does not exist"); cheats.prank(address(registryCoordinator)); stakeRegistry.registerOperator(setup.operator, setup.operatorId, invalidQuorums); } @@ -1224,10 +1417,12 @@ contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { cheats.prank(address(registryCoordinator)); stakeRegistry.deregisterOperator(setup.operatorId, setup.quorumsToRemove); - IStakeRegistry.StakeUpdate[] memory newOperatorStakes = _getLatestStakeUpdates(setup.operatorId, setup.registeredQuorumNumbers); - IStakeRegistry.StakeUpdate[] memory newTotalStakes = _getLatestTotalStakeUpdates(setup.registeredQuorumNumbers); + IStakeRegistry.StakeUpdate[] memory newOperatorStakes = + _getLatestStakeUpdates(setup.operatorId, setup.registeredQuorumNumbers); + IStakeRegistry.StakeUpdate[] memory newTotalStakes = + _getLatestTotalStakeUpdates(setup.registeredQuorumNumbers); - for (uint i = 0; i < setup.registeredQuorumNumbers.length; i++) { + for (uint256 i = 0; i < setup.registeredQuorumNumbers.length; i++) { uint8 registeredQuorum = uint8(setup.registeredQuorumNumbers[i]); IStakeRegistry.StakeUpdate memory prevOperatorStake = setup.prevOperatorStakes[i]; @@ -1242,24 +1437,49 @@ contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { if (deregistered) { // Check that operator's stake was removed from both operator and total assertEq(newOperatorStake.stake, 0, "failed to remove stake"); - assertEq(newTotalStake.stake + prevOperatorStake.stake, prevTotalStake.stake, "failed to remove stake from total"); - + assertEq( + newTotalStake.stake + prevOperatorStake.stake, + prevTotalStake.stake, + "failed to remove stake from total" + ); + // Check that we had an update this block - assertEq(newOperatorStake.updateBlockNumber, uint32(block.number), "operator stake has incorrect update block"); - assertEq(newOperatorStake.nextUpdateBlockNumber, 0, "operator stake has incorrect next update block"); - assertEq(newTotalStake.updateBlockNumber, uint32(block.number), "total stake has incorrect update block"); - assertEq(newTotalStake.nextUpdateBlockNumber, 0, "total stake has incorrect next update block"); + assertEq( + newOperatorStake.updateBlockNumber, + uint32(block.number), + "operator stake has incorrect update block" + ); + assertEq( + newOperatorStake.nextUpdateBlockNumber, + 0, + "operator stake has incorrect next update block" + ); + assertEq( + newTotalStake.updateBlockNumber, + uint32(block.number), + "total stake has incorrect update block" + ); + assertEq( + newTotalStake.nextUpdateBlockNumber, + 0, + "total stake has incorrect next update block" + ); } else { // Ensure no change to operator or total stakes - assertTrue(_isUnchanged(prevOperatorStake, newOperatorStake), "operator stake incorrectly updated"); - assertTrue(_isUnchanged(prevTotalStake, newTotalStake), "total stake incorrectly updated"); + assertTrue( + _isUnchanged(prevOperatorStake, newOperatorStake), + "operator stake incorrectly updated" + ); + assertTrue( + _isUnchanged(prevTotalStake, newTotalStake), "total stake incorrectly updated" + ); } } } // Track total stake removed from each quorum as we deregister operators mapping(uint8 => uint96) _totalStakeRemoved; - + /** * @dev Registers multiple operators for each initialized quorum, adding `additionalStake` * to the minimum stake for each quorum. Tests deregistering the operators for @@ -1284,21 +1504,24 @@ contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { bytes memory registeredQuorums = initializedQuorumBytes; uint192 quorumsToRemoveBitmap = setups[0].quorumsToRemoveBitmap; - IStakeRegistry.StakeUpdate[] memory prevTotalStakes = _getLatestTotalStakeUpdates(registeredQuorums); + IStakeRegistry.StakeUpdate[] memory prevTotalStakes = + _getLatestTotalStakeUpdates(registeredQuorums); // Deregister operators one at a time and check results - for (uint i = 0; i < numOperators; i++) { + for (uint256 i = 0; i < numOperators; i++) { DeregisterSetup memory setup = setups[i]; bytes32 operatorId = setup.operatorId; cheats.prank(address(registryCoordinator)); stakeRegistry.deregisterOperator(setup.operatorId, setup.quorumsToRemove); - IStakeRegistry.StakeUpdate[] memory newOperatorStakes = _getLatestStakeUpdates(operatorId, registeredQuorums); - IStakeRegistry.StakeUpdate[] memory newTotalStakes = _getLatestTotalStakeUpdates(registeredQuorums); + IStakeRegistry.StakeUpdate[] memory newOperatorStakes = + _getLatestStakeUpdates(operatorId, registeredQuorums); + IStakeRegistry.StakeUpdate[] memory newTotalStakes = + _getLatestTotalStakeUpdates(registeredQuorums); // Check results for each quorum - for (uint j = 0; j < registeredQuorums.length; j++) { + for (uint256 j = 0; j < registeredQuorums.length; j++) { uint8 registeredQuorum = uint8(registeredQuorums[j]); IStakeRegistry.StakeUpdate memory prevOperatorStake = setup.prevOperatorStakes[j]; @@ -1315,24 +1538,48 @@ contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { // Check that operator's stake was removed from both operator and total assertEq(newOperatorStake.stake, 0, "failed to remove stake"); - assertEq(newTotalStake.stake + _totalStakeRemoved[registeredQuorum], prevTotalStake.stake, "failed to remove stake from total"); - + assertEq( + newTotalStake.stake + _totalStakeRemoved[registeredQuorum], + prevTotalStake.stake, + "failed to remove stake from total" + ); + // Check that we had an update this block - assertEq(newOperatorStake.updateBlockNumber, uint32(block.number), "operator stake has incorrect update block"); - assertEq(newOperatorStake.nextUpdateBlockNumber, 0, "operator stake has incorrect next update block"); - assertEq(newTotalStake.updateBlockNumber, uint32(block.number), "total stake has incorrect update block"); - assertEq(newTotalStake.nextUpdateBlockNumber, 0, "total stake has incorrect next update block"); + assertEq( + newOperatorStake.updateBlockNumber, + uint32(block.number), + "operator stake has incorrect update block" + ); + assertEq( + newOperatorStake.nextUpdateBlockNumber, + 0, + "operator stake has incorrect next update block" + ); + assertEq( + newTotalStake.updateBlockNumber, + uint32(block.number), + "total stake has incorrect update block" + ); + assertEq( + newTotalStake.nextUpdateBlockNumber, + 0, + "total stake has incorrect next update block" + ); } else { // Ensure no change to operator stake - assertTrue(_isUnchanged(prevOperatorStake, newOperatorStake), "operator stake incorrectly updated"); + assertTrue( + _isUnchanged(prevOperatorStake, newOperatorStake), + "operator stake incorrectly updated" + ); } } } // Now that we've deregistered all the operators, check the final results // For the quorums we chose to deregister from, the total stake should be zero - IStakeRegistry.StakeUpdate[] memory finalTotalStakes = _getLatestTotalStakeUpdates(registeredQuorums); - for (uint i = 0; i < registeredQuorums.length; i++) { + IStakeRegistry.StakeUpdate[] memory finalTotalStakes = + _getLatestTotalStakeUpdates(registeredQuorums); + for (uint256 i = 0; i < registeredQuorums.length; i++) { uint8 registeredQuorum = uint8(registeredQuorums[i]); // Whether or not we deregistered operators from this quorum @@ -1340,10 +1587,21 @@ contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { if (deregistered) { assertEq(finalTotalStakes[i].stake, 0, "failed to remove all stake from quorum"); - assertEq(finalTotalStakes[i].updateBlockNumber, uint32(block.number), "failed to remove all stake from quorum"); - assertEq(finalTotalStakes[i].nextUpdateBlockNumber, 0, "failed to remove all stake from quorum"); + assertEq( + finalTotalStakes[i].updateBlockNumber, + uint32(block.number), + "failed to remove all stake from quorum" + ); + assertEq( + finalTotalStakes[i].nextUpdateBlockNumber, + 0, + "failed to remove all stake from quorum" + ); } else { - assertTrue(_isUnchanged(finalTotalStakes[i], prevTotalStakes[i]), "incorrectly updated total stake history for unmodified quorum"); + assertTrue( + _isUnchanged(finalTotalStakes[i], prevTotalStakes[i]), + "incorrectly updated total stake history for unmodified quorum" + ); } } } @@ -1367,8 +1625,8 @@ contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { cheats.assume(operatorsPerBlock >= 1 && operatorsPerBlock <= 4); cheats.assume(totalBlocks >= 2 && totalBlocks <= 5); - uint numOperators = operatorsPerBlock * totalBlocks; - uint operatorIdx; // track index in setups over test + uint256 numOperators = operatorsPerBlock * totalBlocks; + uint256 operatorIdx; // track index in setups over test // Select multiple new operators, set their weight equal to the minimum plus some additional, // then register them for all initialized quorums @@ -1382,61 +1640,91 @@ contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { // For all operators, we're going to register for and then deregister from all initialized quorums bytes memory registeredQuorums = initializedQuorumBytes; - IStakeRegistry.StakeUpdate[] memory prevTotalStakes = _getLatestTotalStakeUpdates(registeredQuorums); - uint startBlock = block.number; + IStakeRegistry.StakeUpdate[] memory prevTotalStakes = + _getLatestTotalStakeUpdates(registeredQuorums); + uint256 startBlock = block.number; - for (uint i = 1; i <= totalBlocks; i++) { + for (uint256 i = 1; i <= totalBlocks; i++) { // Move to current block number - uint currBlock = startBlock + i; + uint256 currBlock = startBlock + i; cheats.roll(currBlock); - uint[] memory prevHistoryLengths = _getTotalStakeHistoryLengths(registeredQuorums); + uint256[] memory prevHistoryLengths = _getTotalStakeHistoryLengths(registeredQuorums); // Within this block: deregister some operators for all quorums and add the stake removed // to `_totalStakeRemoved` for later checks - for (uint j = 0; j < operatorsPerBlock; j++) { + for (uint256 j = 0; j < operatorsPerBlock; j++) { DeregisterSetup memory setup = setups[operatorIdx]; operatorIdx++; cheats.prank(address(registryCoordinator)); stakeRegistry.deregisterOperator(setup.operatorId, setup.quorumsToRemove); - for (uint k = 0; k < registeredQuorums.length; k++) { + for (uint256 k = 0; k < registeredQuorums.length; k++) { uint8 quorumNumber = uint8(registeredQuorums[k]); _totalStakeRemoved[quorumNumber] += setup.prevOperatorStakes[k].stake; } } - uint[] memory newHistoryLengths = _getTotalStakeHistoryLengths(registeredQuorums); - IStakeRegistry.StakeUpdate[] memory newTotalStakes = _getLatestTotalStakeUpdates(registeredQuorums); + uint256[] memory newHistoryLengths = _getTotalStakeHistoryLengths(registeredQuorums); + IStakeRegistry.StakeUpdate[] memory newTotalStakes = + _getLatestTotalStakeUpdates(registeredQuorums); // Validate the sum of all updates this block: // Each quorum should have a new historical entry with the correct update block pointers // ... and each quorum's stake should have decreased by `_totalStakeRemoved[quorum]` - for (uint j = 0; j < registeredQuorums.length; j++) { + for (uint256 j = 0; j < registeredQuorums.length; j++) { uint8 quorumNumber = uint8(registeredQuorums[j]); // Check that we've added 1 to total stake history length - assertEq(prevHistoryLengths[j] + 1, newHistoryLengths[j], "total history should have a new entry"); + assertEq( + prevHistoryLengths[j] + 1, + newHistoryLengths[j], + "total history should have a new entry" + ); // Validate latest entry correctness - assertEq(newTotalStakes[j].stake + _totalStakeRemoved[quorumNumber], prevTotalStakes[j].stake, "stake not removed correctly from total stake"); - assertEq(newTotalStakes[j].updateBlockNumber, currBlock, "latest update should be from current block"); - assertEq(newTotalStakes[j].nextUpdateBlockNumber, 0, "latest update should not have next update block"); - - IStakeRegistry.StakeUpdate memory prevUpdate = - stakeRegistry.getTotalStakeUpdateAtIndex(quorumNumber, prevHistoryLengths[j]-1); + assertEq( + newTotalStakes[j].stake + _totalStakeRemoved[quorumNumber], + prevTotalStakes[j].stake, + "stake not removed correctly from total stake" + ); + assertEq( + newTotalStakes[j].updateBlockNumber, + currBlock, + "latest update should be from current block" + ); + assertEq( + newTotalStakes[j].nextUpdateBlockNumber, + 0, + "latest update should not have next update block" + ); + + IStakeRegistry.StakeUpdate memory prevUpdate = stakeRegistry + .getTotalStakeUpdateAtIndex(quorumNumber, prevHistoryLengths[j] - 1); // Validate previous entry was updated correctly - assertTrue(prevUpdate.stake > newTotalStakes[j].stake, "previous update should have higher stake than latest"); - assertEq(prevUpdate.updateBlockNumber + 1, newTotalStakes[j].updateBlockNumber, "prev entry should be from last block"); - assertEq(prevUpdate.nextUpdateBlockNumber, newTotalStakes[j].updateBlockNumber, "prev entry.next should be latest.cur"); + assertTrue( + prevUpdate.stake > newTotalStakes[j].stake, + "previous update should have higher stake than latest" + ); + assertEq( + prevUpdate.updateBlockNumber + 1, + newTotalStakes[j].updateBlockNumber, + "prev entry should be from last block" + ); + assertEq( + prevUpdate.nextUpdateBlockNumber, + newTotalStakes[j].updateBlockNumber, + "prev entry.next should be latest.cur" + ); } } // Now that we've deregistered all the operators, check the final results // Each quorum's stake should be zero - IStakeRegistry.StakeUpdate[] memory finalTotalStakes = _getLatestTotalStakeUpdates(registeredQuorums); - for (uint i = 0; i < registeredQuorums.length; i++) { + IStakeRegistry.StakeUpdate[] memory finalTotalStakes = + _getLatestTotalStakeUpdates(registeredQuorums); + for (uint256 i = 0; i < registeredQuorums.length; i++) { assertEq(finalTotalStakes[i].stake, 0, "failed to remove all stake from quorum"); } } @@ -1444,30 +1732,27 @@ contract StakeRegistryUnitTests_Deregister is StakeRegistryUnitTests { /// @notice Tests for StakeRegistry.updateOperatorStake contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { - using BitmapUtils for *; function test_updateOperatorStake_Revert_WhenNotRegistryCoordinator() public { - UpdateSetup memory setup = _fuzz_setupUpdateOperatorStake({ - registeredFor: initializedQuorumBitmap, - fuzzy_Delta: 0 - }); + UpdateSetup memory setup = + _fuzz_setupUpdateOperatorStake({registeredFor: initializedQuorumBitmap, fuzzy_Delta: 0}); - cheats.expectRevert("StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator"); + cheats.expectRevert( + "StakeRegistry.onlyRegistryCoordinator: caller is not the RegistryCoordinator" + ); stakeRegistry.updateOperatorStake(setup.operator, setup.operatorId, setup.quorumNumbers); } 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 - }); - + UpdateSetup memory setup = + _fuzz_setupUpdateOperatorStake({registeredFor: initializedQuorumBitmap, fuzzy_Delta: 0}); + // Get a list of valid quorums ending in an invalid quorum number bytes memory invalidQuorums = _fuzz_getInvalidQuorums(rand); - cheats.expectRevert("StakeRegistry.updateOperatorStake: quorum does not exist"); + cheats.expectRevert("StakeRegistry.quorumExists: quorum does not exist"); cheats.prank(address(registryCoordinator)); stakeRegistry.updateOperatorStake(setup.operator, setup.operatorId, invalidQuorums); } @@ -1487,20 +1772,24 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { }); // Get starting state - IStakeRegistry.StakeUpdate[] memory prevOperatorStakes = _getLatestStakeUpdates(setup.operatorId, setup.quorumNumbers); - IStakeRegistry.StakeUpdate[] memory prevTotalStakes = _getLatestTotalStakeUpdates(setup.quorumNumbers); + IStakeRegistry.StakeUpdate[] memory prevOperatorStakes = + _getLatestStakeUpdates(setup.operatorId, setup.quorumNumbers); + IStakeRegistry.StakeUpdate[] memory prevTotalStakes = + _getLatestTotalStakeUpdates(setup.quorumNumbers); // updateOperatorStake cheats.prank(address(registryCoordinator)); - uint192 quorumsToRemove = + uint192 quorumsToRemove = stakeRegistry.updateOperatorStake(setup.operator, setup.operatorId, setup.quorumNumbers); // Get ending state - IStakeRegistry.StakeUpdate[] memory newOperatorStakes = _getLatestStakeUpdates(setup.operatorId, setup.quorumNumbers); - IStakeRegistry.StakeUpdate[] memory newTotalStakes = _getLatestTotalStakeUpdates(setup.quorumNumbers); + IStakeRegistry.StakeUpdate[] memory newOperatorStakes = + _getLatestStakeUpdates(setup.operatorId, setup.quorumNumbers); + IStakeRegistry.StakeUpdate[] memory newTotalStakes = + _getLatestTotalStakeUpdates(setup.quorumNumbers); // Check results for each quorum - for (uint i = 0; i < setup.quorumNumbers.length; i++) { + for (uint256 i = 0; i < setup.quorumNumbers.length; i++) { uint8 quorumNumber = uint8(setup.quorumNumbers[i]); uint96 minimumStake = setup.minimumStakes[i]; @@ -1513,33 +1802,63 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { IStakeRegistry.StakeUpdate memory newTotalStake = newTotalStakes[i]; // Sanity-check setup - operator should start with minimumStake - assertTrue(prevOperatorStake.stake == minimumStake, "operator should start with nonzero stake"); + assertTrue( + prevOperatorStake.stake == minimumStake, "operator should start with nonzero stake" + ); if (endingWeight > minimumStake) { // Check updating an operator who has added stake above the minimum: // Only updates should be stake added to operator/total stakes uint96 stakeAdded = setup.stakeDeltaAbs; - assertEq(prevOperatorStake.stake + stakeAdded, newOperatorStake.stake, "failed to add delta to operator stake"); - assertEq(prevTotalStake.stake + stakeAdded, newTotalStake.stake, "failed to add delta to total stake"); + assertEq( + prevOperatorStake.stake + stakeAdded, + newOperatorStake.stake, + "failed to add delta to operator stake" + ); + assertEq( + prevTotalStake.stake + stakeAdded, + newTotalStake.stake, + "failed to add delta to total stake" + ); // Return value should be empty since we're still above the minimum - assertTrue(quorumsToRemove.isEmpty(), "positive stake delta should not remove any quorums"); + assertTrue( + quorumsToRemove.isEmpty(), "positive stake delta should not remove any quorums" + ); } else if (endingWeight < minimumStake) { // Check updating an operator who is now below the minimum: // Stake should now be zero, regardless of stake delta uint96 stakeRemoved = minimumStake; - assertEq(prevOperatorStake.stake - stakeRemoved, newOperatorStake.stake, "failed to remove delta from operator stake"); - assertEq(prevTotalStake.stake - stakeRemoved, newTotalStake.stake, "failed to remove delta from total stake"); + assertEq( + prevOperatorStake.stake - stakeRemoved, + newOperatorStake.stake, + "failed to remove delta from operator stake" + ); + 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 - assertTrue(quorumsToRemove.isSet(quorumNumber), "quorum should be in removal bitmap"); + assertTrue( + quorumsToRemove.isSet(quorumNumber), "quorum should be in removal bitmap" + ); } else { // Check that no update occurs if weight remains the same - assertTrue(_isUnchanged(prevOperatorStake, newOperatorStake), "neutral stake delta should not have changed operator stake history"); - assertTrue(_isUnchanged(prevTotalStake, newTotalStake), "neutral stake delta should not have changed total stake history"); + assertTrue( + _isUnchanged(prevOperatorStake, newOperatorStake), + "neutral stake delta should not have changed operator stake history" + ); + assertTrue( + _isUnchanged(prevTotalStake, newTotalStake), + "neutral stake delta should not have changed total stake history" + ); // Check that return value is empty - we're still at the minimum, so no quorums should be removed - assertTrue(quorumsToRemove.isEmpty(), "neutral stake delta should not remove any quorums"); + assertTrue( + quorumsToRemove.isEmpty(), "neutral stake delta should not remove any quorums" + ); } } } @@ -1568,11 +1887,12 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { bytes memory quorumNumbers = initializedQuorumBytes; // Get initial total history state - uint[] memory initialHistoryLengths = _getTotalStakeHistoryLengths(quorumNumbers); - IStakeRegistry.StakeUpdate[] memory initialTotalStakes = _getLatestTotalStakeUpdates(quorumNumbers); + uint256[] memory initialHistoryLengths = _getTotalStakeHistoryLengths(quorumNumbers); + IStakeRegistry.StakeUpdate[] memory initialTotalStakes = + _getLatestTotalStakeUpdates(quorumNumbers); // Call `updateOperatorStake` one by one - for (uint i = 0; i < numOperators; i++) { + for (uint256 i = 0; i < numOperators; i++) { UpdateSetup memory setup = setups[i]; // updateOperatorStake @@ -1581,10 +1901,11 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { } // Check final results for each quorum - uint[] memory finalHistoryLengths = _getTotalStakeHistoryLengths(quorumNumbers); - IStakeRegistry.StakeUpdate[] memory finalTotalStakes = _getLatestTotalStakeUpdates(quorumNumbers); + uint256[] memory finalHistoryLengths = _getTotalStakeHistoryLengths(quorumNumbers); + IStakeRegistry.StakeUpdate[] memory finalTotalStakes = + _getLatestTotalStakeUpdates(quorumNumbers); - for (uint i = 0; i < quorumNumbers.length; i++) { + for (uint256 i = 0; i < quorumNumbers.length; i++) { IStakeRegistry.StakeUpdate memory initialTotalStake = initialTotalStakes[i]; IStakeRegistry.StakeUpdate memory finalTotalStake = finalTotalStakes[i]; @@ -1593,23 +1914,42 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { uint96 stakeDeltaAbs = setups[0].stakeDeltaAbs; // Sanity-check setup: previous total stake should be minimumStake * numOperators - assertEq(initialTotalStake.stake, minimumStake * numOperators, "quorum should start with minimum stake from all operators"); + assertEq( + initialTotalStake.stake, + minimumStake * numOperators, + "quorum should start with minimum stake from all operators" + ); // history lengths should be unchanged - assertEq(initialHistoryLengths[i], finalHistoryLengths[i], "history lengths should remain unchanged"); - + assertEq( + initialHistoryLengths[i], + finalHistoryLengths[i], + "history lengths should remain unchanged" + ); + if (endingWeight > minimumStake) { // All operators had their stake increased by stakeDelta uint96 stakeAdded = numOperators * stakeDeltaAbs; - assertEq(initialTotalStake.stake + stakeAdded, finalTotalStake.stake, "failed to add delta for all operators"); + assertEq( + initialTotalStake.stake + stakeAdded, + finalTotalStake.stake, + "failed to add delta for all operators" + ); } else if (endingWeight < minimumStake) { // All operators had their entire stake removed uint96 stakeRemoved = numOperators * minimumStake; - assertEq(initialTotalStake.stake - stakeRemoved, finalTotalStake.stake, "failed to remove delta from total stake"); + assertEq( + initialTotalStake.stake - stakeRemoved, + finalTotalStake.stake, + "failed to remove delta from total stake" + ); assertEq(finalTotalStake.stake, 0, "final total stake should be zero"); } else { // No change in stake for any operator - assertTrue(_isUnchanged(initialTotalStake, finalTotalStake), "neutral stake delta should result in no change"); + assertTrue( + _isUnchanged(initialTotalStake, finalTotalStake), + "neutral stake delta should result in no change" + ); } } } @@ -1626,7 +1966,7 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { int8 stakeDelta ) public { cheats.assume(totalBlocks >= 2 && totalBlocks <= 8); - + uint256 startBlock = block.number; for (uint256 j = 1; j <= totalBlocks; j++) { UpdateSetup memory setup = _fuzz_setupUpdateOperatorStake({ @@ -1635,9 +1975,12 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { }); // Get starting state - IStakeRegistry.StakeUpdate[] memory prevOperatorStakes = _getLatestStakeUpdates(setup.operatorId, setup.quorumNumbers); - IStakeRegistry.StakeUpdate[] memory prevTotalStakes = _getLatestTotalStakeUpdates(setup.quorumNumbers); - uint256[] memory prevOperatorHistoryLengths = _getStakeHistoryLengths(setup.operatorId, setup.quorumNumbers); + IStakeRegistry.StakeUpdate[] memory prevOperatorStakes = + _getLatestStakeUpdates(setup.operatorId, setup.quorumNumbers); + IStakeRegistry.StakeUpdate[] memory prevTotalStakes = + _getLatestTotalStakeUpdates(setup.quorumNumbers); + uint256[] memory prevOperatorHistoryLengths = + _getStakeHistoryLengths(setup.operatorId, setup.quorumNumbers); // Move to current block number uint256 currBlock = startBlock + j; @@ -1645,16 +1988,20 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { // updateOperatorStake cheats.prank(address(registryCoordinator)); - uint192 quorumsToRemove = - stakeRegistry.updateOperatorStake(setup.operator, setup.operatorId, setup.quorumNumbers); + uint192 quorumsToRemove = stakeRegistry.updateOperatorStake( + setup.operator, setup.operatorId, setup.quorumNumbers + ); // Get ending state - IStakeRegistry.StakeUpdate[] memory newOperatorStakes = _getLatestStakeUpdates(setup.operatorId, setup.quorumNumbers); - IStakeRegistry.StakeUpdate[] memory newTotalStakes = _getLatestTotalStakeUpdates(setup.quorumNumbers); - uint256[] memory newOperatorHistoryLengths = _getStakeHistoryLengths(setup.operatorId, setup.quorumNumbers); + IStakeRegistry.StakeUpdate[] memory newOperatorStakes = + _getLatestStakeUpdates(setup.operatorId, setup.quorumNumbers); + IStakeRegistry.StakeUpdate[] memory newTotalStakes = + _getLatestTotalStakeUpdates(setup.quorumNumbers); + uint256[] memory newOperatorHistoryLengths = + _getStakeHistoryLengths(setup.operatorId, setup.quorumNumbers); // Check results for each quorum - for (uint i = 0; i < setup.quorumNumbers.length; i++) { + for (uint256 i = 0; i < setup.quorumNumbers.length; i++) { uint8 quorumNumber = uint8(setup.quorumNumbers[i]); uint96 minimumStake = setup.minimumStakes[i]; @@ -1667,42 +2014,95 @@ contract StakeRegistryUnitTests_StakeUpdates is StakeRegistryUnitTests { // IStakeRegistry.StakeUpdate memory newTotalStake = newTotalStakes[i]; // Sanity-check setup - operator should start with minimumStake - assertTrue(prevOperatorStake.stake == minimumStake, "operator should start with nonzero stake"); + assertTrue( + prevOperatorStake.stake == minimumStake, + "operator should start with nonzero stake" + ); if (endingWeight > minimumStake) { // Check updating an operator who has added stake above the minimum: uint96 stakeAdded = setup.stakeDeltaAbs; - assertEq(prevOperatorStake.stake + stakeAdded, newOperatorStake.stake, "failed to add delta to operator stake"); - assertEq(prevTotalStakes[i].stake + stakeAdded, newTotalStakes[i].stake, "failed to add delta to total stake"); + assertEq( + prevOperatorStake.stake + stakeAdded, + newOperatorStake.stake, + "failed to add delta to operator stake" + ); + assertEq( + prevTotalStakes[i].stake + stakeAdded, + newTotalStakes[i].stake, + "failed to add delta to total stake" + ); // Return value should be empty since we're still above the minimum - assertTrue(quorumsToRemove.isEmpty(), "positive stake delta should not remove any quorums"); - assertEq(prevOperatorHistoryLengths[i] + 1, newOperatorHistoryLengths[i], "operator should have a new pushed update"); + assertTrue( + quorumsToRemove.isEmpty(), + "positive stake delta should not remove any quorums" + ); + assertEq( + prevOperatorHistoryLengths[i] + 1, + newOperatorHistoryLengths[i], + "operator should have a new pushed update" + ); } else if (endingWeight < minimumStake) { // Check updating an operator who is now below the minimum: // Stake should now be zero, regardless of stake delta uint96 stakeRemoved = minimumStake; - assertEq(prevOperatorStake.stake - stakeRemoved, newOperatorStake.stake, "failed to remove delta from operator stake"); + assertEq( + prevOperatorStake.stake - stakeRemoved, + newOperatorStake.stake, + "failed to remove delta from operator stake" + ); // 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 - assertTrue(quorumsToRemove.isSet(quorumNumber), "quorum should be in removal bitmap"); + assertTrue( + quorumsToRemove.isSet(quorumNumber), "quorum should be in removal bitmap" + ); if (prevOperatorStake.stake >= minimumStake) { // Total stakes and operator history should be updated - assertEq(prevOperatorHistoryLengths[i] + 1, newOperatorHistoryLengths[i], "operator should have a new pushed update"); - assertEq(prevTotalStakes[i].stake, newTotalStakes[i].stake + prevOperatorStake.stake, "failed to remove from total stake"); + assertEq( + prevOperatorHistoryLengths[i] + 1, + newOperatorHistoryLengths[i], + "operator should have a new pushed update" + ); + assertEq( + prevTotalStakes[i].stake, + newTotalStakes[i].stake + prevOperatorStake.stake, + "failed to remove from total stake" + ); } else { // Total stakes and history should remain unchanged - assertEq(prevOperatorHistoryLengths[i], newOperatorHistoryLengths[i], "history lengths should remain unchanged"); - assertEq(prevTotalStakes[i].stake, newTotalStakes[i].stake, "total stake should remain unchanged"); + assertEq( + prevOperatorHistoryLengths[i], + newOperatorHistoryLengths[i], + "history lengths should remain unchanged" + ); + assertEq( + prevTotalStakes[i].stake, + newTotalStakes[i].stake, + "total stake should remain unchanged" + ); } } else { // Check that no update occurs if weight remains the same - assertTrue(_isUnchanged(prevOperatorStake, newOperatorStake), "neutral stake delta should not have changed operator stake history"); - assertTrue(_isUnchanged(prevTotalStakes[i], newTotalStakes[i]), "neutral stake delta should not have changed total stake history"); + assertTrue( + _isUnchanged(prevOperatorStake, newOperatorStake), + "neutral stake delta should not have changed operator stake history" + ); + assertTrue( + _isUnchanged(prevTotalStakes[i], newTotalStakes[i]), + "neutral stake delta should not have changed total stake history" + ); // Check that return value is empty - we're still at the minimum, so no quorums should be removed - assertTrue(quorumsToRemove.isEmpty(), "neutral stake delta should not remove any quorums"); - assertEq(prevOperatorHistoryLengths[i], newOperatorHistoryLengths[i], "history lengths should remain unchanged"); + assertTrue( + quorumsToRemove.isEmpty(), + "neutral stake delta should not remove any quorums" + ); + assertEq( + prevOperatorHistoryLengths[i], + newOperatorHistoryLengths[i], + "history lengths should remain unchanged" + ); } } } @@ -1715,7 +2115,7 @@ contract StakeRegistryUnitTests_weightOfOperatorForQuorum is StakeRegistryUnitTe /** * @dev Initialize a new quorum with fuzzed multipliers and corresponding shares for an operator. - * The minimum stake for the quorum is 0 so that any fuzzed input shares will register the operator + * The minimum stake for the quorum is 0 so that any fuzzed input shares will register the operator * successfully and return a value for weightOfOperatorForQuorum. Fuzz test sets the operator shares * and asserts that the summed weight of the operator is correct. */ @@ -1730,23 +2130,30 @@ 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); - for (uint i = 0; i < strategyParams.length; i++) { - multipliers[i] = uint96(_randUint({rand: bytes32(uint256(multipliers[i])), min: 0, max: 1000*WEIGHTING_DIVISOR })); - shares[i] = uint96(_randUint({rand: bytes32(uint256(shares[i])), min: 0, max: 10e20 })); + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.StrategyParams[](3); + for (uint256 i = 0; i < strategyParams.length; i++) { + multipliers[i] = uint96( + _randUint({ + rand: bytes32(uint256(multipliers[i])), + min: 0, + max: 1000 * WEIGHTING_DIVISOR + }) + ); + shares[i] = uint96(_randUint({rand: bytes32(uint256(shares[i])), min: 0, max: 10e20})); - IStrategy strat = IStrategy(address(uint160(uint256(keccak256(abi.encodePacked("Voteweighing test", i)))))); - strategyParams[i] = IStakeRegistry.StrategyParams( - strat, - uint96(WEIGHTING_DIVISOR) + multipliers[i] + IStrategy strat = IStrategy( + address(uint160(uint256(keccak256(abi.encodePacked("Voteweighing test", i))))) ); + strategyParams[i] = + IStakeRegistry.StrategyParams(strat, uint96(WEIGHTING_DIVISOR) + multipliers[i]); } cheats.prank(address(registryCoordinator)); uint8 quorumNumber = nextQuorum; - stakeRegistry.initializeQuorum(quorumNumber, 0 /* minimumStake */, strategyParams); + stakeRegistry.initializeQuorum(quorumNumber, 0, /* minimumStake */ strategyParams); // set the operator shares - for (uint i = 0; i < strategyParams.length; i++) { + for (uint256 i = 0; i < strategyParams.length; i++) { delegationMock.setOperatorShares(operator, strategyParams[i].strategy, shares[i]); } @@ -1756,11 +2163,12 @@ contract StakeRegistryUnitTests_weightOfOperatorForQuorum is StakeRegistryUnitTe cheats.prank(address(registryCoordinator)); stakeRegistry.registerOperator(operator, defaultOperatorId, quorumNumbers); - // assert weight of the operator uint96 expectedWeight = 0; - for (uint i = 0; i < strategyParams.length; i++) { - expectedWeight += uint96(uint256(shares[i]) * uint256(strategyParams[i].multiplier) / WEIGHTING_DIVISOR); + for (uint256 i = 0; i < strategyParams.length; i++) { + expectedWeight += uint96( + uint256(shares[i]) * uint256(strategyParams[i].multiplier) / WEIGHTING_DIVISOR + ); } assertEq(stakeRegistry.weightOfOperatorForQuorum(quorumNumber, operator), expectedWeight); } @@ -1772,27 +2180,27 @@ contract StakeRegistryUnitTests_weightOfOperatorForQuorum is StakeRegistryUnitTe ) public { // 3 LST Strat multipliers, rETH, stETH, ETH uint96[] memory multipliers = new uint96[](3); - multipliers[0] = uint96(1070136092289993178); - multipliers[1] = uint96(1071364636818145808); - multipliers[2] = uint96(1000000000000000000); - - IStakeRegistry.StrategyParams[] memory strategyParams = new IStakeRegistry.StrategyParams[](3); - for (uint 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] + 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); + + IStakeRegistry.StrategyParams[] memory strategyParams = + new IStakeRegistry.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]); } // create a valid quorum cheats.prank(address(registryCoordinator)); uint8 quorumNumber = nextQuorum; - stakeRegistry.initializeQuorum(quorumNumber, 0 /* minimumStake */, strategyParams); + stakeRegistry.initializeQuorum(quorumNumber, 0, /* minimumStake */ strategyParams); // set the operator shares - for (uint i = 0; i < strategyParams.length; i++) { + for (uint256 i = 0; i < strategyParams.length; i++) { delegationMock.setOperatorShares(operator, strategyParams[i].strategy, shares[i]); } @@ -1802,11 +2210,12 @@ contract StakeRegistryUnitTests_weightOfOperatorForQuorum is StakeRegistryUnitTe cheats.prank(address(registryCoordinator)); stakeRegistry.registerOperator(operator, defaultOperatorId, quorumNumbers); - // assert weight of the operator uint96 expectedWeight = 0; - for (uint i = 0; i < strategyParams.length; i++) { - expectedWeight += uint96(uint256(shares[i]) * uint256(strategyParams[i].multiplier) / WEIGHTING_DIVISOR); + for (uint256 i = 0; i < strategyParams.length; i++) { + expectedWeight += uint96( + uint256(shares[i]) * uint256(strategyParams[i].multiplier) / WEIGHTING_DIVISOR + ); } assertEq(stakeRegistry.weightOfOperatorForQuorum(quorumNumber, operator), expectedWeight); }