From f5ba67a772ed07d7a4791a001c7d7daf05ce7124 Mon Sep 17 00:00:00 2001 From: QUAQ Date: Thu, 25 Apr 2024 22:58:54 -0500 Subject: [PATCH 1/9] feat: rereg delay --- src/RegistryCoordinator.sol | 7 +++++++ src/RegistryCoordinatorStorage.sol | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 19367892..dc4bc9fa 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -368,6 +368,7 @@ contract RegistryCoordinator is operator: operator, quorumNumbers: quorumNumbers }); + lastEjectionTimestamp[operator] = block.timestamp; } /******************************************************************************* @@ -423,6 +424,10 @@ contract RegistryCoordinator is _setEjector(_ejector); } + function setReregistrationDelay(uint256 _reregistrationDelay) external onlyOwner { + reregistrationDelay = _reregistrationDelay; + } + /******************************************************************************* INTERNAL FUNCTIONS *******************************************************************************/ @@ -457,6 +462,8 @@ contract RegistryCoordinator is require(quorumsToAdd.noBitsInCommon(currentBitmap), "RegistryCoordinator._registerOperator: operator already registered for some quorums being registered for"); uint192 newBitmap = uint192(currentBitmap.plus(quorumsToAdd)); + require(lastEjectionTimestamp[operator] + reregistrationDelay < block.timestamp, "RegistryCoordinator._registerOperator: operator cannot reregister yet"); + /** * Update operator's bitmap, socket, and status. Only update operatorInfo if needed: * if we're `REGISTERED`, the operatorId and status are already correct. diff --git a/src/RegistryCoordinatorStorage.sol b/src/RegistryCoordinatorStorage.sol index e8c42850..aeb660b9 100644 --- a/src/RegistryCoordinatorStorage.sol +++ b/src/RegistryCoordinatorStorage.sol @@ -64,6 +64,10 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { /// @notice the address of the entity allowed to eject operators from the AVS address public ejector; + mapping(address => uint256) public lastEjectionTimestamp; + + uint256 public reregistrationDelay; + constructor( IServiceManager _serviceManager, IStakeRegistry _stakeRegistry, @@ -78,5 +82,5 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { // storage gap for upgradeability // slither-disable-next-line shadowing-state - uint256[41] private __GAP; + uint256[39] private __GAP; } From a71d3b2b780fe66721415367885824718165cec8 Mon Sep 17 00:00:00 2001 From: QUAQ Date: Fri, 26 Apr 2024 11:17:37 -0500 Subject: [PATCH 2/9] test: fix tests --- test/integration/User.t.sol | 2 ++ test/unit/EjectionManagerUnit.t.sol | 2 ++ 2 files changed, 4 insertions(+) diff --git a/test/integration/User.t.sol b/test/integration/User.t.sol index a94e5f6e..fbb55198 100644 --- a/test/integration/User.t.sol +++ b/test/integration/User.t.sol @@ -117,6 +117,7 @@ contract User is Test { function registerOperator(bytes calldata quorums) public createSnapshot virtual returns (bytes32) { _log("registerOperator", quorums); + vm.warp(block.timestamp + 1); registryCoordinator.registerOperator({ quorumNumbers: quorums, socket: NAME, @@ -208,6 +209,7 @@ contract User is Test { expiry: expiry }); + vm.warp(block.timestamp + 1); registryCoordinator.registerOperatorWithChurn({ quorumNumbers: allQuorums, socket: NAME, diff --git a/test/unit/EjectionManagerUnit.t.sol b/test/unit/EjectionManagerUnit.t.sol index 899874f0..aca3dae9 100644 --- a/test/unit/EjectionManagerUnit.t.sol +++ b/test/unit/EjectionManagerUnit.t.sol @@ -251,6 +251,8 @@ contract EjectionManagerUnitTests is MockAVSDeployer { testEjectOperators_MultipleOperatorInsideRatelimit(); + vm.warp(block.timestamp + 1); + _registerOperaters(operatorsToEject, stake); vm.warp(block.timestamp + ratelimitWindow); From 1dc136bfc6cf32d7ec26eaf4a153a95e0fc4f7f1 Mon Sep 17 00:00:00 2001 From: QUAQ Date: Fri, 26 Apr 2024 11:21:39 -0500 Subject: [PATCH 3/9] chore: natspec --- src/RegistryCoordinator.sol | 7 +++++++ src/RegistryCoordinatorStorage.sol | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index dc4bc9fa..6b19cd04 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -424,6 +424,12 @@ contract RegistryCoordinator is _setEjector(_ejector); } + /** + * @notice Sets the reregistration delay, which is the time an operator must wait after + * ejection before registering for any quorum + * @param _reregistrationDelay the new reregistration delay + * @dev only callable by the owner + */ function setReregistrationDelay(uint256 _reregistrationDelay) external onlyOwner { reregistrationDelay = _reregistrationDelay; } @@ -462,6 +468,7 @@ contract RegistryCoordinator is require(quorumsToAdd.noBitsInCommon(currentBitmap), "RegistryCoordinator._registerOperator: operator already registered for some quorums being registered for"); uint192 newBitmap = uint192(currentBitmap.plus(quorumsToAdd)); + // Check that the operator can reregister if ejected require(lastEjectionTimestamp[operator] + reregistrationDelay < block.timestamp, "RegistryCoordinator._registerOperator: operator cannot reregister yet"); /** diff --git a/src/RegistryCoordinatorStorage.sol b/src/RegistryCoordinatorStorage.sol index aeb660b9..57b4668c 100644 --- a/src/RegistryCoordinatorStorage.sol +++ b/src/RegistryCoordinatorStorage.sol @@ -64,8 +64,9 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { /// @notice the address of the entity allowed to eject operators from the AVS address public ejector; + /// @notice the last timestamp an operator was ejected mapping(address => uint256) public lastEjectionTimestamp; - + /// @notice the delay before an operator can reregister after being ejected uint256 public reregistrationDelay; constructor( From 03d40e169dd59d24c07aabf6d6460824a8ec790c Mon Sep 17 00:00:00 2001 From: QUAQ Date: Fri, 26 Apr 2024 11:55:18 -0500 Subject: [PATCH 4/9] test: unit --- test/unit/RegistryCoordinatorUnit.t.sol | 56 +++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index b906b8be..55e0835d 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -988,6 +988,62 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist registryCoordinator._deregisterOperatorExternal(defaultOperator, incorrectQuorum); } + function test_reregisterOperator_revert_reregistrationDelay() public { + uint256 reregistrationDelay = 1 days; + cheats.warp(block.timestamp + reregistrationDelay); + cheats.prank(registryCoordinatorOwner); + registryCoordinator.setReregistrationDelay(reregistrationDelay); + + ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; + uint32 registrationBlockNumber = 100; + uint32 reregistrationBlockNumber = 200; + + bytes memory quorumNumbers = new bytes(1); + quorumNumbers[0] = bytes1(defaultQuorumNumber); + + _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); + + cheats.prank(defaultOperator); + cheats.roll(registrationBlockNumber); + registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + + cheats.prank(ejector); + registryCoordinator.ejectOperator(defaultOperator, quorumNumbers); + + cheats.prank(defaultOperator); + cheats.roll(reregistrationBlockNumber); + cheats.expectRevert("RegistryCoordinator._registerOperator: operator cannot reregister yet"); + registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + } + + function test_reregisterOperator_reregistrationDelay() public { + uint256 reregistrationDelay = 1 days; + cheats.warp(block.timestamp + reregistrationDelay); + cheats.prank(registryCoordinatorOwner); + registryCoordinator.setReregistrationDelay(reregistrationDelay); + + ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; + uint32 registrationBlockNumber = 100; + uint32 reregistrationBlockNumber = 200; + + bytes memory quorumNumbers = new bytes(1); + quorumNumbers[0] = bytes1(defaultQuorumNumber); + + _setOperatorWeight(defaultOperator, uint8(quorumNumbers[0]), defaultStake); + + cheats.prank(defaultOperator); + cheats.roll(registrationBlockNumber); + registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + + cheats.prank(ejector); + registryCoordinator.ejectOperator(defaultOperator, quorumNumbers); + + cheats.prank(defaultOperator); + cheats.roll(reregistrationBlockNumber); + cheats.warp(block.timestamp + reregistrationDelay + 1); + registryCoordinator.registerOperator(quorumNumbers, defaultSocket, pubkeyRegistrationParams, emptySig); + } + // note: this is not possible to test, because there is no route to getting the operator registered for nonexistent quorums // function test_deregisterOperatorExternal_revert_nonexistentQuorums() public { From 2f6d7a5bb322a0e5b0b635a1c9bba1f70c13338d Mon Sep 17 00:00:00 2001 From: QUAQ Date: Fri, 26 Apr 2024 21:13:23 -0500 Subject: [PATCH 5/9] fix: grief --- src/RegistryCoordinator.sol | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 6b19cd04..79eb771f 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -364,11 +364,22 @@ contract RegistryCoordinator is address operator, bytes calldata quorumNumbers ) external onlyEjector { - _deregisterOperator({ - operator: operator, - quorumNumbers: quorumNumbers - }); lastEjectionTimestamp[operator] = block.timestamp; + + OperatorInfo storage operatorInfo = _operatorInfo[operator]; + bytes32 operatorId = operatorInfo.operatorId; + uint192 quorumsToRemove = uint192(BitmapUtils.orderedBytesArrayToBitmap(quorumNumbers, quorumCount)); + uint192 currentBitmap = _currentOperatorBitmap(operatorId); + if( + operatorInfo.status == OperatorStatus.REGISTERED && + !quorumsToRemove.isEmpty() && + quorumsToRemove.isSubsetOf(currentBitmap) + ){ + _deregisterOperator({ + operator: operator, + quorumNumbers: quorumNumbers + }); + } } /******************************************************************************* From b962174ecbee2534be393881aedebcd92c63cd65 Mon Sep 17 00:00:00 2001 From: QUAQ Date: Fri, 26 Apr 2024 21:14:13 -0500 Subject: [PATCH 6/9] refactor: ejection manager --- src/EjectionManager.sol | 33 ++++++++++++----------------- src/interfaces/IEjectionManager.sol | 6 +++--- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/EjectionManager.sol b/src/EjectionManager.sol index 78181063..4668c4c8 100644 --- a/src/EjectionManager.sol +++ b/src/EjectionManager.sol @@ -60,15 +60,12 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable{ /** * @notice Ejects operators from the AVSs RegistryCoordinator under a ratelimit * @param _operatorIds The ids of the operators 'j' to eject for each quorum 'i' - * @return ejectedOperatorsForQuorum The total number of operators ejected for each quorum 'i' - * @dev This function will eject as many operators as possible without reverting prioritizing operators at the lower index + * @dev This function will eject as many operators as possible prioritizing operators at the lower index * @dev The owner can eject operators without recording of stake ejection */ - function ejectOperators(bytes32[][] memory _operatorIds) external returns (uint32[] memory){ + function ejectOperators(bytes32[][] memory _operatorIds) external { require(isEjector[msg.sender] || msg.sender == owner(), "Ejector: Only owner or ejector can eject"); - uint32[] memory ejectedOperatorsForQuorum = new uint32[](_operatorIds.length); - for(uint i = 0; i < _operatorIds.length; ++i) { uint8 quorumNumber = uint8(i); @@ -76,7 +73,7 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable{ uint256 stakeForEjection; uint32 ejectedOperators; - bool broke; + bool ratelimitHit; for(uint8 j = 0; j < _operatorIds[i].length; ++j) { uint256 operatorStake = stakeRegistry.getCurrentStake(_operatorIds[i][j], quorumNumber); @@ -90,35 +87,31 @@ contract EjectionManager is IEjectionManager, OwnableUpgradeable{ timestamp: block.timestamp, stakeEjected: stakeForEjection })); - broke = true; + ratelimitHit = true; break; } - //try-catch used to prevent race condition of operator deregistering before ejection - try registryCoordinator.ejectOperator( + stakeForEjection += operatorStake; + ++ejectedOperators; + + registryCoordinator.ejectOperator( registryCoordinator.getOperatorFromId(_operatorIds[i][j]), abi.encodePacked(quorumNumber) - ) { - stakeForEjection += operatorStake; - ++ejectedOperators; - emit OperatorEjected(_operatorIds[i][j], quorumNumber); - } catch (bytes memory err) { - emit FailedOperatorEjection(_operatorIds[i][j], quorumNumber, err); - } + ); + + emit OperatorEjected(_operatorIds[i][j], quorumNumber); } //record the stake ejected if ejector and ratelimit enforced - if(!broke && isEjector[msg.sender]){ + if(!ratelimitHit && isEjector[msg.sender]){ stakeEjectedForQuorum[quorumNumber].push(StakeEjection({ timestamp: block.timestamp, stakeEjected: stakeForEjection })); } - ejectedOperatorsForQuorum[i] = ejectedOperators; + emit QuorumEjection(ejectedOperators, ratelimitHit); } - - return ejectedOperatorsForQuorum; } /** diff --git a/src/interfaces/IEjectionManager.sol b/src/interfaces/IEjectionManager.sol index 454d0e61..9a02991e 100644 --- a/src/interfaces/IEjectionManager.sol +++ b/src/interfaces/IEjectionManager.sol @@ -25,14 +25,14 @@ interface IEjectionManager { event QuorumEjectionParamsSet(uint8 quorumNumber, uint32 rateLimitWindow, uint16 ejectableStakePercent); ///@notice Emitted when an operator is ejected event OperatorEjected(bytes32 operatorId, uint8 quorumNumber); - ///@notice Emitted when an operator ejection fails - event FailedOperatorEjection(bytes32 operatorId, uint8 quorumNumber, bytes err); + ///@notice Emitted when operators are ejected for a quroum + event QuorumEjection(uint32 ejectedOperators, bool ratelimitHit); /** * @notice Ejects operators from the AVSs registryCoordinator under a ratelimit * @param _operatorIds The ids of the operators to eject for each quorum */ - function ejectOperators(bytes32[][] memory _operatorIds) external returns (uint32[] memory); + function ejectOperators(bytes32[][] memory _operatorIds) external; /** * @notice Sets the ratelimit parameters for a quorum From 271aad4705a123e4e6c17752db3c6831774e0a81 Mon Sep 17 00:00:00 2001 From: QUAQ Date: Fri, 26 Apr 2024 21:14:48 -0500 Subject: [PATCH 7/9] fix: units --- test/unit/EjectionManagerUnit.t.sol | 51 +++++------------------------ 1 file changed, 9 insertions(+), 42 deletions(-) diff --git a/test/unit/EjectionManagerUnit.t.sol b/test/unit/EjectionManagerUnit.t.sol index aca3dae9..7fcd4905 100644 --- a/test/unit/EjectionManagerUnit.t.sol +++ b/test/unit/EjectionManagerUnit.t.sol @@ -1,4 +1,5 @@ // SPDX-License-Identifier: BUSL-1.1 + pragma solidity ^0.8.12; import {EjectionManager} from "../../src/EjectionManager.sol"; @@ -87,11 +88,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } cheats.prank(ejector); - uint32[] memory ejectedOperatorsForQuorum = ejectionManager.ejectOperators(operatorIds); - - for(uint8 i = 0; i < numQuorums; i++) { - assertEq(ejectedOperatorsForQuorum[i], operatorsToEject); - } + ejectionManager.ejectOperators(operatorIds); assertEq(uint8(registryCoordinator.getOperatorStatus(defaultOperator)), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); } @@ -122,11 +119,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } cheats.prank(ejector); - uint32[] memory ejectedOperatorsForQuorum = ejectionManager.ejectOperators(operatorIds); - - for(uint8 i = 0; i < numQuorums; i++) { - assertEq(ejectedOperatorsForQuorum[i], operatorsToEject); - } + ejectionManager.ejectOperators(operatorIds); for(uint8 i = 0; i < operatorsToEject; i++) { assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); @@ -160,11 +153,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } cheats.prank(ejector); - uint32[] memory ejectedOperatorsForQuorum = ejectionManager.ejectOperators(operatorIds); - - for(uint8 i = 0; i < numQuorums; i++) { - assertEq(ejectedOperatorsForQuorum[i], operatorsCanEject); - } + ejectionManager.ejectOperators(operatorIds); for(uint8 i = 0; i < operatorsCanEject; i++) { assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); @@ -201,11 +190,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } cheats.prank(ejector); - uint32[] memory ejectedOperatorsForQuorum = ejectionManager.ejectOperators(operatorIds); - - for(uint8 i = 0; i < numQuorums; i++) { - assertEq(ejectedOperatorsForQuorum[i], operatorsToEject); - } + ejectionManager.ejectOperators(operatorIds); for(uint8 i = 0; i < operatorsToEject; i++) { assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); @@ -233,11 +218,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } cheats.prank(ejector); - ejectedOperatorsForQuorum = ejectionManager.ejectOperators(operatorIds); - - for(uint8 i = 0; i < numQuorums; i++) { - assertEq(ejectedOperatorsForQuorum[i], operatorsToEject); - } + ejectionManager.ejectOperators(operatorIds); for(uint8 i = 0; i < operatorsToEject; i++) { assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, operatorsToEject + i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); @@ -277,11 +258,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } cheats.prank(ejector); - uint32[] memory ejectedOperatorsForQuorum = ejectionManager.ejectOperators(operatorIds); - - for(uint8 i = 0; i < numQuorums; i++) { - assertEq(ejectedOperatorsForQuorum[i], operatorsToEject); - } + ejectionManager.ejectOperators(operatorIds); for(uint8 i = 0; i < operatorsToEject; i++) { assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); @@ -314,11 +291,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } cheats.prank(registryCoordinatorOwner); - uint32[] memory ejectedOperatorsForQuorum = ejectionManager.ejectOperators(operatorIds); - - for(uint8 i = 0; i < numQuorums; i++) { - assertEq(ejectedOperatorsForQuorum[i], operatorsToEject); - } + ejectionManager.ejectOperators(operatorIds); for(uint8 i = 0; i < operatorsToEject; i++) { assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); @@ -347,8 +320,6 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } for(uint8 i = 0; i < numQuorums; i++) { - //cheats.expectEmit(true, true, true, true, address(ejectionManager)); - //emit FailedOperatorEjection(operatorIds[i][0], i, abi.encodePacked("revert: RegistryCoordinator._deregisterOperator: operator is not registered")); for(uint8 j = 1; j < operatorsToEject; j++) { cheats.expectEmit(true, true, true, true, address(ejectionManager)); emit OperatorEjected(operatorIds[i][j], i); @@ -356,11 +327,7 @@ contract EjectionManagerUnitTests is MockAVSDeployer { } cheats.prank(ejector); - uint32[] memory ejectedOperatorsForQuorum = ejectionManager.ejectOperators(operatorIds); - - for(uint8 i = 0; i < numQuorums; i++) { - assertEq(ejectedOperatorsForQuorum[i], operatorsToEject - 1); - } + ejectionManager.ejectOperators(operatorIds); for(uint8 i = 0; i < operatorsToEject; i++) { assertEq(uint8(registryCoordinator.getOperatorStatus(_incrementAddress(defaultOperator, i))), uint8(IRegistryCoordinator.OperatorStatus.DEREGISTERED)); From 0e69039c7cb8a29ba29a3f7000140745217ff7f3 Mon Sep 17 00:00:00 2001 From: QUAQ Date: Fri, 26 Apr 2024 21:34:26 -0500 Subject: [PATCH 8/9] fix: name nit --- src/RegistryCoordinator.sol | 12 ++++++------ src/RegistryCoordinatorStorage.sol | 4 ++-- test/unit/RegistryCoordinatorUnit.t.sol | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index 79eb771f..bbf498f5 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -436,13 +436,13 @@ contract RegistryCoordinator is } /** - * @notice Sets the reregistration delay, which is the time an operator must wait after - * ejection before registering for any quorum - * @param _reregistrationDelay the new reregistration delay + * @notice Sets the ejection cooldown, which is the time an operator must wait in + * seconds afer ejection before registering for any quorum + * @param _ejectionCooldown the new ejection cooldown in seconds * @dev only callable by the owner */ - function setReregistrationDelay(uint256 _reregistrationDelay) external onlyOwner { - reregistrationDelay = _reregistrationDelay; + function setEjectionCooldown(uint256 _ejectionCooldown) external onlyOwner { + ejectionCooldown = _ejectionCooldown; } /******************************************************************************* @@ -480,7 +480,7 @@ contract RegistryCoordinator is uint192 newBitmap = uint192(currentBitmap.plus(quorumsToAdd)); // Check that the operator can reregister if ejected - require(lastEjectionTimestamp[operator] + reregistrationDelay < block.timestamp, "RegistryCoordinator._registerOperator: operator cannot reregister yet"); + require(lastEjectionTimestamp[operator] + ejectionCooldown < block.timestamp, "RegistryCoordinator._registerOperator: operator cannot reregister yet"); /** * Update operator's bitmap, socket, and status. Only update operatorInfo if needed: diff --git a/src/RegistryCoordinatorStorage.sol b/src/RegistryCoordinatorStorage.sol index 57b4668c..5451efb3 100644 --- a/src/RegistryCoordinatorStorage.sol +++ b/src/RegistryCoordinatorStorage.sol @@ -66,8 +66,8 @@ abstract contract RegistryCoordinatorStorage is IRegistryCoordinator { /// @notice the last timestamp an operator was ejected mapping(address => uint256) public lastEjectionTimestamp; - /// @notice the delay before an operator can reregister after being ejected - uint256 public reregistrationDelay; + /// @notice the delay in seconds before an operator can reregister after being ejected + uint256 public ejectionCooldown; constructor( IServiceManager _serviceManager, diff --git a/test/unit/RegistryCoordinatorUnit.t.sol b/test/unit/RegistryCoordinatorUnit.t.sol index 55e0835d..c262b0da 100644 --- a/test/unit/RegistryCoordinatorUnit.t.sol +++ b/test/unit/RegistryCoordinatorUnit.t.sol @@ -992,7 +992,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist uint256 reregistrationDelay = 1 days; cheats.warp(block.timestamp + reregistrationDelay); cheats.prank(registryCoordinatorOwner); - registryCoordinator.setReregistrationDelay(reregistrationDelay); + registryCoordinator.setEjectionCooldown(reregistrationDelay); ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; uint32 registrationBlockNumber = 100; @@ -1020,7 +1020,7 @@ contract RegistryCoordinatorUnitTests_DeregisterOperator_EjectOperator is Regist uint256 reregistrationDelay = 1 days; cheats.warp(block.timestamp + reregistrationDelay); cheats.prank(registryCoordinatorOwner); - registryCoordinator.setReregistrationDelay(reregistrationDelay); + registryCoordinator.setEjectionCooldown(reregistrationDelay); ISignatureUtils.SignatureWithSaltAndExpiry memory emptySig; uint32 registrationBlockNumber = 100; From 0bad4f386099897960ef4199ff83c9f53d4b51a1 Mon Sep 17 00:00:00 2001 From: QUAQ Date: Mon, 29 Apr 2024 16:37:38 -0400 Subject: [PATCH 9/9] docs: ejector dev tag --- src/RegistryCoordinator.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/src/RegistryCoordinator.sol b/src/RegistryCoordinator.sol index bbf498f5..4006d9f4 100644 --- a/src/RegistryCoordinator.sol +++ b/src/RegistryCoordinator.sol @@ -359,6 +359,7 @@ contract RegistryCoordinator is * @notice Forcibly deregisters an operator from one or more quorums * @param operator the operator to eject * @param quorumNumbers the quorum numbers to eject the operator from + * @dev possible race condition if prior to being ejected for a set of quorums the operator self deregisters from a subset */ function ejectOperator( address operator,