diff --git a/lib/core b/lib/core index 2a5f6f0..feb15ec 160000 --- a/lib/core +++ b/lib/core @@ -1 +1 @@ -Subproject commit 2a5f6f0fcee9a8d0ace03c38c77a352c5e5f95ae +Subproject commit feb15ec0b55e30b56b9595a8b9d8f179f173bb76 diff --git a/src/examples/self-register-network/SelfRegisterEd25519Middleware.sol b/src/examples/self-register-network/SelfRegisterEd25519Middleware.sol index 8f64090..cdf77f0 100644 --- a/src/examples/self-register-network/SelfRegisterEd25519Middleware.sol +++ b/src/examples/self-register-network/SelfRegisterEd25519Middleware.sol @@ -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); } } diff --git a/src/examples/self-register-network/SelfRegisterMiddleware.sol b/src/examples/self-register-network/SelfRegisterMiddleware.sol index d205782..ef3cedf 100644 --- a/src/examples/self-register-network/SelfRegisterMiddleware.sol +++ b/src/examples/self-register-network/SelfRegisterMiddleware.sol @@ -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); } } diff --git a/src/examples/sqrt-task-network/SelfRegisterSqrtTaskMiddleware.sol b/src/examples/sqrt-task-network/SelfRegisterSqrtTaskMiddleware.sol index ae6ed35..0874c9f 100644 --- a/src/examples/sqrt-task-network/SelfRegisterSqrtTaskMiddleware.sol +++ b/src/examples/sqrt-task-network/SelfRegisterSqrtTaskMiddleware.sol @@ -85,7 +85,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) { diff --git a/src/extensions/operators/ApprovalRegisterOperators.sol b/src/extensions/operators/ApprovalRegisterOperators.sol deleted file mode 100644 index dda290e..0000000 --- a/src/extensions/operators/ApprovalRegisterOperators.sol +++ /dev/null @@ -1,110 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -import {SelfRegisterOperators} from "./SelfRegisterOperators.sol"; -import {IApprovalRegisterOperators} from "../../interfaces/extensions/operators/IApprovalRegisterOperators.sol"; -/** - * @title ApprovalRegisterOperators - * @notice Extends SelfRegisterOperators to add approval-based registration - */ - -abstract contract ApprovalRegisterOperators is SelfRegisterOperators, IApprovalRegisterOperators { - uint64 public constant ApprovalRegisterOperators_VERSION = 1; - - struct ApprovalRegisterOperatorsStorage { - RegistrationRequest[] requests; - } - - // keccak256(abi.encode(uint256(keccak256("symbiotic.storage.ApprovalRegisterOperators")) - 1)) & ~bytes32(uint256(0xff)) - bytes32 private constant ApprovalRegisterOperators_STORAGE_LOCATION = - 0x8d3c0d900c3fcfbc53470fac03a90d5cf6aa7b77c3f1ed10e6c6bd4d192eaf00; - - function _getApprovalRegisterOperatorsStorage() private pure returns (ApprovalRegisterOperatorsStorage storage $) { - bytes32 location = ApprovalRegisterOperators_STORAGE_LOCATION; - assembly { - $.slot := location - } - } - - /** - * @inheritdoc IApprovalRegisterOperators - */ - function getRegistrationRequestCount() public view returns (uint256) { - return _getApprovalRegisterOperatorsStorage().requests.length; - } - - /** - * @inheritdoc IApprovalRegisterOperators - */ - function getRegistrationRequest( - uint256 index - ) public view returns (RegistrationRequest memory) { - return _getApprovalRegisterOperatorsStorage().requests[index]; - } - - /** - * @inheritdoc IApprovalRegisterOperators - */ - function registerOperator( - uint256 requestIndex - ) external checkAccess { - RegistrationRequest memory request = getRegistrationRequest(requestIndex); - _registerOperatorImpl(request.operator, request.key, request.vault); - ApprovalRegisterOperatorsStorage storage $ = _getApprovalRegisterOperatorsStorage(); - uint256 lastIndex = $.requests.length - 1; - if (requestIndex != lastIndex) { - $.requests[requestIndex] = $.requests[lastIndex]; - } - $.requests.pop(); - } - - /** - * @notice Override to prevent direct registration - */ - function registerOperator(bytes memory key, address vault, bytes memory signature) external virtual override { - revert DirectRegistrationNotAllowed(); - } - - /** - * @notice Override to prevent direct registration - */ - function registerOperator( - address operator, - bytes memory key, - address vault, - bytes memory signature, - bytes memory keySignature - ) public virtual override { - revert DirectRegistrationNotAllowed(); - } - - /** - * @inheritdoc IApprovalRegisterOperators - */ - function requestRegisterOperator(bytes memory key, address vault, bytes memory signature) external { - _verifyKey(msg.sender, key, signature); - ApprovalRegisterOperatorsStorage storage $ = _getApprovalRegisterOperatorsStorage(); - $.requests.push(RegistrationRequest({operator: msg.sender, vault: vault, key: key})); - } - - /** - * @inheritdoc IApprovalRegisterOperators - */ - function requestRegisterOperator( - address operator, - bytes memory key, - address vault, - bytes memory signature, - bytes memory keySignature - ) public { - SelfRegisterOperatorsStorage storage s = _getSelfRegisterOperatorsStorage(); - _verifyEIP712( - operator, - keccak256(abi.encode(REGISTER_OPERATOR_TYPEHASH, operator, keccak256(key), vault, s.nonces[operator]++)), - signature - ); - _verifyKey(operator, key, keySignature); - ApprovalRegisterOperatorsStorage storage $ = _getApprovalRegisterOperatorsStorage(); - $.requests.push(RegistrationRequest({operator: operator, vault: vault, key: key})); - } -} diff --git a/src/extensions/operators/ForcePauseApprovalRegisterOperators.sol b/src/extensions/operators/ForcePauseApprovalRegisterOperators.sol deleted file mode 100644 index 5ec1e29..0000000 --- a/src/extensions/operators/ForcePauseApprovalRegisterOperators.sol +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -import {ApprovalRegisterOperators} from "./ApprovalRegisterOperators.sol"; -import {SelfRegisterOperators} from "./SelfRegisterOperators.sol"; -import {ForcePauseSelfRegisterOperators} from "./ForcePauseSelfRegisterOperators.sol"; -import {BaseOperators} from "./BaseOperators.sol"; -/** - * @title ForcePauseSelfRegisterOperators - * @notice Extension of SelfRegisterOperators that allows authorized addresses to forcefully pause operators - * @dev Implements force pause functionality and prevents unpausing of force-paused operators - */ - -abstract contract ForcePauseApprovalRegisterOperators is ForcePauseSelfRegisterOperators, ApprovalRegisterOperators { - uint64 public constant ForcePauseApprovalRegisterOperators_VERSION = 1; - - function registerOperator( - bytes memory key, - address vault, - bytes memory signature - ) external override(ApprovalRegisterOperators, SelfRegisterOperators) { - revert DirectRegistrationNotAllowed(); - } - - // Override the registerOperator function to resolve ambiguity - function registerOperator( - address operator, - bytes memory key, - address vault, - bytes memory signature, - bytes memory keySignature - ) public override(ApprovalRegisterOperators, SelfRegisterOperators) { - revert DirectRegistrationNotAllowed(); - } - - function _beforeUnpauseOperator( - address operator - ) internal virtual override(ForcePauseSelfRegisterOperators, BaseOperators) { - super._beforeUnpauseOperator(operator); - } - - function _beforeUnpauseOperatorVault( - address operator, - address vault - ) internal virtual override(ForcePauseSelfRegisterOperators, BaseOperators) { - super._beforeUnpauseOperatorVault(operator, vault); - } - - function _beforeUnregisterOperator( - address operator - ) internal virtual override(ForcePauseSelfRegisterOperators, BaseOperators) { - super._beforeUnregisterOperator(operator); - } - - function _beforeUnregisterOperatorVault( - address operator, - address vault - ) internal virtual override(BaseOperators, ForcePauseSelfRegisterOperators) { - super._beforeUnregisterOperatorVault(operator, vault); - } -} diff --git a/src/extensions/operators/SelfRegisterOperators.sol b/src/extensions/operators/SelfRegisterOperators.sol index 385bd7d..ea7d4f9 100644 --- a/src/extensions/operators/SelfRegisterOperators.sol +++ b/src/extensions/operators/SelfRegisterOperators.sol @@ -35,6 +35,7 @@ abstract contract SelfRegisterOperators is BaseOperators, SigManager, EIP712Upgr keccak256("UnpauseOperatorVault(address operator,address vault,uint256 nonce)"); struct SelfRegisterOperatorsStorage { + uint256 minPower; mapping(address => uint256) nonces; } @@ -49,20 +50,21 @@ abstract contract SelfRegisterOperators is BaseOperators, SigManager, EIP712Upgr } } - function nonces( - address operator - ) public view returns (uint256) { - return _getSelfRegisterOperatorsStorage().nonces[operator]; - } - /** - * @notice Initializes the contract with EIP712 domain separator + * @notice Initializes the contract with EIP712 domain separator and minimum power threshold * @param name The name to use for the EIP712 domain separator + * @param _minPower The minimum power threshold */ - function __SelfRegisterOperators_init( - string memory name - ) internal onlyInitializing { + function __SelfRegisterOperators_init(string memory name, uint256 _minPower) internal onlyInitializing { __EIP712_init(name, "1"); + SelfRegisterOperatorsStorage storage $ = _getSelfRegisterOperatorsStorage(); + $.minPower = _minPower; + } + + function nonces( + address operator + ) public view returns (uint256) { + return _getSelfRegisterOperatorsStorage().nonces[operator]; } /** @@ -70,6 +72,7 @@ abstract contract SelfRegisterOperators is BaseOperators, SigManager, EIP712Upgr */ function registerOperator(bytes memory key, address vault, bytes memory signature) external virtual { _verifyKey(msg.sender, key, signature); + _checkMinPower(msg.sender, vault); _registerOperatorImpl(msg.sender, key, vault); } @@ -84,6 +87,7 @@ abstract contract SelfRegisterOperators is BaseOperators, SigManager, EIP712Upgr bytes memory keySignature ) public virtual { _verifyKey(operator, key, keySignature); + _checkMinPower(operator, vault); SelfRegisterOperatorsStorage storage $ = _getSelfRegisterOperatorsStorage(); _verifyEIP712( operator, @@ -265,6 +269,21 @@ abstract contract SelfRegisterOperators is BaseOperators, SigManager, EIP712Upgr _unpauseOperatorVaultImpl(operator, vault); } + function _checkMinPower(address operator, address vault) internal view { + SelfRegisterOperatorsStorage storage $ = _getSelfRegisterOperatorsStorage(); + address[] memory vaults = _activeVaults(); + uint160[] memory subnetworks = _activeSubnetworks(); + uint256 power = _getOperatorPower(operator, vaults, subnetworks); + if (address(vault) != address(0)) { + vaults = new address[](1); + vaults[0] = vault; + power += _getOperatorPower(operator, vaults, subnetworks); + } + if (power < $.minPower) { + revert NotEnoughPower(); + } + } + /** * @notice Verifies a key signature * @param operator The address of the operator diff --git a/src/interfaces/extensions/operators/IApprovalRegisterOperators.sol b/src/interfaces/extensions/operators/IApprovalRegisterOperators.sol deleted file mode 100644 index 5aa416d..0000000 --- a/src/interfaces/extensions/operators/IApprovalRegisterOperators.sol +++ /dev/null @@ -1,63 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.25; - -/** - * @title IApprovalRegisterOperators - * @notice Interface for approval-based operator registration - */ -interface IApprovalRegisterOperators { - struct RegistrationRequest { - address operator; - address vault; - bytes key; - } - - error DirectRegistrationNotAllowed(); - - /** - * @notice Get the total number of pending registration requests - * @return The number of requests - */ - function getRegistrationRequestCount() external view returns (uint256); - - /** - * @notice Get a specific registration request by index - * @param index The index of the request to retrieve - * @return The registration request details - */ - function getRegistrationRequest( - uint256 index - ) external view returns (RegistrationRequest memory); - - /** - * @notice Register an operator based on a pending request - * @param requestIndex The index of the request to register - */ - function registerOperator( - uint256 requestIndex - ) external; - - /** - * @notice Request registration as an operator - * @param key The operator's public key - * @param vault Optional vault address to associate - * @param signature Signature proving ownership of the key - */ - function requestRegisterOperator(bytes memory key, address vault, bytes memory signature) external; - - /** - * @notice Request registration on behalf of another operator - * @param operator The address of the operator to register - * @param key The operator's public key - * @param vault Optional vault address to associate - * @param signature EIP712 signature authorizing registration - * @param keySignature Signature proving ownership of the key - */ - function requestRegisterOperator( - address operator, - bytes memory key, - address vault, - bytes memory signature, - bytes memory keySignature - ) external; -} diff --git a/src/interfaces/extensions/operators/ISelfRegisterOperators.sol b/src/interfaces/extensions/operators/ISelfRegisterOperators.sol index 9a6fe8b..c55c018 100644 --- a/src/interfaces/extensions/operators/ISelfRegisterOperators.sol +++ b/src/interfaces/extensions/operators/ISelfRegisterOperators.sol @@ -7,6 +7,7 @@ pragma solidity ^0.8.25; */ interface ISelfRegisterOperators { error InvalidSignature(); + error NotEnoughPower(); /** * @notice Returns the nonce for an operator address diff --git a/src/managers/VaultManager.sol b/src/managers/VaultManager.sol index 0a5cc9f..d57567d 100644 --- a/src/managers/VaultManager.sol +++ b/src/managers/VaultManager.sol @@ -65,7 +65,8 @@ abstract contract VaultManager is NetworkStorage, SlashingWindowStorage, Capture enum DelegatorType { FULL_RESTAKE, NETWORK_RESTAKE, - OPERATOR_SPECIFIC + OPERATOR_SPECIFIC, + OPERATOR_NETWORK_SPECIFIC } // keccak256(abi.encode(uint256(keccak256("symbiotic.storage.VaultManager")) - 1)) & ~bytes32(uint256(0xff)) @@ -733,8 +734,10 @@ abstract contract VaultManager is NetworkStorage, SlashingWindowStorage, Capture function _validateOperatorVault(address operator, address vault) internal view { address delegator = IVault(vault).delegator(); if ( - IEntity(delegator).TYPE() != uint64(DelegatorType.OPERATOR_SPECIFIC) - || IOperatorSpecificDelegator(delegator).operator() != operator + ( + IEntity(delegator).TYPE() != uint64(DelegatorType.OPERATOR_SPECIFIC) + && IEntity(delegator).TYPE() != uint64(DelegatorType.OPERATOR_NETWORK_SPECIFIC) + ) || IOperatorSpecificDelegator(delegator).operator() != operator ) { revert NotOperatorSpecificVault(); }