Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: threshold for operator registration #23

Merged
merged 3 commits into from
Jan 23, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ contract SelfRegisterEd25519Middleware is
address owner
) internal initializer {
__BaseMiddleware_init(network, slashingWindow, vaultRegistry, operatorRegistry, operatorNetOptin, reader);
__SelfRegisterOperators_init("SelfRegisterEd25519Middleware");
__SelfRegisterOperators_init("SelfRegisterEd25519Middleware", 0);
__OwnableAccessManager_init(owner);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ contract SelfRegisterMiddleware is
address owner
) internal initializer {
__BaseMiddleware_init(network, slashingWindow, vaultRegistry, operatorRegistry, operatorNetOptIn, reader);
__SelfRegisterOperators_init("SelfRegisterMiddleware");
__SelfRegisterOperators_init("SelfRegisterMiddleware", 0);
__OwnableAccessManager_init(owner);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ contract SelfRegisterSqrtTaskMiddleware is
INetworkRegistry(networkRegistry).registerNetwork();
__BaseMiddleware_init(address(this), slashingWindow, vaultRegistry, operatorRegistry, operatorNetOptin, reader);
__OwnableAccessManager_init(owner);
__SelfRegisterOperators_init("SelfRegisterSqrtTaskMiddleware");
__SelfRegisterOperators_init("SelfRegisterSqrtTaskMiddleware", 0);
}

function createTask(uint256 value, address validator) external returns (uint256 taskIndex) {
Expand Down
24 changes: 8 additions & 16 deletions src/extensions/operators/ForcePauseSelfRegisterOperators.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ abstract contract ForcePauseSelfRegisterOperators is SelfRegisterOperators, IFor
function forcePauseOperator(
address operator
) external checkAccess {
ForcePauseSelfRegisterOperatorsStorage storage $ = _getForcePauseStorage();
$.forcePaused[operator] = true;
_getForcePauseStorage().forcePaused[operator] = true;
if (_operatorWasActiveAt(_now() + 1, operator)) {
_pauseOperatorImpl(operator);
}
Expand All @@ -51,8 +50,7 @@ abstract contract ForcePauseSelfRegisterOperators is SelfRegisterOperators, IFor
function forceUnpauseOperator(
address operator
) external checkAccess {
ForcePauseSelfRegisterOperatorsStorage storage $ = _getForcePauseStorage();
$.forcePaused[operator] = false;
_getForcePauseStorage().forcePaused[operator] = false;
if (!_isOperatorRegistered(operator)) {
return;
}
Expand All @@ -72,8 +70,7 @@ abstract contract ForcePauseSelfRegisterOperators is SelfRegisterOperators, IFor
* @inheritdoc IForcePauseSelfRegisterOperators
*/
function forcePauseOperatorVault(address operator, address vault) external checkAccess {
ForcePauseSelfRegisterOperatorsStorage storage $ = _getForcePauseStorage();
$.forcePausedVault[operator][vault] = true;
_getForcePauseStorage().forcePausedVault[operator][vault] = true;
if (_operatorVaultWasActiveAt(_now() + 1, operator, vault)) {
_pauseOperatorVaultImpl(operator, vault);
}
Expand All @@ -83,10 +80,8 @@ abstract contract ForcePauseSelfRegisterOperators is SelfRegisterOperators, IFor
* @inheritdoc IForcePauseSelfRegisterOperators
*/
function forceUnpauseOperatorVault(address operator, address vault) external checkAccess {
ForcePauseSelfRegisterOperatorsStorage storage $ = _getForcePauseStorage();
$.forcePausedVault[operator][vault] = false;
VaultManagerStorage storage s = _getVaultManagerStorage();
if (!s._vaultOperator.contains(vault)) {
_getForcePauseStorage().forcePausedVault[operator][vault] = false;
if (!_getVaultManagerStorage()._vaultOperator.contains(vault)) {
return;
}
_unpauseOperatorVaultImpl(operator, vault);
Expand All @@ -107,8 +102,7 @@ abstract contract ForcePauseSelfRegisterOperators is SelfRegisterOperators, IFor
address operator
) internal virtual override {
super._beforeUnpauseOperator(operator);
ForcePauseSelfRegisterOperatorsStorage storage $ = _getForcePauseStorage();
if ($.forcePaused[operator]) revert OperatorForcePaused();
if (_operatorForcePaused(operator)) revert OperatorForcePaused();
}

/**
Expand Down Expand Up @@ -145,12 +139,10 @@ abstract contract ForcePauseSelfRegisterOperators is SelfRegisterOperators, IFor
function _operatorForcePaused(
address operator
) private view returns (bool) {
ForcePauseSelfRegisterOperatorsStorage storage $ = _getForcePauseStorage();
return $.forcePaused[operator];
return _getForcePauseStorage().forcePaused[operator];
}

function _operatorVaultForcePaused(address operator, address vault) private view returns (bool) {
ForcePauseSelfRegisterOperatorsStorage storage $ = _getForcePauseStorage();
return $.forcePausedVault[operator][vault];
return _getForcePauseStorage().forcePausedVault[operator][vault];
}
}
97 changes: 94 additions & 3 deletions src/extensions/operators/SelfRegisterOperators.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {SigManager} from "../../managers/extendable/SigManager.sol";
import {EIP712Upgradeable} from "@openzeppelin/contracts-upgradeable/utils/cryptography/EIP712Upgradeable.sol";
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import {ISelfRegisterOperators} from "../../interfaces/extensions/operators/ISelfRegisterOperators.sol";
import {PauseableEnumerableSet} from "../../libraries/PauseableEnumerableSet.sol";

/**
* @title SelfRegisterOperators
Expand All @@ -14,6 +15,8 @@ import {ISelfRegisterOperators} from "../../interfaces/extensions/operators/ISel
* @dev CAUTION: If activeOperators functionality is needed, use ApprovalRegisterOperators instead to prevent DOS attacks
*/
abstract contract SelfRegisterOperators is BaseOperators, SigManager, EIP712Upgradeable, ISelfRegisterOperators {
using PauseableEnumerableSet for PauseableEnumerableSet.AddressSet;

uint64 public constant SelfRegisterOperators_VERSION = 1;

// EIP-712 TypeHash constants
Expand All @@ -36,6 +39,7 @@ abstract contract SelfRegisterOperators is BaseOperators, SigManager, EIP712Upgr

struct SelfRegisterOperatorsStorage {
mapping(address => uint256) nonces;
uint256 minPowerThreshold;
}

// keccak256(abi.encode(uint256(keccak256("symbiotic.storage.SelfRegisterOperators")) - 1)) & ~bytes32(uint256(0xff))
Expand All @@ -55,14 +59,17 @@ abstract contract SelfRegisterOperators is BaseOperators, SigManager, EIP712Upgr
return _getSelfRegisterOperatorsStorage().nonces[operator];
}

function minPowerThreshold() external view returns (uint256) {
return _getSelfRegisterOperatorsStorage().minPowerThreshold;
}

/**
* @notice Initializes the contract with EIP712 domain separator
* @param name The name to use for the EIP712 domain separator
*/
function __SelfRegisterOperators_init(
string memory name
) internal onlyInitializing {
function __SelfRegisterOperators_init(string memory name, uint256 minPowerThreshold) internal onlyInitializing {
__EIP712_init(name, "1");
_getSelfRegisterOperatorsStorage().minPowerThreshold = minPowerThreshold;
}

/**
Expand Down Expand Up @@ -265,6 +272,62 @@ abstract contract SelfRegisterOperators is BaseOperators, SigManager, EIP712Upgr
_unpauseOperatorVaultImpl(operator, vault);
}

/**
* @notice Updates the minimum power threshold for operators, be careful, this will allow to kick operators below the threshold
* @param minPowerThreshold The new minimum power threshold
*/
function updatePowerThreshold(
uint256 minPowerThreshold
) external checkAccess {
_getSelfRegisterOperatorsStorage().minPowerThreshold = minPowerThreshold;
}

/**
* @notice Attempts to kick an operator if they are below the power threshold
* @dev Will pause the operator if they are active, or unregister them if they are inactive
* @param operator The address of the operator to try kicking
*/
function tryKickOperator(
address operator
) public {
if (!_isOperatorRegistered(operator)) {
revert OperatorNotRegistered();
}

if (!_isOperatorBelowPowerThreshold(operator, address(0))) {
revert OperatorAbovePowerThreshold();
}

if (_operatorWasActiveAt(_now(), operator)) {
_pauseOperatorImpl(operator);
return;
}

if (_getOperatorManagerStorage()._operators.checkUnregister(_now(), _SLASHING_WINDOW(), operator)) {
_unregisterOperatorImpl(operator);
}
}

/**
* @notice Attempts to kick an operator if they are below the power threshold
* @dev Will pause the operator if they are active, or unregister them if they are inactive
* @param operator The address of the operator to try kicking
*/
function tryKickOperatorVault(address operator, address vault) public {
if (!_isOperatorBelowPowerThreshold(operator, address(0))) {
revert OperatorAbovePowerThreshold();
}

if (_operatorVaultWasActiveAt(_now(), operator, vault)) {
_pauseOperatorVaultImpl(operator, vault);
return;
}

if (_getVaultManagerStorage()._operatorVaults[operator].checkUnregister(_now(), _SLASHING_WINDOW(), vault)) {
_unregisterOperatorVaultImpl(operator, vault);
}
}

/**
* @notice Verifies a key signature
* @param operator The address of the operator
Expand All @@ -288,4 +351,32 @@ abstract contract SelfRegisterOperators is BaseOperators, SigManager, EIP712Upgr
revert InvalidSignature();
}
}

function _beforeRegisterOperator(address operator, bytes memory key, address vault) internal virtual override {
super._beforeRegisterOperator(operator, key, vault);
_checkOperatorPowerThreshold(operator, vault);
}

function _beforeUnpauseOperator(
address operator
) internal virtual override {
super._beforeUnpauseOperator(operator);
_checkOperatorPowerThreshold(operator, address(0));
}

function _checkOperatorPowerThreshold(address operator, address vault) private view {
if (_isOperatorBelowPowerThreshold(operator, vault)) {
revert OperatorPowerBelowThreshold();
}
}

function _isOperatorBelowPowerThreshold(address operator, address vault) private view returns (bool) {
address[] memory _vaults = _activeOperatorVaults(operator);
address[] memory vaults = new address[](1);
vaults[0] = vault;
uint160[] memory _subnetworks = _activeSubnetworks();
uint256 power = _getOperatorPower(operator, _vaults, _subnetworks);
power += _getOperatorPower(operator, vaults, _subnetworks);
return power < _getSelfRegisterOperatorsStorage().minPowerThreshold;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ pragma solidity ^0.8.25;
*/
interface ISelfRegisterOperators {
error InvalidSignature();

error OperatorPowerBelowThreshold();
error OperatorAbovePowerThreshold();
/**
* @notice Returns the nonce for an operator address
* @param operator The operator address to check
* @return The current nonce value
*/

function nonces(
address operator
) external view returns (uint256);
Expand Down
Loading