From 9c0f93c94d6ae3dd2e89a5e4faec6857ffafaced Mon Sep 17 00:00:00 2001 From: WillQ Date: Fri, 9 May 2025 10:17:43 +0800 Subject: [PATCH 1/4] fix: registry not deployed bug --- script/Deployments.s.sol | 13 ++++-- script/configs/deploy-test-config.json | 62 -------------------------- script/deploy.sh | 4 +- 3 files changed, 11 insertions(+), 68 deletions(-) delete mode 100644 script/configs/deploy-test-config.json diff --git a/script/Deployments.s.sol b/script/Deployments.s.sol index c8c1b71..c0ab390 100644 --- a/script/Deployments.s.sol +++ b/script/Deployments.s.sol @@ -70,6 +70,8 @@ contract Deploy is Script, Test { address public urc; address public implOwner; + uint256 public urcMinCollateral; + // Constant for admin storage slot bytes32 constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; @@ -302,7 +304,7 @@ contract Deploy is Script, Test { registry: urc, slasher: address(linglongSlasherInfo.proxy), allocationManager: allocationManager, - registrationMinCollateral: 0 + registrationMinCollateral: urcMinCollateral }); ProxyAdmin(eigenLayerMiddlewareInfo.admin).upgradeAndCall( ITransparentUpgradeableProxy(address(deployedContracts.eigenLayerMiddleware)), @@ -363,9 +365,9 @@ contract Deploy is Script, Test { vm.stopBroadcast(); deployEigenLayer(configFileName); - + vm.startBroadcast(); IRegistry.Config memory registryConfig = IRegistry.Config({ - minCollateralWei: 0.1 ether, + minCollateralWei: uint80(urcMinCollateral), fraudProofWindow: 7200, unregistrationDelay: 7200, slashWindow: 7200, @@ -376,6 +378,8 @@ contract Deploy is Script, Test { emit log_address(address(registry)); urc = address(registry); vm.serializeAddress(taiyiAddresses, "urc", address(registry)); + vm.serializeUint(taiyiAddresses, "urcMinCollateral", urcMinCollateral); + vm.stopBroadcast(); } function setupHoleskyAddresses() internal { @@ -391,7 +395,8 @@ contract Deploy is Script, Test { urc = 0x0000000000000000000000000000000000000000; } - function run(string memory configFileName) public { + function run(string memory configFileName, uint256 minCollateral) public { + urcMinCollateral = minCollateral; // Get deployer address from private key (uint256 proxyDeployerPrivateKey, uint256 implPrivateKey) = getPrivateKeys(); deployer = vm.addr(proxyDeployerPrivateKey); diff --git a/script/configs/deploy-test-config.json b/script/configs/deploy-test-config.json deleted file mode 100644 index a1d8223..0000000 --- a/script/configs/deploy-test-config.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "maintainer": "samlaf@eigenlabs.org", - "multisig_addresses": { - "operationsMultisig": "0xD8F3183DEF51A987222D845be228e0Bbb932C222", - "communityMultisig": "0xD8F3183DEF51A987222D845be228e0Bbb932C222", - "pauserMultisig": "0xD8F3183DEF51A987222D845be228e0Bbb932C222", - "executorMultisig": "0xD8F3183DEF51A987222D845be228e0Bbb932C222", - "timelock": "0xD8F3183DEF51A987222D845be228e0Bbb932C222" - }, - "strategies": [ - { - "token_address": "0x86A4F08103eade88adE0be164d7BDa8Fe166680d", - "token_symbol": "WETH", - "max_per_deposit": 115792089237316195423570985008687907853269984665640564039457584007913129639935, - "max_deposits": 115792089237316195423570985008687907853269984665640564039457584007913129639935 - } - ], - "strategyManager": { - "init_paused_status": 0, - "init_withdrawal_delay_blocks": 1 - }, - "eigenPod": { - "PARTIAL_WITHDRAWAL_FRAUD_PROOF_PERIOD_BLOCKS": 1, - "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": "32000000000" - }, - "eigenPodManager": { - "init_paused_status": 30 - }, - "delayedWithdrawalRouter": { - "init_paused_status": 0, - "init_withdrawal_delay_blocks": 1 - }, - "slasher": { - "init_paused_status": 0 - }, - "delegation": { - "withdrawal_delay_blocks": 900, - "init_paused_status": 0, - "init_withdrawal_delay_blocks": 1 - }, - "rewardsCoordinator": { - "init_paused_status": 0, - "CALCULATION_INTERVAL_SECONDS": 604800, - "MAX_REWARDS_DURATION": 6048000, - "MAX_RETROACTIVE_LENGTH": 7776000, - "MAX_FUTURE_LENGTH": 2592000, - "GENESIS_REWARDS_TIMESTAMP": 1710979200, - "rewards_updater_address": "0x18a0f92Ad9645385E8A8f3db7d0f6CF7aBBb0aD4", - "activation_delay": 7200, - "calculation_interval_seconds": 604800, - "global_operator_commission_bips": 1000, - "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, - "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 - }, - "allocationManager": { - "init_paused_status": 0, - "DEALLOCATION_DELAY": 900, - "ALLOCATION_CONFIGURATION_DELAY": 1 - }, - "ethPOSDepositAddress": "0x4242424242424242424242424242424242424242", - "semver": "v0.0.0" - } diff --git a/script/deploy.sh b/script/deploy.sh index 39d3bb8..8792641 100644 --- a/script/deploy.sh +++ b/script/deploy.sh @@ -15,5 +15,5 @@ fi export FOUNDRY_PROFILE=ci forge script --rpc-url $EXECUTION_URL \ -vvvv --broadcast ./script/Deployments.s.sol:Deploy \ ---sig "run(string memory configFile)" \ --- eigenlayer-deploy-config-devnet.json +--sig "run(string memory configFile, uint256 minCollateral)" \ +-- eigenlayer-deploy-config-devnet.json 0.1ether From b3fafb4b39130ebdac6ec1241b87431971917e7b Mon Sep 17 00:00:00 2001 From: WillQ Date: Fri, 9 May 2025 21:43:32 +0800 Subject: [PATCH 2/4] update OperatorSetIdLib --- script/SetupContract.s.sol | 4 +- script/configs/deploy-test-config.json | 62 ++ src/eigenlayer-avs/EigenLayerMiddleware.sol | 20 +- .../EigenLayerRewardsHandler.sol | 5 +- src/interfaces/ILinglongChallenger.sol | 4 +- src/interfaces/ILinglongSlasher.sol | 4 +- src/interfaces/ITaiyiRegistryCoordinator.sol | 164 ++--- src/libs/EigenLayerMiddlewareLib.sol | 19 +- src/libs/OperatorSubsetLib.sol | 649 ++++-------------- src/libs/SymbioticNetworkMiddlewareLib.sol | 19 +- .../TaiyiRegistryCoordinator.sol | 543 +++++++-------- src/slasher/LinglongSlasher.sol | 28 +- .../TaiyiRegistryCoordinatorStorage.sol | 2 +- .../SymbioticNetworkMiddleware.sol | 21 +- src/taiyi/TaiyiInteractiveChallenger.sol | 2 +- test/DeployTest.t.sol | 2 +- test/EigenLayerMiddleware.t.sol | 33 +- test/OperatorSubsetLib.t.sol | 648 +++++------------ test/SymbioticMiddleware.t.sol | 21 +- test/utils/MockChallenger.sol | 2 +- 20 files changed, 743 insertions(+), 1509 deletions(-) create mode 100644 script/configs/deploy-test-config.json diff --git a/script/SetupContract.s.sol b/script/SetupContract.s.sol index 6dccfcb..eadae07 100644 --- a/script/SetupContract.s.sol +++ b/script/SetupContract.s.sol @@ -117,10 +117,10 @@ contract SetupContract is Script, Test { strategies[0] = IStrategy(wethStrategyAddr); uint32 validatorOperatorSetId = eigenLayerMiddleware.createOperatorSet( - strategies, OperatorSubsetLib.VALIDATOR_SUBSET_TYPE, 0 + strategies, OperatorSubsetLib.EIGENLAYER_VALIDATOR_SUBSET_ID, 0 ); uint32 underwriterOperatorSetId = eigenLayerMiddleware.createOperatorSet( - strategies, OperatorSubsetLib.UNDERWRITER_SUBSET_TYPE, 0 + strategies, OperatorSubsetLib.EIGENLAYER_UNDERWRITER_SUBSET_ID, 0 ); OperatorSet memory opSet; diff --git a/script/configs/deploy-test-config.json b/script/configs/deploy-test-config.json new file mode 100644 index 0000000..a1d8223 --- /dev/null +++ b/script/configs/deploy-test-config.json @@ -0,0 +1,62 @@ +{ + "maintainer": "samlaf@eigenlabs.org", + "multisig_addresses": { + "operationsMultisig": "0xD8F3183DEF51A987222D845be228e0Bbb932C222", + "communityMultisig": "0xD8F3183DEF51A987222D845be228e0Bbb932C222", + "pauserMultisig": "0xD8F3183DEF51A987222D845be228e0Bbb932C222", + "executorMultisig": "0xD8F3183DEF51A987222D845be228e0Bbb932C222", + "timelock": "0xD8F3183DEF51A987222D845be228e0Bbb932C222" + }, + "strategies": [ + { + "token_address": "0x86A4F08103eade88adE0be164d7BDa8Fe166680d", + "token_symbol": "WETH", + "max_per_deposit": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "max_deposits": 115792089237316195423570985008687907853269984665640564039457584007913129639935 + } + ], + "strategyManager": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 1 + }, + "eigenPod": { + "PARTIAL_WITHDRAWAL_FRAUD_PROOF_PERIOD_BLOCKS": 1, + "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": "32000000000" + }, + "eigenPodManager": { + "init_paused_status": 30 + }, + "delayedWithdrawalRouter": { + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 1 + }, + "slasher": { + "init_paused_status": 0 + }, + "delegation": { + "withdrawal_delay_blocks": 900, + "init_paused_status": 0, + "init_withdrawal_delay_blocks": 1 + }, + "rewardsCoordinator": { + "init_paused_status": 0, + "CALCULATION_INTERVAL_SECONDS": 604800, + "MAX_REWARDS_DURATION": 6048000, + "MAX_RETROACTIVE_LENGTH": 7776000, + "MAX_FUTURE_LENGTH": 2592000, + "GENESIS_REWARDS_TIMESTAMP": 1710979200, + "rewards_updater_address": "0x18a0f92Ad9645385E8A8f3db7d0f6CF7aBBb0aD4", + "activation_delay": 7200, + "calculation_interval_seconds": 604800, + "global_operator_commission_bips": 1000, + "OPERATOR_SET_GENESIS_REWARDS_TIMESTAMP": 1720656000, + "OPERATOR_SET_MAX_RETROACTIVE_LENGTH": 2592000 + }, + "allocationManager": { + "init_paused_status": 0, + "DEALLOCATION_DELAY": 900, + "ALLOCATION_CONFIGURATION_DELAY": 1 + }, + "ethPOSDepositAddress": "0x4242424242424242424242424242424242424242", + "semver": "v0.0.0" + } diff --git a/src/eigenlayer-avs/EigenLayerMiddleware.sol b/src/eigenlayer-avs/EigenLayerMiddleware.sol index 46ea596..e154b29 100644 --- a/src/eigenlayer-avs/EigenLayerMiddleware.sol +++ b/src/eigenlayer-avs/EigenLayerMiddleware.sol @@ -101,7 +101,9 @@ contract EigenLayerMiddleware is /// @dev Validates that msg.sender is registered in the validator operatorSet with ID 0 modifier onlyValidatorOperatorSet() { if ( - REGISTRY_COORDINATOR.isEigenLayerOperatorInSet(uint32(0), msg.sender) == false + !REGISTRY_COORDINATOR.isOperatorInLinglongSubset( + OperatorSubsetLib.EIGENLAYER_VALIDATOR_SUBSET_ID, msg.sender + ) ) { revert EigenLayerMiddlewareLib @@ -226,8 +228,8 @@ contract EigenLayerMiddleware is returns (bytes32) { if ( - !REGISTRY_COORDINATOR.getEigenLayerOperatorFromOperatorSet( - OperatorSubsetLib.VALIDATOR_SUBSET_TYPE, msg.sender + !REGISTRY_COORDINATOR.isOperatorInLinglongSubset( + OperatorSubsetLib.EIGENLAYER_VALIDATOR_SUBSET_ID, msg.sender ) ) { revert @@ -259,8 +261,8 @@ contract EigenLayerMiddleware is /// @dev Removes all delegations and unregisters from the Registry contract function unregisterValidators(bytes32 registrationRoot) external { if ( - !REGISTRY_COORDINATOR.getEigenLayerOperatorFromOperatorSet( - OperatorSubsetLib.VALIDATOR_SUBSET_TYPE, msg.sender + !REGISTRY_COORDINATOR.isOperatorInLinglongSubset( + OperatorSubsetLib.EIGENLAYER_VALIDATOR_SUBSET_ID, msg.sender ) ) { revert @@ -337,8 +339,8 @@ contract EigenLayerMiddleware is external { if ( - !REGISTRY_COORDINATOR.getEigenLayerOperatorFromOperatorSet( - OperatorSubsetLib.VALIDATOR_SUBSET_TYPE, msg.sender + !REGISTRY_COORDINATOR.isOperatorInLinglongSubset( + OperatorSubsetLib.EIGENLAYER_VALIDATOR_SUBSET_ID, msg.sender ) ) { revert @@ -347,8 +349,8 @@ contract EigenLayerMiddleware is } if ( - !REGISTRY_COORDINATOR.getEigenLayerOperatorFromOperatorSet( - OperatorSubsetLib.UNDERWRITER_SUBSET_TYPE, delegateeAddress + !REGISTRY_COORDINATOR.isOperatorInLinglongSubset( + OperatorSubsetLib.EIGENLAYER_UNDERWRITER_SUBSET_ID, delegateeAddress ) ) { revert diff --git a/src/eigenlayer-avs/EigenLayerRewardsHandler.sol b/src/eigenlayer-avs/EigenLayerRewardsHandler.sol index 97667a5..741c7ce 100644 --- a/src/eigenlayer-avs/EigenLayerRewardsHandler.sol +++ b/src/eigenlayer-avs/EigenLayerRewardsHandler.sol @@ -15,6 +15,7 @@ import { IRewardsCoordinatorTypes } from "@eigenlayer-contracts/src/contracts/interfaces/IRewardsCoordinator.sol"; +import { OperatorSubsetLib } from "../libs/OperatorSubsetLib.sol"; import { BLS } from "@urc/lib/BLS.sol"; /// @title EigenLayerRewardsHandler @@ -116,7 +117,7 @@ contract EigenLayerRewardsHandler { // Get underwriter operators and total staked amount address[] memory underwriterOperators = middleware.getRegistryCoordinator() - .getEigenLayerOperatorSetOperators(uint32(0)); + .getLinglongSubsetOperators(OperatorSubsetLib.EIGENLAYER_UNDERWRITER_SUBSET_ID); if (underwriterOperators.length == 0) { revert NoUnderwriterOperators(); @@ -159,7 +160,7 @@ contract EigenLayerRewardsHandler { { // Get validator operators for this AVS address[] memory operators = middleware.getRegistryCoordinator() - .getEigenLayerOperatorSetOperators(uint32(0)); + .getLinglongSubsetOperators(OperatorSubsetLib.EIGENLAYER_VALIDATOR_SUBSET_ID); if (operators.length == 0) { revert NoUnderwriterOperators(); diff --git a/src/interfaces/ILinglongChallenger.sol b/src/interfaces/ILinglongChallenger.sol index 3acc547..119b6f1 100644 --- a/src/interfaces/ILinglongChallenger.sol +++ b/src/interfaces/ILinglongChallenger.sol @@ -113,12 +113,12 @@ interface ILinglongChallenger { /// @notice Check if slashing is in progress for an operator /// @param operator The operator address - /// @param operatorSetId The operator set ID + /// @param linglongSubsetId The operator set ID /// @return inProgress Whether slashing is in progress /// @return slashingId The ID of the slashing function isSlashingInProgress( address operator, - uint96 operatorSetId + uint32 linglongSubsetId ) external view diff --git a/src/interfaces/ILinglongSlasher.sol b/src/interfaces/ILinglongSlasher.sol index fe2d35a..ba71a3e 100644 --- a/src/interfaces/ILinglongSlasher.sol +++ b/src/interfaces/ILinglongSlasher.sol @@ -134,13 +134,13 @@ interface ILinglongSlasher is ISlasher { /// @notice Check if a slashing request is currently in progress for an operator /// @param operator The operator address to check - /// @param operatorSetId The operator set ID + /// @param linglongSubsetId The operator set ID /// @param challengeContract The challenger contract to check /// @return inProgress Whether a slashing is in progress /// @return slashingId The ID of the slashing request (if any) function isSlashingInProgress( address operator, - uint96 operatorSetId, + uint32 linglongSubsetId, address challengeContract ) external diff --git a/src/interfaces/ITaiyiRegistryCoordinator.sol b/src/interfaces/ITaiyiRegistryCoordinator.sol index 25c28cc..400bc53 100644 --- a/src/interfaces/ITaiyiRegistryCoordinator.sol +++ b/src/interfaces/ITaiyiRegistryCoordinator.sol @@ -3,8 +3,11 @@ pragma solidity ^0.8.27; import { BN254 } from "../libs/BN254.sol"; +import { IPubkeyRegistry } from "./IPubkeyRegistry.sol"; import { IAllocationManagerTypes } from "@eigenlayer-contracts/src/contracts/interfaces/IAllocationManager.sol"; +import { ISignatureUtilsMixinTypes } from + "@eigenlayer-contracts/src/contracts/interfaces/ISignatureUtilsMixin.sol"; import { IStrategy } from "@eigenlayer-contracts/src/contracts/interfaces/IStrategy.sol"; import { OperatorSet } from "@eigenlayer-contracts/src/contracts/libraries/OperatorSetLib.sol"; @@ -51,19 +54,6 @@ interface ITaiyiRegistryCoordinator { SYMBIOTIC } - /// @notice Defines the type of restaking service used by the protocol - /// @dev Used to specify which restaking mechanism an operator is using - /// @custom:enum EIGENLAYER_VALIDATOR The operator is using EigenLayer for restaking - /// @custom:enum EIGENLAYER_UNDERWRITER The operator is using EigenLayer for restaking - /// @custom:enum SYMBIOTIC_VALIDATOR The operator is using Symbiotic for restaking - /// @custom:enum SYMBIOTIC_UNDERWRITER The operator is using Symbiotic for restaking - enum RestakingServiceTypes { - EIGENLAYER_VALIDATOR, - EIGENLAYER_UNDERWRITER, - SYMBIOTIC_VALIDATOR, - SYMBIOTIC_UNDERWRITER - } - /// @notice Error thrown when an operator is not registered error NotRegistered(); @@ -85,11 +75,8 @@ interface ITaiyiRegistryCoordinator { /// @notice Error thrown when a caller is not the restaking middleware error OnlyRestakingMiddleware(); - /// @notice Error thrown when a caller is not the EigenLayer middleware - error OnlyEigenlayerMiddleware(); - - /// @notice Error thrown when a caller is not the symbiotic middleware - error OnlySymbioticMiddleware(); + /// @notice Error thrown when a caller is not the middleware + error OnlyMiddleware(); /// @notice Error thrown when an operator is not registered error OperatorNotDeregistered(); @@ -100,6 +87,12 @@ interface ITaiyiRegistryCoordinator { /// @notice Error thrown when an operator set is not found error OperatorSetNotFound(uint32 operatorSetId); + /// @notice Error thrown when an invalid subset ID is provided + error OnlySymbioticSubsetId(); + + /// @notice Error thrown when an invalid subset ID is provided + error OnlyEigenlayerSubsetId(); + /// @notice Emitted when a new middleware is added or updated event RestakingMiddlewareUpdated( RestakingProtocol restakingProtocol, address newMiddleware @@ -124,24 +117,13 @@ interface ITaiyiRegistryCoordinator { /// @param socket The new socket value event OperatorSocketUpdate(bytes32 indexed operatorId, string socket); - /// @notice Emitted when the ejector address is updated - /// @param previousEjector The previous ejector address - /// @param newEjector The new ejector address - event EjectorUpdated(address indexed previousEjector, address indexed newEjector); - - /// @notice Emitted when the restaking middleware address is updated - /// @param previousMiddleware The previous middleware address - /// @param newMiddleware The new middleware address - event RestakingMiddlewareUpdated( - address indexed previousMiddleware, address indexed newMiddleware - ); - /// @notice Updates the socket address for the calling operator /// @param socket The new socket address to set function updateSocket(string memory socket) external; /// @notice Register an operator with the specified operator set IDs /// @param operator The address of the operator to register + /// @param avs The AVS address /// @param operatorSetIds The operator set IDs to register the operator with /// @param data Additional data required for registration function registerOperator( @@ -154,6 +136,7 @@ interface ITaiyiRegistryCoordinator { /// @notice Deregister an operator from the specified operator set IDs /// @param operator The address of the operator to deregister + /// @param avs The AVS address /// @param operatorSetIds The operator set IDs to deregister the operator from function deregisterOperator( address operator, @@ -163,14 +146,9 @@ interface ITaiyiRegistryCoordinator { external; /// @notice Create a new operator set with the specified strategies - /// @param subnetworkId The ID of the subnetwork - /// @param minStake The minimum stake required for the subnetwork - function createSubnetwork(uint96 subnetworkId, uint256 minStake) external; - - /// @notice Create a new operator set with the specified strategies - /// @param operatorSetId The ID of the operator set + /// @param linglongSubsetId The ID of the operator set /// @param minStake The minimum stake required for the operator set - function createOperatorSet(uint32 operatorSetId, uint256 minStake) external; + function createLinglongSubset(uint32 linglongSubsetId, uint256 minStake) external; /// @notice Gets the protocol type for a middleware address /// @param middleware The middleware address to query @@ -185,53 +163,33 @@ interface ITaiyiRegistryCoordinator { /// @return True if the middleware is a restaking middleware, false otherwise function isRestakingMiddleware(address middleware) external view returns (bool); - /// @notice Get the operators in the specified subnetwork - /// @param baseSubnetworkId The ID of the subnetwork - /// @return Array of operator addresses in the subnetwork - function getSymbioticSubnetworkOperators(uint96 baseSubnetworkId) - external - view - returns (address[] memory); - /// @notice Get the operators in the specified operator set - /// @param baseOperatorSetId The ID of the operator set + /// @param linglongSubsetId The ID of the operator set /// @return Array of operator addresses in the set - function getEigenLayerOperatorSetOperators(uint32 baseOperatorSetId) + function getLinglongSubsetOperators(uint32 linglongSubsetId) external view returns (address[] memory); - /// @notice Get all symbiotic operator sets - /// @return Array of operator set IDs - function getSymbioticSubnetworks() external view returns (uint96[] memory); - - /// @notice Get all eigenlayer operator sets - /// @return Array of operator set IDs - function getEigenLayerOperatorSets() external view returns (uint32[] memory); - - /// @notice Get the operator set with the specified ID - /// @param operatorSetId The ID of the operator set - /// @param operator The address of the operator - /// @return Array of operator addresses in the set - function getEigenLayerOperatorFromOperatorSet( - uint32 operatorSetId, - address operator - ) + /// @notice Get the size of a specific operator set + /// @param linglongSubsetId The ID of the operator set + /// @return The size of the operator set + function getLinglongSubsetSize(uint32 linglongSubsetId) external view - returns (bool); + returns (uint256); - /// @notice Get the operator set with the specified ID - /// @param operatorSetId The ID of the operator set - /// @param operator The address of the operator - /// @return Array of operator addresses in the set - function getSymbioticOperatorFromOperatorSet( - uint96 operatorSetId, - address operator - ) + /// @notice Get all operator sets + /// @return Array of operator set IDs + function getLinglongSubnets() external view returns (uint32[] memory); + + /// @notice Get all middleware addresses for a specific protocol + /// @param protocol The protocol type to filter by + /// @return Array of middleware addresses for the specified protocol + function getRestakingMiddlewareByProtocol(RestakingProtocol protocol) external view - returns (bool); + returns (address[] memory); /// @notice Get all operator sets that an operator has allocated magnitude to /// @param operator The operator whose allocated sets to fetch @@ -247,11 +205,11 @@ interface ITaiyiRegistryCoordinator { /// @notice Get all strategies that an operator has allocated magnitude to in a specific operator set /// @param operator The operator whose allocated strategies to fetch - /// @param baseOperatorSetId The ID of the operator set to query + /// @param linglongSubsetId The ID of the operator set to query /// @return allocatedStrategies Array of strategy addresses that the operator has allocated magnitude to in the operator set function getEigenLayerOperatorAllocatedStrategies( address operator, - uint32 baseOperatorSetId + uint32 linglongSubsetId ) external view @@ -259,27 +217,37 @@ interface ITaiyiRegistryCoordinator { /// @notice Get all strategies that an operator has allocated magnitude to in a specific symbiotic subnetwork /// @param operator The operator whose allocated strategies to fetch - /// @param baseSubnetworkId The ID of the subnetwork to query + /// @param linglongSubsetId The ID of the subnetwork to query /// @return allocatedStrategies Array of strategy addresses that the operator has allocated magnitude to in the subnetwork function getSymbioticOperatorAllocatedStrategies( address operator, - uint96 baseSubnetworkId + uint32 linglongSubsetId ) external view returns (address[] memory allocatedStrategies); + /// @notice Get the amount of strategy allocation for an operator in an EigenLayer operator set + /// @param operator The operator to query + /// @param linglongSubsetId The operator set ID + /// @param strategy The strategy to query + /// @return The amount of allocation function getEigenLayerOperatorAllocatedStrategiesAmount( address operator, - uint32 baseOperatorSetId, + uint32 linglongSubsetId, IStrategy strategy ) external returns (uint256); + /// @notice Get the amount of strategy allocation for an operator in a Symbiotic subnetwork + /// @param operator The operator to query + /// @param linglongSubsetId The subnetwork ID + /// @param strategy The strategy to query + /// @return The amount of allocation function getSymbioticOperatorAllocatedStrategiesAmount( address operator, - uint96 baseSubnetworkId, + uint32 linglongSubsetId, IStrategy strategy ) external @@ -326,42 +294,34 @@ interface ITaiyiRegistryCoordinator { returns (bytes32); /// @notice whether the operator set Id is set - /// @param operatorSetId operator Id - /// @return yes or no - function isEigenlayerOperatorSetExist(uint32 operatorSetId) - external - view - returns (bool); - - /// @notice whether the operator set Id is set - /// @param operatorSetId operator Id + /// @param linglongSubsetId operator Id /// @return yes or no - function isSymbioticOperatorSetExist(uint96 operatorSetId) + function isLinglongSubsetExist(uint32 linglongSubsetId) external view returns (bool); /// @notice Checks if an operator is in a specific operator set - /// @param operatorSetId The operator set ID + /// @param linglongSubsetId The operator set ID /// @param operator The operator address /// @return True if the operator is in the set, false otherwise - function isEigenLayerOperatorInSet( - uint32 operatorSetId, + function isOperatorInLinglongSubset( + uint32 linglongSubsetId, address operator ) external view returns (bool); - /// @notice Checks if an operator is in a specific symbiotic operator set - /// @param baseSubnetworkId The ID of the subnetwork - /// @param operator The operator address - /// @return True if the operator is in the set, false otherwise - function isSymbioticOperatorInSubnetwork( - uint96 baseSubnetworkId, - address operator - ) + /// @notice External function to decode operator data + /// @param data The data to decode + /// @return socket The socket string + /// @return params The PubkeyRegistrationParams + function decodeOperatorData(bytes calldata data) external - view - returns (bool); + pure + returns ( + string memory socket, + IPubkeyRegistry.PubkeyRegistrationParams memory params + ); } diff --git a/src/libs/EigenLayerMiddlewareLib.sol b/src/libs/EigenLayerMiddlewareLib.sol index d3b0b99..912a3ec 100644 --- a/src/libs/EigenLayerMiddlewareLib.sol +++ b/src/libs/EigenLayerMiddlewareLib.sol @@ -33,8 +33,6 @@ library EigenLayerMiddlewareLib { using EnumerableSet for EnumerableSet.AddressSet; using EnumerableSet for EnumerableSet.Bytes32Set; using EnumerableMapLib for EnumerableMapLib.Uint256ToBytes32Map; - using OperatorSubsetLib for uint96; - using OperatorSubsetLib for uint32; /// @notice Custom errors error OperatorNotRegisteredInEigenLayer(); @@ -78,7 +76,7 @@ library EigenLayerMiddlewareLib { // Count total strategies first for (uint256 i = 0; i < operatorSetsLength;) { - (, uint32 baseId) = operatorSets[i].id.decodeOperatorSetId32(); + uint32 baseId = operatorSets[i].id; address[] memory setStrategies = registryCoordinator .getEigenLayerOperatorAllocatedStrategies(operator, baseId); totalStrategiesCount += setStrategies.length; @@ -97,7 +95,7 @@ library EigenLayerMiddlewareLib { // Fill array with all strategies for (uint256 i = 0; i < operatorSetsLength;) { - (, uint32 baseId) = operatorSets[i].id.decodeOperatorSetId32(); + uint32 baseId = operatorSets[i].id; address[] memory setStrategies = registryCoordinator .getEigenLayerOperatorAllocatedStrategies(operator, baseId); uint256 setStrategiesLength = setStrategies.length; @@ -264,18 +262,19 @@ library EigenLayerMiddlewareLib { ITaiyiRegistryCoordinator registryCoordinator, IStrategy[] memory strategies, uint256 minStake, - uint32 operatorSetType + uint32 linglongSubsetId ) internal returns (uint32 operatorSetId) { // Get the current operator set count from allocationManager - operatorSetId = uint32(operatorSetType).encodeOperatorSetId32( - ITaiyiRegistryCoordinator.RestakingProtocol.EIGENLAYER + operatorSetId = linglongSubsetId; + require( + OperatorSubsetLib.isEigenlayerProtocolID(linglongSubsetId), + "Invalid eigenlayer subset ID" ); - require( - !registryCoordinator.isEigenlayerOperatorSetExist(operatorSetId), + !registryCoordinator.isLinglongSubsetExist(operatorSetId), OperatorSetAlreadyExists() ); @@ -292,7 +291,7 @@ library EigenLayerMiddlewareLib { avsAddress, createSetParams ); - registryCoordinator.createOperatorSet(operatorSetId, minStake); + registryCoordinator.createLinglongSubset(operatorSetId, minStake); return operatorSetId; } diff --git a/src/libs/OperatorSubsetLib.sol b/src/libs/OperatorSubsetLib.sol index 3060a3c..485ba66 100644 --- a/src/libs/OperatorSubsetLib.sol +++ b/src/libs/OperatorSubsetLib.sol @@ -9,629 +9,234 @@ import { EnumerableSet } from import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; /// @title OperatorSubsetLib -/// @notice Library for handling operator set IDs with embedded protocol type information -/// @dev Uses bit manipulation to efficiently encode/decode protocol type in operator set IDs -/// and provides methods to manipulate operator sets +/// @notice Library for handling linglong subset IDs with embedded protocol type information +/// @dev Uses bit manipulation to efficiently encode/decode protocol type in linglong subset IDs +/// and provides methods to manipulate linglong subsets library OperatorSubsetLib { using EnumerableSet for EnumerableSet.AddressSet; using EnumerableSet for EnumerableSet.UintSet; - // Constants for uint96 encoding (5 bits protocol, 91 bits baseId) - // Reserve the highest 5 bits for protocol type (allows up to 32 protocol types) - // This leaves 91 bits for the actual operator set ID - uint8 private constant PROTOCOL_BITS = 5; - uint8 private constant PROTOCOL_SHIFT_96 = 91; // 96 - PROTOCOL_BITS - uint96 private constant PROTOCOL_MASK_96 = - (uint96(1) << PROTOCOL_BITS) - 1 << PROTOCOL_SHIFT_96; // Generates mask dynamically e.g., 0xF800...00 - uint96 private constant ID_MASK_96 = (uint96(1) << PROTOCOL_SHIFT_96) - 1; // Generates mask for lowest 91 bits e.g., 0x07FF...FF - - // Constants for uint32 encoding (5 bits protocol, 27 bits baseId) - uint8 private constant PROTOCOL_SHIFT_32 = 27; // 32 - PROTOCOL_BITS - uint32 private constant PROTOCOL_MASK_32 = 0xF8000000; // Highest 5 bits set - uint32 private constant ID_MASK_32 = 0x07FFFFFF; // Lowest 27 bits set - error OperatorSetLib__OperatorSetDoesNotExist(); - error OperatorSetLib__IdTooLarge(); - error OperatorSetLib__IdTooLarge32(); - - uint32 constant VALIDATOR_SUBSET_TYPE = 0; - uint32 constant UNDERWRITER_SUBSET_TYPE = 1; - - /// @notice Structure to store operator sets with their members - - struct OperatorSets { - EnumerableSet.UintSet operatorSetIds96; // For 96-bit IDs - EnumerableSet.UintSet operatorSetIds32; // For 32-bit IDs - // set id to operator address mapping for 96-bit IDs - mapping(uint96 => EnumerableSet.AddressSet) sets96; - // set id => minStake mapping for 96-bit IDs - mapping(uint96 => uint256) minStake96; - // set id to operator address mapping for 32-bit IDs - mapping(uint32 => EnumerableSet.AddressSet) sets32; - // set id => minStake mapping for 32-bit IDs - mapping(uint32 => uint256) minStake32; - } - - /// @notice Encodes a protocol type and base ID into a single ID using uint96 (5 bits protocol, 91 bits baseId) - /// @dev Uses uint96 for larger operator set IDs - /// @param baseId The original operator set ID (must be < 2^91) - /// @param protocol The restaking protocol type - /// @return The encoded operator set ID with protocol information as uint96 - function encodeOperatorSetId96( - uint96 baseId, - ITaiyiRegistryCoordinator.RestakingProtocol protocol - ) - internal - pure - returns (uint96) - { - // Ensure baseId doesn't use the reserved bits - if (baseId > ID_MASK_96) { - revert OperatorSetLib__IdTooLarge(); - } - - // Convert protocol enum to uint96 and shift to the reserved bits position - uint96 protocolBits = (uint96(uint8(protocol)) << PROTOCOL_SHIFT_96); - - // Combine the protocol bits with the base ID - return protocolBits | baseId; - } - - /// @notice Encodes a protocol type and base ID into a single ID using uint32 (5 bits protocol, 27 bits baseId) - /// @dev Uses uint32 for smaller operator set IDs - /// @param baseId The original operator set ID (must be < 2^27) - /// @param protocol The restaking protocol type - /// @return The encoded operator set ID with protocol information as uint32 - function encodeOperatorSetId32( - uint32 baseId, - ITaiyiRegistryCoordinator.RestakingProtocol protocol - ) - internal - pure - returns (uint32) - { - // Ensure baseId doesn't use the reserved bits - if (baseId > ID_MASK_32) { - revert OperatorSetLib__IdTooLarge32(); - } - - // Convert protocol enum to uint32 and shift to the reserved bits position - uint32 protocolBits = (uint32(uint8(protocol)) << PROTOCOL_SHIFT_32); - - // Combine the protocol bits with the base ID - return protocolBits | baseId; - } - - /// @notice Encodes a protocol type and base ID into a single ID using uint32 for IAVSRegistrar compatibility - /// @dev Special version that constrains both the protocol and base ID to ensure the result fits in uint32 - /// @param baseId The original operator set ID (must be < 2^27) - /// @param protocol The restaking protocol type - /// @return The encoded operator set ID with protocol information as uint32, safe for IAVSRegistrar - function encodeOperatorSetIdForIAVS( - uint96 baseId, - ITaiyiRegistryCoordinator.RestakingProtocol protocol - ) - internal - pure - returns (uint32) - { - // For IAVSRegistrar compatibility, we must ensure the base ID is small - // Limit to 27 bits (2^27-1 = 134,217,727) to leave room for protocol - if (baseId > ID_MASK_32) { - revert OperatorSetLib__IdTooLarge32(); - } - - // Convert protocol enum to uint32 and shift to the reserved bits position - uint32 protocolBits = (uint32(uint8(protocol)) << PROTOCOL_SHIFT_32); - - // Combine the protocol bits with the base ID - return protocolBits | uint32(baseId); - } - - /// @notice Decodes a uint96 operator set ID to extract the protocol type and base ID - /// @dev Works with uint96 encoded IDs (5 bits protocol, 91 bits baseId) - /// @param encodedId The encoded operator set ID as uint96 - /// @return protocol The restaking protocol type - /// @return baseId The original operator set ID as uint96 - function decodeOperatorSetId96(uint96 encodedId) - internal - pure - returns (ITaiyiRegistryCoordinator.RestakingProtocol protocol, uint96 baseId) - { - // Extract the protocol bits and convert to enum - protocol = ITaiyiRegistryCoordinator.RestakingProtocol( - uint8(encodedId >> PROTOCOL_SHIFT_96) - ); - - // Extract the base ID by masking out the protocol bits - baseId = encodedId & ID_MASK_96; - - return (protocol, baseId); - } - - /// @notice Decodes a uint32 operator set ID to extract the protocol type and base ID - /// @dev Works with uint32 encoded IDs (5 bits protocol, 27 bits baseId) - /// @param encodedId The encoded operator set ID as uint32 - /// @return protocol The restaking protocol type - /// @return baseId The original operator set ID as uint32 - function decodeOperatorSetId32(uint32 encodedId) - internal - pure - returns (ITaiyiRegistryCoordinator.RestakingProtocol protocol, uint32 baseId) - { - // Extract the protocol bits and convert to enum - protocol = ITaiyiRegistryCoordinator.RestakingProtocol( - uint8(encodedId >> PROTOCOL_SHIFT_32) - ); - // Extract the base ID by masking out the protocol bits - baseId = encodedId & ID_MASK_32; + // the below are the available linglong subset id + uint32 constant EIGENLAYER_VALIDATOR_SUBSET_ID = 0; + uint32 constant EIGENLAYER_UNDERWRITER_SUBSET_ID = 1; + uint32 constant SYMBIOTIC_VALIDATOR_SUBSET_ID = 2; + uint32 constant SYMBIOTIC_UNDERWRITER_SUBSET_ID = 3; - return (protocol, baseId); + /// @notice Structure to store linglong subsets with their members + struct LinglongSubsets { + // linglong subset id + EnumerableSet.UintSet linglongSubsetIds; + // linglong subset id => subset members + mapping(uint32 => EnumerableSet.AddressSet) operatorSetMembers; + // linglong subset id => subset min stake + mapping(uint32 => uint256) minStake; } - /// @notice Decodes an encoded uint32 operator set ID back to its original uint96 baseId - /// @dev Extracts the baseId part from the encoded ID, removing protocol information - /// @param encodedId The encoded operator set ID with protocol information - /// @return The original baseId as uint96 - function decodeOperatorSetIdFromIAVS(uint32 encodedId) + function isEigenlayerProtocolID(uint32 linglongSubsetId) internal pure - returns (uint96) - { - // Extract only the baseId bits by masking out the protocol bits - return uint96(encodedId & ID_MASK_32); - } - - /// @notice Gets just the protocol type from a uint96 encoded operator set ID - /// @dev Works with uint96 encoded IDs (5 bits protocol, 91 bits baseId) - /// @param encodedId The encoded operator set ID as uint96 - /// @return The restaking protocol type - function getProtocolType96(uint96 encodedId) - internal - pure - returns (ITaiyiRegistryCoordinator.RestakingProtocol) + returns (bool) { - return ITaiyiRegistryCoordinator.RestakingProtocol( - uint8(encodedId >> PROTOCOL_SHIFT_96) - ); + return linglongSubsetId == EIGENLAYER_VALIDATOR_SUBSET_ID + || linglongSubsetId == EIGENLAYER_UNDERWRITER_SUBSET_ID; } - /// @notice Gets just the protocol type from a uint32 encoded operator set ID - /// @dev Works with uint32 encoded IDs (5 bits protocol, 27 bits baseId) - /// @param encodedId The encoded operator set ID as uint32 - /// @return The restaking protocol type - function getProtocolType32(uint32 encodedId) + function isSymbioticProtocolID(uint32 linglongSubsetId) internal pure - returns (ITaiyiRegistryCoordinator.RestakingProtocol) - { - return ITaiyiRegistryCoordinator.RestakingProtocol( - uint8(encodedId >> PROTOCOL_SHIFT_32) - ); - } - - /// @notice Gets just the base ID from a uint96 encoded operator set ID - /// @dev Works with uint96 encoded IDs (5 bits protocol, 91 bits baseId) - /// @param encodedId The encoded operator set ID as uint96 - /// @return The original operator set ID as uint96 - function getBaseId96(uint96 encodedId) internal pure returns (uint96) { - return encodedId & ID_MASK_96; - } - - /// @notice Gets just the base ID from a uint32 encoded operator set ID - /// @dev Works with uint32 encoded IDs (5 bits protocol, 27 bits baseId) - /// @param encodedId The encoded operator set ID as uint32 - /// @return The original operator set ID as uint32 - function getBaseId32(uint32 encodedId) internal pure returns (uint32) { - return encodedId & ID_MASK_32; - } - - /// @notice Creates an extended operator set with protocol information using uint96 ID - /// @dev Uses uint96 for larger operator set IDs - /// @param operatorSets The storage reference to operator sets mapping - /// @param encodedId The encoded operator set ID as uint96 - /// @return Success boolean - function createOperatorSet96( - OperatorSets storage operatorSets, - uint96 encodedId, - uint256 minStake - ) - internal returns (bool) { - operatorSets.minStake96[encodedId] = minStake; - return operatorSets.operatorSetIds96.add(uint256(encodedId)); - } - - /// @notice Creates an extended operator set with protocol information using uint32 ID - /// @dev Uses uint32 for smaller operator set IDs - /// @param operatorSets The storage reference to operator sets mapping - /// @param encodedId The encoded operator set ID as uint32 - /// @param minStake The minimum stake required for the operator set + return linglongSubsetId == SYMBIOTIC_VALIDATOR_SUBSET_ID + || linglongSubsetId == SYMBIOTIC_UNDERWRITER_SUBSET_ID; + } + /// @notice Creates a linglong subset with protocol information using uint32 ID + /// @dev Uses uint32 for linglong subset IDs + /// @param linglongSubsets The storage reference to linglong subsets mapping + /// @param linglongSubsetId The linglong subset ID as uint32 + /// @param minStake The minimum stake required for this subset /// @return Success boolean - function createOperatorSet32( - OperatorSets storage operatorSets, - uint32 encodedId, + + function createLinglongSubset( + LinglongSubsets storage linglongSubsets, + uint32 linglongSubsetId, uint256 minStake ) internal returns (bool) { - operatorSets.minStake32[encodedId] = minStake; - return operatorSets.operatorSetIds32.add(uint256(encodedId)); + linglongSubsets.minStake[linglongSubsetId] = minStake; + return linglongSubsets.linglongSubsetIds.add(linglongSubsetId); } - // ======== OPERATOR SET MANAGEMENT FUNCTIONS ======== + // ======== LINGLONG SUBSET MANAGEMENT FUNCTIONS ======== - /// @notice Adds an operator to a specific operator set using uint96 ID - /// @dev Works with uint96 encoded operator set IDs - /// @param operatorSets The storage reference to operator sets mapping - /// @param operatorSetId The encoded ID of the operator set as uint96 + /// @notice Adds an operator to a specific linglong subset using uint32 ID + /// @dev Works with uint32 linglong subset IDs + /// @param linglongSubsets The storage reference to linglong subsets mapping + /// @param linglongSubsetId The ID of the linglong subset as uint32 /// @param operator The address of the operator to add /// @return True if the operator was added, false if already present - function addOperatorToSet96( - OperatorSets storage operatorSets, - uint96 operatorSetId, + function addOperatorToLinglongSubset( + LinglongSubsets storage linglongSubsets, + uint32 linglongSubsetId, address operator ) internal returns (bool) { - if (operatorSets.operatorSetIds96.contains(uint256(operatorSetId))) { - return operatorSets.sets96[operatorSetId].add(operator); + if (linglongSubsets.linglongSubsetIds.contains(linglongSubsetId)) { + return linglongSubsets.operatorSetMembers[linglongSubsetId].add(operator); } else { revert OperatorSetLib__OperatorSetDoesNotExist(); } } - /// @notice Adds an operator to a specific operator set using uint32 ID - /// @dev Works with uint32 encoded operator set IDs - /// @param operatorSets The storage reference to operator sets mapping - /// @param operatorSetId The encoded ID of the operator set as uint32 - /// @param operator The address of the operator to add - /// @return True if the operator was added, false if already present - function addOperatorToSet32( - OperatorSets storage operatorSets, - uint32 operatorSetId, - address operator + function isLinglongSubsetIdCreated( + LinglongSubsets storage linglongSubsets, + uint32 linglongSubsetId ) internal + view returns (bool) { - if (operatorSets.operatorSetIds32.contains(uint256(operatorSetId))) { - return operatorSets.sets32[operatorSetId].add(operator); - } else { - revert OperatorSetLib__OperatorSetDoesNotExist(); - } - } - - /// @notice Adds an operator to multiple operator sets at once using uint96 IDs - /// @dev Works with uint96 base IDs and encoded IDs - /// @param operatorSets The storage reference to operator sets mapping - /// @param operatorSetIds Array of operator set IDs as uint96[] (encoded) - /// @param protocol The protocol type to encode with the base IDs - /// @param operator The address of the operator to add - function addOperatorToSets96( - OperatorSets storage operatorSets, - uint96[] memory operatorSetIds, - ITaiyiRegistryCoordinator.RestakingProtocol protocol, - address operator - ) - internal - { - for (uint256 i = 0; i < operatorSetIds.length; i++) { - addOperatorToSet96(operatorSets, operatorSetIds[i], operator); - } + return linglongSubsets.linglongSubsetIds.contains(linglongSubsetId); } - /// @notice Adds an operator to multiple operator sets at once using uint32 IDs - /// @dev Works with uint32 base IDs and encoded IDs - /// @param operatorSets The storage reference to operator sets mapping - /// @param operatorSetIds Array of operator set IDs as uint32[] (not encoded) - /// @param protocol The protocol type to encode with the base IDs + /// @notice Adds an operator to multiple linglong subsets at once using uint32 IDs + /// @dev Works with uint32 IDs + /// @param linglongSubsets The storage reference to linglong subsets mapping + /// @param linglongSubsetIds Array of linglong subset IDs as uint32[] /// @param operator The address of the operator to add - function addOperatorToSets32( - OperatorSets storage operatorSets, - uint32[] memory operatorSetIds, - ITaiyiRegistryCoordinator.RestakingProtocol protocol, - address operator - ) - internal - { - for (uint256 i = 0; i < operatorSetIds.length; i++) { - addOperatorToSet32(operatorSets, operatorSetIds[i], operator); - } - } - - /// @notice Removes an operator from a specific operator set - /// @param operatorSets The storage reference to operator sets mapping - /// @param operatorSetId The encoded ID of the operator set - /// @param operator The address of the operator to remove - /// @return True if the operator was removed, false if not present - function removeOperatorFromSet96( - OperatorSets storage operatorSets, - uint96 operatorSetId, + function addOperatorToLinglongSubsets( + LinglongSubsets storage linglongSubsets, + uint32[] memory linglongSubsetIds, address operator ) internal - returns (bool) { - if (operatorSets.operatorSetIds96.contains(uint256(operatorSetId))) { - return operatorSets.sets96[operatorSetId].remove(operator); - } else { - revert OperatorSetLib__OperatorSetDoesNotExist(); + for (uint256 i = 0; i < linglongSubsetIds.length; i++) { + addOperatorToLinglongSubset(linglongSubsets, linglongSubsetIds[i], operator); } } - /// @notice Removes an operator from a specific operator set - /// @param operatorSets The storage reference to operator sets mapping - /// @param operatorSetId The encoded ID of the operator set + /// @notice Removes an operator from a specific linglong subset + /// @param linglongSubsets The storage reference to linglong subsets mapping + /// @param linglongSubsetId The ID of the linglong subset /// @param operator The address of the operator to remove /// @return True if the operator was removed, false if not present - function removeOperatorFromSet32( - OperatorSets storage operatorSets, - uint32 operatorSetId, + function removeOperatorFromLinglongSubset( + LinglongSubsets storage linglongSubsets, + uint32 linglongSubsetId, address operator ) internal returns (bool) { - if (operatorSets.operatorSetIds32.contains(uint256(operatorSetId))) { - return operatorSets.sets32[operatorSetId].remove(operator); + if (linglongSubsets.linglongSubsetIds.contains(linglongSubsetId)) { + return linglongSubsets.operatorSetMembers[linglongSubsetId].remove(operator); } else { revert OperatorSetLib__OperatorSetDoesNotExist(); } } - /// @notice Removes an operator from multiple operator sets at once - /// @param operatorSets The storage reference to operator sets mapping - /// @param baseIds Array of base IDs (not encoded) to remove the operator from - /// @param protocol The protocol type to encode with the base IDs - /// @param operator The address of the operator to remove - function removeOperatorFromSets96( - OperatorSets storage operatorSets, - uint96[] memory baseIds, - ITaiyiRegistryCoordinator.RestakingProtocol protocol, - address operator - ) - internal - { - for (uint256 i = 0; i < baseIds.length; i++) { - uint96 encodedId = encodeOperatorSetId96(baseIds[i], protocol); - removeOperatorFromSet96(operatorSets, encodedId, operator); - } - } - - /// @notice Removes an operator from multiple operator sets at once - /// @param operatorSets The storage reference to operator sets mapping - /// @param baseIds Array of base IDs (not encoded) to remove the operator from - /// @param protocol The protocol type to encode with the base IDs + /// @notice Removes an operator from multiple linglong subsets at once + /// @param linglongSubsets The storage reference to linglong subsets mapping + /// @param linglongSubsetIds Array of linglong subset IDs to remove the operator from /// @param operator The address of the operator to remove - function removeOperatorFromSets32( - OperatorSets storage operatorSets, - uint32[] memory baseIds, - ITaiyiRegistryCoordinator.RestakingProtocol protocol, + function removeOperatorFromLinglongSubsets( + LinglongSubsets storage linglongSubsets, + uint32[] memory linglongSubsetIds, address operator ) internal { - for (uint256 i = 0; i < baseIds.length; i++) { - uint32 encodedId = encodeOperatorSetId32(baseIds[i], protocol); - removeOperatorFromSet32(operatorSets, encodedId, operator); - } - } - - /// @notice Checks if an operator is in a specific operator set - /// @param operatorSets The storage reference to operator sets mapping - /// @param operatorSetId The encoded ID of the operator set - /// @param operator The address of the operator to check - /// @return True if the operator is in the set, false otherwise - function isOperatorInSet96( - OperatorSets storage operatorSets, - uint96 operatorSetId, - address operator - ) - internal - view - returns (bool) - { - if (operatorSets.operatorSetIds96.contains(uint256(operatorSetId))) { - return operatorSets.sets96[operatorSetId].contains(operator); - } else { - revert OperatorSetLib__OperatorSetDoesNotExist(); + for (uint256 i = 0; i < linglongSubsetIds.length; i++) { + removeOperatorFromLinglongSubset( + linglongSubsets, linglongSubsetIds[i], operator + ); } } - /// @notice Checks if an operator is in a specific operator set - /// @param operatorSets The storage reference to operator sets mapping - /// @param operatorSetId The encoded ID of the operator set + /// @notice Checks if an operator is in a specific linglong subset + /// @param linglongSubsets The storage reference to linglong subsets mapping + /// @param linglongSubsetId The ID of the linglong subset /// @param operator The address of the operator to check - /// @return True if the operator is in the set, false otherwise - function isOperatorInSet32( - OperatorSets storage operatorSets, - uint32 operatorSetId, + /// @return True if the operator is in the subset, false otherwise + function isOperatorInLinglongSubset( + LinglongSubsets storage linglongSubsets, + uint32 linglongSubsetId, address operator ) internal view returns (bool) { - if (operatorSets.operatorSetIds32.contains(uint256(operatorSetId))) { - return operatorSets.sets32[operatorSetId].contains(operator); - } else { - revert OperatorSetLib__OperatorSetDoesNotExist(); - } - } - - /// @notice Gets all operators in a specific operator set using uint96 ID - /// @dev Works with uint96 encoded operator set IDs - /// @param operatorSets The storage reference to operator sets mapping - /// @param operatorSetId The encoded ID of the operator set as uint96 - /// @return Array of operator addresses in the set - function getOperatorsInSet96( - OperatorSets storage operatorSets, - uint96 operatorSetId - ) - internal - view - returns (address[] memory) - { - if (operatorSets.operatorSetIds96.contains(uint256(operatorSetId))) { - return operatorSets.sets96[operatorSetId].values(); + if (linglongSubsets.linglongSubsetIds.contains(linglongSubsetId)) { + return linglongSubsets.operatorSetMembers[linglongSubsetId].contains(operator); } else { revert OperatorSetLib__OperatorSetDoesNotExist(); } } - /// @notice Gets all operators in a specific operator set using uint32 ID - /// @dev Works with uint32 encoded operator set IDs - /// @param operatorSets The storage reference to operator sets mapping - /// @param operatorSetId The encoded ID of the operator set as uint32 - /// @return Array of operator addresses in the set - function getOperatorsInSet32( - OperatorSets storage operatorSets, - uint32 operatorSetId + /// @notice Gets all operators in a specific linglong subset using uint32 ID + /// @dev Works with uint32 linglong subset IDs + /// @param linglongSubsets The storage reference to linglong subsets mapping + /// @param linglongSubsetId The ID of the linglong subset as uint32 + /// @return Array of operator addresses in the subset + function getOperatorsInLinglongSubset( + LinglongSubsets storage linglongSubsets, + uint32 linglongSubsetId ) internal view returns (address[] memory) { - if (operatorSets.operatorSetIds32.contains(uint256(operatorSetId))) { - return operatorSets.sets32[operatorSetId].values(); + if (linglongSubsets.linglongSubsetIds.contains(linglongSubsetId)) { + return linglongSubsets.operatorSetMembers[linglongSubsetId].values(); } else { revert OperatorSetLib__OperatorSetDoesNotExist(); } } - /// @notice Gets all operator sets that an operator has allocated to - /// @param operatorSets The storage reference to operator sets mapping + /// @notice Gets all linglong subsets that an operator has allocated to + /// @param linglongSubsets The storage reference to linglong subsets mapping /// @param operator The address of the operator to check - /// @return Array of operator sets that the operator has allocated magnitude to - function getOperatorSetsFromOperator96( - OperatorSets storage operatorSets, + /// @return Array of linglong subsets that the operator has allocated magnitude to + function getLinglongSubsetsFromOperator( + LinglongSubsets storage linglongSubsets, address operator ) - internal - view - returns (uint96[] memory) - { - uint256[] memory rawValues = operatorSets.operatorSetIds96.values(); - uint96[] memory result = new uint96[](rawValues.length); - for (uint256 i = 0; i < rawValues.length; i++) { - uint96 operatorSetId = SafeCast.toUint96(rawValues[i]); - if (isOperatorInSet96(operatorSets, operatorSetId, operator)) { - result[i] = operatorSetId; - } - } - return result; - } - - /// @notice Gets the number of operators in a specific operator set - /// @param operatorSets The storage reference to operator sets mapping - /// @param operatorSetId The encoded ID of the operator set - /// @return The number of operators in the set - function getOperatorSetLength96( - OperatorSets storage operatorSets, - uint96 operatorSetId - ) - internal - view - returns (uint256) - { - if (operatorSets.operatorSetIds96.contains(uint256(operatorSetId))) { - return operatorSets.sets96[operatorSetId].length(); - } else { - revert OperatorSetLib__OperatorSetDoesNotExist(); - } - } - - /// @notice Gets the number of operators in a specific operator set - /// @param operatorSets The storage reference to operator sets mapping - /// @param operatorSetId The encoded ID of the operator set - /// @return The number of operators in the set - function getOperatorSetLength32( - OperatorSets storage operatorSets, - uint32 operatorSetId - ) - internal - view - returns (uint256) - { - if (operatorSets.operatorSetIds32.contains(uint256(operatorSetId))) { - return operatorSets.sets32[operatorSetId].length(); - } else { - revert OperatorSetLib__OperatorSetDoesNotExist(); - } - } - - /// @notice Gets all operator sets - /// @param operatorSets The storage reference to operator sets mapping - /// @return Array of operator set IDs - function getOperatorSets96(OperatorSets storage operatorSets) - internal - view - returns (uint96[] memory) - { - uint256[] memory rawValues = operatorSets.operatorSetIds96.values(); - uint96[] memory result = new uint96[](rawValues.length); - for (uint256 i = 0; i < rawValues.length; i++) { - result[i] = SafeCast.toUint96(rawValues[i]); - } - return result; - } - - /// @notice Gets all operator sets - /// @param operatorSets The storage reference to operator sets mapping - /// @return Array of operator set IDs - function getOperatorSets32(OperatorSets storage operatorSets) internal view returns (uint32[] memory) { - uint256[] memory rawValues = operatorSets.operatorSetIds32.values(); + uint256[] memory rawValues = linglongSubsets.linglongSubsetIds.values(); uint32[] memory result = new uint32[](rawValues.length); for (uint256 i = 0; i < rawValues.length; i++) { - result[i] = SafeCast.toUint32(rawValues[i]); + uint32 linglongSubsetId = SafeCast.toUint32(rawValues[i]); + if (isOperatorInLinglongSubset(linglongSubsets, linglongSubsetId, operator)) { + result[i] = linglongSubsetId; + } } return result; } - /// @param operatorSets The storage reference to operator sets mapping - /// @param operatorSetId The encoded ID of the operator set - /// @param index The index of the operator to retrieve - /// @return The operator address at the given index - function getOperatorAt96( - OperatorSets storage operatorSets, - uint96 operatorSetId, - uint256 index - ) - internal - view - returns (address) - { - if (operatorSets.operatorSetIds96.contains(uint256(operatorSetId))) { - return operatorSets.sets96[operatorSetId].at(index); - } else { - revert OperatorSetLib__OperatorSetDoesNotExist(); - } - } - - /// @param operatorSets The storage reference to operator sets mapping - /// @param operatorSetId The encoded ID of the operator set - /// @param index The index of the operator to retrieve - /// @return The operator address at the given index - function getOperatorAt32( - OperatorSets storage operatorSets, - uint32 operatorSetId, - uint256 index + /// @notice Gets the number of operators in a specific linglong subset + /// @param linglongSubsets The storage reference to linglong subsets mapping + /// @param linglongSubsetId The ID of the linglong subset + /// @return The number of operators in the subset + function getLinglongSubsetLength( + LinglongSubsets storage linglongSubsets, + uint32 linglongSubsetId ) internal view - returns (address) + returns (uint256) { - if (operatorSets.operatorSetIds32.contains(uint256(operatorSetId))) { - return operatorSets.sets32[operatorSetId].at(index); + if (linglongSubsets.linglongSubsetIds.contains(linglongSubsetId)) { + return linglongSubsets.operatorSetMembers[linglongSubsetId].length(); } else { revert OperatorSetLib__OperatorSetDoesNotExist(); } @@ -639,27 +244,15 @@ library OperatorSubsetLib { /* ========== MIN STAKE HELPERS ========== */ - /// @notice Returns the minimum stake required for a uint32 operator set - function getMinStake32( - OperatorSets storage operatorSets, - uint32 encodedId - ) - internal - view - returns (uint256) - { - return operatorSets.minStake32[encodedId]; - } - - /// @notice Returns the minimum stake required for a uint96 operator set - function getMinStake96( - OperatorSets storage operatorSets, - uint96 encodedId + /// @notice Returns the minimum stake required for a linglong subset + function getMinStake( + LinglongSubsets storage linglongSubsets, + uint32 linglongSubsetId ) internal view returns (uint256) { - return operatorSets.minStake96[encodedId]; + return linglongSubsets.minStake[linglongSubsetId]; } } diff --git a/src/libs/SymbioticNetworkMiddlewareLib.sol b/src/libs/SymbioticNetworkMiddlewareLib.sol index d233c95..0fe8182 100644 --- a/src/libs/SymbioticNetworkMiddlewareLib.sol +++ b/src/libs/SymbioticNetworkMiddlewareLib.sol @@ -18,6 +18,8 @@ import { OperatorSubsetLib } from "./OperatorSubsetLib.sol"; import { SafeCast96To32Lib } from "./SafeCast96To32Lib.sol"; import { SafeCast96To32Lib } from "./SafeCast96To32Lib.sol"; + +import { SafeCast } from "@openzeppelin-contracts/contracts/utils/math/SafeCast.sol"; import { Subnetworks } from "@symbiotic-middleware-sdk/extensions/Subnetworks.sol"; import { Subnetwork } from "@symbiotic/contracts/libraries/Subnetwork.sol"; @@ -25,7 +27,6 @@ import { Subnetwork } from "@symbiotic/contracts/libraries/Subnetwork.sol"; /// @notice Library containing core logic for the SymbioticNetworkMiddleware contract library SymbioticNetworkMiddlewareLib { using EnumerableSet for EnumerableSet.Bytes32Set; - using OperatorSubsetLib for uint96; using EnumerableMapLib for EnumerableMapLib.Uint256ToBytes32Map; using SafeCast96To32Lib for uint96[]; using SafeCast96To32Lib for uint96; @@ -197,7 +198,9 @@ library SymbioticNetworkMiddlewareLib { view returns (uint96[] memory allocatedSubnetworks) { - uint96[] memory subnetworks = registryCoordinator.getSymbioticSubnetworks(); + uint96[] memory subnetworks = new uint96[](2); + subnetworks[0] = OperatorSubsetLib.SYMBIOTIC_VALIDATOR_SUBSET_ID; + subnetworks[1] = OperatorSubsetLib.SYMBIOTIC_UNDERWRITER_SUBSET_ID; // First allocate a temporary array to hold all potential subnetworks uint96[] memory tempAllocated = new uint96[](subnetworks.length); @@ -205,16 +208,12 @@ library SymbioticNetworkMiddlewareLib { // First pass: Add all allocated subnetworks to the temporary array for (uint256 i = 0; i < subnetworks.length; i++) { - (, uint96 subnetworkId) = subnetworks[i].decodeOperatorSetId96(); - if ( - registryCoordinator.isSymbioticOperatorInSubnetwork( - subnetworkId, operator - ) - ) { + uint32 subnetworkId = uint32(subnetworks[i]); + if (registryCoordinator.isOperatorInLinglongSubset(subnetworkId, operator)) { // Check if this subnetworkId is already in the array bool isDuplicate = false; for (uint256 j = 0; j < allocatedCount; j++) { - if (tempAllocated[j] == subnetworkId) { + if (tempAllocated[j] == SafeCast.toUint96(subnetworkId)) { isDuplicate = true; break; } @@ -222,7 +221,7 @@ library SymbioticNetworkMiddlewareLib { // Only add if not a duplicate if (!isDuplicate) { - tempAllocated[allocatedCount] = subnetworkId; + tempAllocated[allocatedCount] = SafeCast.toUint96(subnetworkId); allocatedCount++; } } diff --git a/src/operator-registries/TaiyiRegistryCoordinator.sol b/src/operator-registries/TaiyiRegistryCoordinator.sol index 5e3e9ed..826b406 100644 --- a/src/operator-registries/TaiyiRegistryCoordinator.sol +++ b/src/operator-registries/TaiyiRegistryCoordinator.sol @@ -45,9 +45,11 @@ import { IPauserRegistry } from "eigenlayer-contracts/src/contracts/interfaces/IPauserRegistry.sol"; import "forge-std/console.sol"; -/// @title A `TaiyiRegistryCoordinator` that has two registries: -/// 1) a `PubkeyRegistry` that keeps track of operators' public keys -/// 2) a `SocketRegistry` that keeps track of operators' sockets (arbitrary strings) +/// @title TaiyiRegistryCoordinator +/// @notice A registry coordinator that manages operator registrations for both EigenLayer and Symbiotic protocols +/// @dev Maintains two registries: +/// 1) PubkeyRegistry: Tracks operators' public keys +/// 2) SocketRegistry: Tracks operators' socket addresses contract TaiyiRegistryCoordinator is ITaiyiRegistryCoordinator, TaiyiRegistryCoordinatorStorage, @@ -60,10 +62,8 @@ contract TaiyiRegistryCoordinator is using BN254 for BN254.G1Point; using EnumerableSet for EnumerableSet.AddressSet; using EnumerableSet for EnumerableSet.UintSet; - using OperatorSubsetLib for OperatorSubsetLib.OperatorSets; + using OperatorSubsetLib for OperatorSubsetLib.LinglongSubsets; using RestakingProtocolMapLib for RestakingProtocolMapLib.Map; - using OperatorSubsetLib for uint96; - using OperatorSubsetLib for uint32; using SafeCast96To32Lib for uint96; using SafeCast96To32Lib for uint32; using SafeCast96To32Lib for uint96[]; @@ -73,19 +73,35 @@ contract TaiyiRegistryCoordinator is // ================================= MODIFIERS ================================================= // ============================================================================================== - /// @notice Modifier that allows only registered middleware contracts to call a function + /// @notice Restricts function access to registered restaking middleware contracts modifier onlyRestakingMiddleware() { require(restakingProtocolMap.contains(msg.sender), OnlyRestakingMiddleware()); _; } - modifier onlyEigenLayerMiddleware() { - require(msg.sender == eigenLayerMiddleware, OnlyEigenlayerMiddleware()); + modifier onlyMiddleware() { + require( + msg.sender == eigenLayerMiddleware || msg.sender == symbioticMiddleware, + OnlyMiddleware() + ); _; } - modifier onlySymbioticMiddleware() { - require(msg.sender == symbioticMiddleware, OnlySymbioticMiddleware()); + /// @notice Restricts function access to Symbiotic protocol subset IDs + modifier onlySymbioticSubsetId(uint32 linglongSubsetId) { + require( + OperatorSubsetLib.isSymbioticProtocolID(linglongSubsetId), + OnlySymbioticSubsetId() + ); + _; + } + + /// @notice Restricts function access to EigenLayer protocol subset IDs + modifier onlyEigenLayerSubsetId(uint32 linglongSubsetId) { + require( + OperatorSubsetLib.isEigenlayerProtocolID(linglongSubsetId), + OnlyEigenlayerSubsetId() + ); _; } @@ -93,6 +109,9 @@ contract TaiyiRegistryCoordinator is // ================================= CONSTRUCTOR & INITIALIZER ================================= // ============================================================================================== + /// @notice Constructor for the TaiyiRegistryCoordinator + /// @param _allocationManager Address of the allocation manager contract + /// @param _pauserRegistry Address of the pauser registry contract constructor( IAllocationManager _allocationManager, IPauserRegistry _pauserRegistry, @@ -104,10 +123,11 @@ contract TaiyiRegistryCoordinator is _disableInitializers(); } - /// @notice Initialize the contract - /// @param initialOwner Address of contract owner - /// @param initialPausedStatus Initial paused status - /// @param _allocationManager Address of allocation manager + /// @notice Initializes the contract with required parameters + /// @param initialOwner Address of the contract owner + /// @param initialPausedStatus Initial paused status for the contract + /// @param _allocationManager Address of the allocation manager contract + /// @param _eigenLayerMiddleware Address of the EigenLayer middleware contract function initialize( address initialOwner, uint256 initialPausedStatus, @@ -122,7 +142,6 @@ contract TaiyiRegistryCoordinator is _transferOwnership(initialOwner); _setPausedStatus(initialPausedStatus); - // Set allocationManager from parameter if (_allocationManager != address(0)) { allocationManager = IAllocationManager(_allocationManager); } @@ -136,11 +155,14 @@ contract TaiyiRegistryCoordinator is // ================================= EXTERNAL WRITE FUNCTIONS ================================== // ============================================================================================== - /// @inheritdoc IAVSRegistrar + /// @notice Registers an operator for either EigenLayer or Symbiotic protocol + /// @param operator Address of the operator to register + /// @param linglongSubsetIds Array of subset IDs to register the operator for + /// @param data Additional registration data including socket and pubkey information function registerOperator( address operator, address, /*avs*/ - uint32[] memory operatorSetIds, + uint32[] memory linglongSubsetIds, bytes calldata data ) external @@ -148,30 +170,33 @@ contract TaiyiRegistryCoordinator is onlyWhenNotPaused(PAUSED_REGISTER_OPERATOR) { if (restakingProtocolMap.get(msg.sender) == RestakingProtocol.SYMBIOTIC) { - _registerOperatorForSymbiotic(operator, operatorSetIds.toUint96Array(), data); + _registerOperatorForSymbiotic(operator, linglongSubsetIds); } else if (msg.sender == address(allocationManager)) { - _registerOperatorForEigenlayer(operator, operatorSetIds, data); + _registerOperatorForEigenlayer(operator, linglongSubsetIds, data); } } - /// @inheritdoc IAVSRegistrar + /// @notice Deregisters an operator from either EigenLayer or Symbiotic protocol + /// @param operator Address of the operator to deregister + /// @param linglongSubsetIds Array of subset IDs to deregister the operator from function deregisterOperator( address operator, address, /*avs*/ - uint32[] memory operatorSetIds + uint32[] memory linglongSubsetIds ) external override(IAVSRegistrar, ITaiyiRegistryCoordinator) onlyWhenNotPaused(PAUSED_DEREGISTER_OPERATOR) { if (restakingProtocolMap.get(msg.sender) == RestakingProtocol.SYMBIOTIC) { - _deregisterOperatorForSymbiotic(operator, operatorSetIds.toUint96Array()); + _deregisterOperatorForSymbiotic(operator); } else if (msg.sender == address(allocationManager)) { - _deregisterOperatorForEigenlayer(operator, operatorSetIds); + _deregisterOperatorForEigenlayer(operator, linglongSubsetIds); } } - /// @inheritdoc ITaiyiRegistryCoordinator + /// @notice Updates an operator's socket address + /// @param socket New socket address for the operator function updateSocket(string memory socket) external { require( _operatorInfo[msg.sender].status == OperatorStatus.REGISTERED, NotRegistered() @@ -179,53 +204,40 @@ contract TaiyiRegistryCoordinator is _setOperatorSocket(_operatorInfo[msg.sender].operatorId, socket); } - /// @dev This function is only callable by the Symbiotic middleware - /// @inheritdoc ITaiyiRegistryCoordinator - function createSubnetwork( - uint96 operatorSetId, - uint256 minStake - ) - external - onlySymbioticMiddleware - { - _operatorSets.createOperatorSet96(operatorSetId, minStake); - } - - /// @dev This function is only callable by the Eigenlayer middleware - /// @inheritdoc ITaiyiRegistryCoordinator - function createOperatorSet( - uint32 operatorSetId, + /// @notice Creates a new Linglong subset for the Symbiotic protocol + /// @param linglongSubsetId ID of the new subset + /// @param minStake Minimum stake required for the subset + function createLinglongSubset( + uint32 linglongSubsetId, uint256 minStake ) external - onlyEigenLayerMiddleware + onlyMiddleware { - _operatorSets.createOperatorSet32(operatorSetId, minStake); + _linglongSubsets.createLinglongSubset(linglongSubsetId, minStake); } // ============================================================================================== // ================================= OWNER/ADMIN FUNCTIONS ===================================== // ============================================================================================== - /// @notice Updates the reference to the socket registry - /// @param _socketRegistry The new socket registry address - /// @dev This is needed for testing purposes when dealing with proxies + /// @notice Updates the socket registry address + /// @param _socketRegistry New socket registry address function updateSocketRegistry(address _socketRegistry) external onlyOwner { require(_socketRegistry != address(0), "Socket registry cannot be zero address"); socketRegistry = ISocketRegistry(_socketRegistry); } - /// @notice Updates the reference to the pubkey registry - /// @param _pubkeyRegistry The new pubkey registry address - /// @dev This is needed for testing purposes when dealing with proxies + /// @notice Updates the pubkey registry address + /// @param _pubkeyRegistry New pubkey registry address function updatePubkeyRegistry(address _pubkeyRegistry) external onlyOwner { require(_pubkeyRegistry != address(0), "Pubkey registry cannot be zero address"); pubkeyRegistry = IPubkeyRegistry(_pubkeyRegistry); } /// @notice Sets the protocol type for a middleware address - /// @param _restakingMiddleware The middleware address - /// @param _restakingProtocol The protocol type (EIGENLAYER or SYMBIOTIC) + /// @param _restakingMiddleware Middleware address to set protocol for + /// @param _restakingProtocol Protocol type (EIGENLAYER or SYMBIOTIC) function setRestakingProtocol( address _restakingMiddleware, RestakingProtocol _restakingProtocol @@ -240,7 +252,9 @@ contract TaiyiRegistryCoordinator is // ================================= EXTERNAL VIEW FUNCTIONS =================================== // ============================================================================================== - /// @inheritdoc IAVSRegistrar + /// @notice Checks if the contract supports a specific AVS + /// @param avs Address of the AVS to check + /// @return bool True if the AVS is supported function supportsAVS(address avs) external view returns (bool) { return avs == eigenLayerMiddleware; } @@ -251,27 +265,26 @@ contract TaiyiRegistryCoordinator is return restakingProtocolMap.addresses(); } - /// @notice Gets all operator sets - /// @return Array of operator set IDs - function getSymbioticSubnetworks() external view returns (uint96[] memory) { - return _operatorSets.getOperatorSets96(); - } - - /// @notice Gets all operator sets - /// @return Array of operator set IDs - function getEigenLayerOperatorSets() external view returns (uint32[] memory) { - return _operatorSets.getOperatorSets32(); + /// @notice Gets all Linglong subset IDs + /// @return Array of subset IDs + function getLinglongSubnets() external view returns (uint32[] memory) { + uint256[] memory subnetIds = _linglongSubsets.linglongSubsetIds.values(); + uint32[] memory subsetIds = new uint32[](subnetIds.length); + for (uint256 i = 0; i < subnetIds.length; i++) { + subsetIds[i] = uint32(subnetIds[i]); + } + return subsetIds; } - /// @notice Checks if a middleware is a restaking middleware - /// @param middleware The middleware address to check - /// @return True if the middleware is a restaking middleware, false otherwise + /// @notice Checks if an address is a registered middleware + /// @param middleware Address to check + /// @return bool True if the address is a registered middleware function isRestakingMiddleware(address middleware) external view returns (bool) { return restakingProtocolMap.contains(middleware); } /// @notice Gets all middleware addresses for a specific protocol - /// @param protocol The protocol type to filter by + /// @param protocol Protocol type to filter by /// @return Array of middleware addresses for the specified protocol function getRestakingMiddlewareByProtocol(RestakingProtocol protocol) external @@ -282,8 +295,8 @@ contract TaiyiRegistryCoordinator is } /// @notice Gets the protocol type for a middleware address - /// @param middleware The middleware address to query - /// @return The protocol type associated with the middleware + /// @param middleware Middleware address to query + /// @return Protocol type associated with the middleware function getMiddlewareProtocol(address middleware) external view @@ -292,92 +305,34 @@ contract TaiyiRegistryCoordinator is return restakingProtocolMap.get(middleware); } - /// @notice Gets an operator from an operator set by address - /// @param baseOperatorSetId The base operator set ID - /// @param operator The operator address - /// @return True if the operator is in the set, false otherwise - function getEigenLayerOperatorFromOperatorSet( - uint32 baseOperatorSetId, - address operator - ) - external - view - returns (bool) - { - return _operatorSets.isOperatorInSet32( - baseOperatorSetId.encodeOperatorSetId32(RestakingProtocol.EIGENLAYER), - operator - ); - } - - /// @notice Gets an operator from a subnetwork by address - /// @param baseSubnetworkId The base subnetwork ID - /// @param operator The operator address - /// @return True if the operator is in the set, false otherwise - function getSymbioticOperatorFromOperatorSet( - uint96 baseSubnetworkId, + /// @notice Checks if an operator is in a specific Linglong subset + /// @param linglongSubsetId ID of the subset to check + /// @param operator Address of the operator to check + /// @return bool True if the operator is in the subset + function isOperatorInLinglongSubset( + uint32 linglongSubsetId, address operator ) external view returns (bool) { - return _operatorSets.isOperatorInSet96( - baseSubnetworkId.encodeOperatorSetId96(RestakingProtocol.SYMBIOTIC), operator - ); - } - - function isEigenlayerOperatorSetExist(uint32 operatorSetId) - external - view - returns (bool) - { - return _operatorSets.operatorSetIds32.contains(operatorSetId); + return _linglongSubsets.isOperatorInLinglongSubset(linglongSubsetId, operator); } - function isSymbioticOperatorSetExist(uint96 operatorSetId) + /// @notice Checks if a Linglong subset exists + /// @param linglongSubsetId ID of the subset to check + /// @return bool True if the subset exists + function isLinglongSubsetExist(uint32 linglongSubsetId) external view returns (bool) { - return _operatorSets.operatorSetIds96.contains(operatorSetId); - } - /// @notice Checks if an operator is in a specific operator set - /// @param baseOperatorSetId The base operator set ID - /// @param operator The operator address - /// @return True if the operator is in the set, false otherwise - - function isEigenLayerOperatorInSet( - uint32 baseOperatorSetId, - address operator - ) - external - view - returns (bool) - { - return _operatorSets.isOperatorInSet32( - baseOperatorSetId.encodeOperatorSetId32(RestakingProtocol.EIGENLAYER), - operator - ); - } - - /// @notice Checks if an operator is in a specific symbiotic operator set - /// @param baseSubnetworkId The base subnetwork ID - /// @param operator The operator address - /// @return True if the operator is in the set, false otherwise - function isSymbioticOperatorInSubnetwork( - uint96 baseSubnetworkId, - address operator - ) - external - view - returns (bool) - { - return _operatorSets.isOperatorInSet96( - baseSubnetworkId.encodeOperatorSetId96(RestakingProtocol.SYMBIOTIC), operator - ); + return _linglongSubsets.linglongSubsetIds.contains(linglongSubsetId); } + /// @notice Gets the count of operator sets + /// @return uint32 Number of operator sets function getOperatorSetCount() external view returns (uint32) { if (restakingProtocolMap.get(msg.sender) == RestakingProtocol.SYMBIOTIC) { return uint32( @@ -388,61 +343,32 @@ contract TaiyiRegistryCoordinator is } } - /// @notice Gets the operators in a specific eigenlayer operator set - /// @param baseOperatorSetId The base operator set ID - /// @return The operator set - function getEigenLayerOperatorSetOperators(uint32 baseOperatorSetId) - external - view - returns (address[] memory) - { - return _operatorSets.getOperatorsInSet32( - baseOperatorSetId.encodeOperatorSetId32(RestakingProtocol.EIGENLAYER) - ); - } - - /// @notice Gets the operators in a specific symbiotic subnetwork - /// @param baseSubnetworkId The base subnetwork ID - /// @return The operator set - function getSymbioticSubnetworkOperators(uint96 baseSubnetworkId) + /// @notice Gets all operators in a specific Linglong subset + /// @param linglongSubsetId ID of the subset to query + /// @return Array of operator addresses in the subset + function getLinglongSubsetOperators(uint32 linglongSubsetId) external view returns (address[] memory) { - return _operatorSets.getOperatorsInSet96( - baseSubnetworkId.encodeOperatorSetId96(RestakingProtocol.SYMBIOTIC) - ); + return _linglongSubsets.getOperatorsInLinglongSubset(linglongSubsetId); } - /// @notice Gets the size of a specific eigenlayer operator set - /// @param baseOperatorSetId The base operator set ID - /// @return The size of the operator set - function getEigenLayerOperatorSetSize(uint32 baseOperatorSetId) + /// @notice Gets the size of a specific Linglong subset + /// @param linglongSubsetId ID of the subset to query + /// @return uint256 Number of operators in the subset + function getLinglongSubsetSize(uint32 linglongSubsetId) external view returns (uint256) { - return _operatorSets.getOperatorSetLength32( - baseOperatorSetId.encodeOperatorSetId32(RestakingProtocol.EIGENLAYER) - ); + return _linglongSubsets.getOperatorsInLinglongSubset(linglongSubsetId).length; } - /// @notice Gets the size of a specific symbiotic subnetwork - /// @param baseSubnetworkId The base subnetwork ID - /// @return The size of the subnetwork - function getSymbioticSubnetworkSize(uint96 baseSubnetworkId) - external - view - returns (uint256) - { - return _operatorSets.getOperatorSetLength96( - baseSubnetworkId.encodeOperatorSetId96(RestakingProtocol.SYMBIOTIC) - ); - } - - /// @notice Returns all operator sets that an operator has allocated magnitude to - /// @param operator The operator whose allocated sets to fetch - /// @return sets The allocated operator sets + /// @notice Gets all operator sets that an operator has allocated magnitude to + /// @param operator Address of the operator to query + /// @param protocol Protocol type to filter by + /// @return sets Allocated operator sets for the operator function getOperatorAllocatedOperatorSets( address operator, RestakingProtocol protocol @@ -452,22 +378,18 @@ contract TaiyiRegistryCoordinator is returns (AllocatedOperatorSets memory sets) { if (protocol == RestakingProtocol.SYMBIOTIC) { - // Get Symbiotic subnetwork (uint96) uint96[] memory symbioticSubnetworkIds = ISymbioticNetworkMiddleware( symbioticMiddleware ).getOperatorAllocatedSubnetworks(operator); - // Initialize the symbioticSets array sets.symbioticSets = new uint96[](symbioticSubnetworkIds.length); for (uint256 i = 0; i < symbioticSubnetworkIds.length; i++) { sets.symbioticSets[i] = symbioticSubnetworkIds[i]; } } else if (protocol == RestakingProtocol.EIGENLAYER) { - // Get EigenLayer operator sets (uint32) OperatorSet[] memory eigenLayerSets = allocationManager.getAllocatedSets(operator); - // Initialize the eigenLayerSets array sets.eigenLayerSets = new uint32[](eigenLayerSets.length); for (uint256 i = 0; i < eigenLayerSets.length; i++) { sets.eigenLayerSets[i] = eigenLayerSets[i].id; @@ -477,21 +399,21 @@ contract TaiyiRegistryCoordinator is return sets; } - /// @notice Returns all strategies that an operator has allocated magnitude to in a specific operator set - /// @param operator The operator whose allocated strategies to fetch - /// @param baseOperatorSetId The ID of the operator set to query + /// @notice Gets all strategies that an operator has allocated magnitude to in a specific EigenLayer subset + /// @param operator Address of the operator to query + /// @param linglongSubsetId ID of the subset to query + /// @return Array of strategy addresses function getEigenLayerOperatorAllocatedStrategies( address operator, - uint32 baseOperatorSetId + uint32 linglongSubsetId ) external view + onlyEigenLayerSubsetId(linglongSubsetId) returns (address[] memory) { - OperatorSet memory operatorSet = OperatorSet({ - avs: msg.sender, - id: baseOperatorSetId.encodeOperatorSetId32(RestakingProtocol.EIGENLAYER) - }); + OperatorSet memory operatorSet = + OperatorSet({ avs: eigenLayerMiddleware, id: linglongSubsetId }); IStrategy[] memory strategies = allocationManager.getAllocatedStrategies(operator, operatorSet); address[] memory allocatedStrategies = new address[](strategies.length); @@ -501,48 +423,50 @@ contract TaiyiRegistryCoordinator is return allocatedStrategies; } - /// @notice Returns all strategies that an operator has allocated magnitude to in a specific symbiotic subnetwork - /// @param operator The operator whose allocated strategies to fetch - /// @param baseSubnetworkId The ID of the subnetwork to query + /// @notice Gets all strategies that an operator has allocated magnitude to in a specific Symbiotic subset + /// @param operator Address of the operator to query + /// @param linglongSubsetId ID of the subset to query + /// @return allocatedStrategies of strategy addresses function getSymbioticOperatorAllocatedStrategies( address operator, - uint96 baseSubnetworkId + uint32 linglongSubsetId ) external view + onlySymbioticSubsetId(linglongSubsetId) returns (address[] memory allocatedStrategies) { (, allocatedStrategies,) = ISymbioticNetworkMiddleware(symbioticMiddleware) - .getOperatorCollaterals( - operator, baseSubnetworkId.encodeOperatorSetId96(RestakingProtocol.SYMBIOTIC) - ); + .getOperatorCollaterals(operator, linglongSubsetId); } + /// @notice Gets the amount of a specific strategy allocated by an operator in a Symbiotic subset + /// @param operator Address of the operator to query + /// @param linglongSubsetId ID of the subset to query + /// @param strategy Strategy to query allocation for + /// @return uint256 Amount of the strategy allocated function getSymbioticOperatorAllocatedStrategiesAmount( address operator, - uint96 baseSubnetworkId, + uint32 linglongSubsetId, IStrategy strategy ) external + onlySymbioticSubsetId(linglongSubsetId) returns (uint256) { - // 1. Get the operator's collaterals for this subnetwork ( address[] memory vaults, address[] memory collateralTokens, uint256[] memory stakedAmounts ) = ISymbioticNetworkMiddleware(symbioticMiddleware).getOperatorCollaterals( - operator, baseSubnetworkId + operator, linglongSubsetId ); - // 2. Find the matching strategy and return its allocation address strategyAddress = address(strategy); - // Check if operator has any vaults/collaterals if (collateralTokens.length == 0) { - // Operator has no registered collaterals in this subnetwork emit OperatorAllocationQuery( - operator, baseSubnetworkId, address(strategy), 0, "No collaterals found" + operator, linglongSubsetId, address(strategy), 0, "No collaterals found" ); return 0; } @@ -550,20 +474,18 @@ contract TaiyiRegistryCoordinator is for (uint256 i = 0; i < collateralTokens.length; i++) { if (collateralTokens[i] == strategyAddress) { if (stakedAmounts[i] > 0) { - // Found a matching strategy with allocation emit OperatorAllocationQuery( operator, - baseSubnetworkId, + linglongSubsetId, address(strategy), stakedAmounts[i], "Allocation found" ); return stakedAmounts[i]; } else { - // Strategy exists but has zero allocation emit OperatorAllocationQuery( operator, - baseSubnetworkId, + linglongSubsetId, address(strategy), 0, "Zero allocation" @@ -573,33 +495,34 @@ contract TaiyiRegistryCoordinator is } } - // Strategy not found among operator's collaterals emit OperatorAllocationQuery( - operator, baseSubnetworkId, address(strategy), 0, "Strategy not found" + operator, linglongSubsetId, address(strategy), 0, "Strategy not found" ); return 0; } - /// @dev Returns 0 if the operator has no allocation for this strategy + /// @notice Gets the amount of a specific strategy allocated by an operator in an EigenLayer subset + /// @param operator Address of the operator to query + /// @param linglongSubsetId ID of the subset to query + /// @param strategy Strategy to query allocation for + /// @return uint256 Amount of the strategy allocated function getEigenLayerOperatorAllocatedStrategiesAmount( address operator, - uint32 baseOperatorSetId, + uint32 linglongSubsetId, IStrategy strategy ) external + onlyEigenLayerSubsetId(linglongSubsetId) returns (uint256) { - OperatorSet memory operatorSet = OperatorSet({ - avs: msg.sender, - id: baseOperatorSetId.encodeOperatorSetId32(RestakingProtocol.EIGENLAYER) - }); + OperatorSet memory operatorSet = + OperatorSet({ avs: eigenLayerMiddleware, id: linglongSubsetId }); IAllocationManagerTypes.Allocation memory allocation = allocationManager.getAllocation(operator, operatorSet, strategy); - // Log the query result emit OperatorAllocationQuery( operator, - baseOperatorSetId, + linglongSubsetId, address(strategy), allocation.currentMagnitude, allocation.effectBlock >= block.number @@ -610,25 +533,34 @@ contract TaiyiRegistryCoordinator is return allocation.currentMagnitude; } - /// ======================================================================================== - /// ============== EIGENLAYER OUT-PROTOCOL OPERATOR VIEW FUNCTIONS ========================= - /// ======================================================================================== + // ============================================================================================== + // ================================= OPERATOR VIEW FUNCTIONS =================================== + // ============================================================================================== + /// @notice Gets information about an operator + /// @param operator Address of the operator to query + /// @return OperatorInfo Information about the operator function getOperator(address operator) external view returns (OperatorInfo memory) { return _operatorInfo[operator]; } - /// @notice Returns the operatorId for the given `operator` + /// @notice Gets the operator ID for an operator address + /// @param operator Address of the operator to query + /// @return bytes32 Operator ID function getOperatorId(address operator) external view returns (bytes32) { return _operatorInfo[operator].operatorId; } - /// @notice Returns the operator address for the given `operatorId` + /// @notice Gets the operator address for an operator ID + /// @param operatorId ID of the operator to query + /// @return address Operator address function getOperatorFromId(bytes32 operatorId) external view returns (address) { return pubkeyRegistry.getOperatorFromId(operatorId); } - /// @notice Returns the status for the given `operator` + /// @notice Gets the status of an operator + /// @param operator Address of the operator to query + /// @return OperatorStatus Status of the operator function getOperatorStatus(address operator) external view @@ -637,8 +569,9 @@ contract TaiyiRegistryCoordinator is return _operatorInfo[operator].status; } - /// @notice Returns the message hash that an operator must sign to register their BLS public key. - /// @param operator is the address of the operator registering their BLS public key + /// @notice Gets the message hash for pubkey registration + /// @param operator Address of the operator registering their pubkey + /// @return BN254.G1Point Message hash for pubkey registration function pubkeyRegistrationMessageHash(address operator) public view @@ -647,8 +580,9 @@ contract TaiyiRegistryCoordinator is return BN254.hashToG1(calculatePubkeyRegistrationMessageHash(operator)); } - /// @notice Returns the message hash that an operator must sign to register their BLS public key. - /// @param operator is the address of the operator registering their BLS public key + /// @notice Calculates the message hash for pubkey registration + /// @param operator Address of the operator registering their pubkey + /// @return bytes32 Message hash for pubkey registration function calculatePubkeyRegistrationMessageHash(address operator) public pure @@ -657,12 +591,10 @@ contract TaiyiRegistryCoordinator is return keccak256(abi.encode(PUBKEY_REGISTRATION_TYPEHASH, operator)); } - /** - * @notice External function to decode operator data - * @param data The data to decode - * @return socket The socket string - * @return params The PubkeyRegistrationParams - */ + /// @notice Decodes operator registration data + /// @param data Data to decode + /// @return socket Socket address + /// @return params Pubkey registration parameters function decodeOperatorData(bytes calldata data) external pure @@ -678,6 +610,9 @@ contract TaiyiRegistryCoordinator is // ================================= INTERNAL FUNCTIONS ======================================== // ============================================================================================== + /// @notice Sets the protocol type for a middleware address + /// @param _restakingMiddleware Middleware address to set protocol for + /// @param _restakingProtocol Protocol type to set function _setRestakingProtocol( address _restakingMiddleware, RestakingProtocol _restakingProtocol @@ -690,7 +625,6 @@ contract TaiyiRegistryCoordinator is ); restakingProtocolMap.set(_restakingMiddleware, _restakingProtocol); - // Update the specific middleware references for easier access if (_restakingProtocol == RestakingProtocol.SYMBIOTIC) { symbioticMiddleware = _restakingMiddleware; } else if (_restakingProtocol == RestakingProtocol.EIGENLAYER) { @@ -700,12 +634,10 @@ contract TaiyiRegistryCoordinator is emit RestakingMiddlewareUpdated(_restakingProtocol, _restakingMiddleware); } - /// @notice Fetches an operator's pubkey hash from the PubkeyRegistry. If the - /// operator has not registered a pubkey, attempts to register a pubkey using - /// `params` - /// @param operator the operator whose pubkey to query from the PubkeyRegistry - /// @param params contains the G1 & G2 public keys of the operator, and a signature proving their ownership - /// @dev `params` can be empty if the operator has already registered a pubkey in the PubkeyRegistry + /// @notice Gets or creates an operator ID + /// @param operator Address of the operator + /// @param params Pubkey registration parameters + /// @return operatorId Operator ID function _getOrCreateOperatorId( address operator, IPubkeyRegistry.PubkeyRegistrationParams memory params @@ -716,10 +648,9 @@ contract TaiyiRegistryCoordinator is return pubkeyRegistry.getOrRegisterOperatorId(operator, params); } - /// @notice Updates an operator's socket address in the SocketRegistry - /// @param operatorId The unique identifier of the operator - /// @param socket The new socket address to set for the operator - /// @dev Emits an OperatorSocketUpdate event after updating + /// @notice Sets an operator's socket address + /// @param operatorId ID of the operator + /// @param socket New socket address function _setOperatorSocket(bytes32 operatorId, string memory socket) internal { socketRegistry.setOperatorSocket(operatorId, socket); emit OperatorSocketUpdate(operatorId, socket); @@ -729,9 +660,13 @@ contract TaiyiRegistryCoordinator is // ================================= PROTOCOL-SPECIFIC FUNCTIONS =============================== // ============================================================================================== + /// @notice Registers an operator for the EigenLayer protocol + /// @param operator Address of the operator to register + /// @param _linglongSubsetIds Array of subset IDs to register for + /// @param data Additional registration data function _registerOperatorForEigenlayer( address operator, - uint32[] memory operatorSetIds, + uint32[] memory _linglongSubsetIds, bytes calldata data ) internal @@ -752,22 +687,17 @@ contract TaiyiRegistryCoordinator is ISignatureUtilsMixinTypes.SignatureWithSaltAndExpiry ) ); - - /// If the operator has NEVER registered a pubkey before, use `params` to register - /// their pubkey in pubkeyRegistry - /// - /// If the operator HAS registered a pubkey, `params` is ignored and the pubkey hash - /// (operatorId) is fetched instead bytes32 operatorId = _getOrCreateOperatorId(operator, params); - _setOperatorSocket(operatorId, socket); - _operatorInfo[operator].status = OperatorStatus.REGISTERED; _operatorInfo[operator].operatorId = operatorId; - uint256[] memory stakes = _checkInitialEigenStake(operator, operatorSetIds); - uint256 aggregateStake; + uint256[] memory stakes = _checkInitialEigenStake(operator, _linglongSubsetIds); for (uint256 i = 0; i < stakes.length; ++i) { - uint256 minStake = _operatorSets.getMinStake32(operatorSetIds[i]); + require( + OperatorSubsetLib.isEigenlayerProtocolID(_linglongSubsetIds[i]), + "Invalid eigenlayer subset ID" + ); + uint256 minStake = _linglongSubsets.getMinStake(_linglongSubsetIds[i]); require(stakes[i] >= minStake, "Stake below set minimum"); } @@ -777,15 +707,15 @@ contract TaiyiRegistryCoordinator is ); } - // Use the library function to add operator to sets - _operatorSets.addOperatorToSets32( - operatorSetIds, RestakingProtocol.EIGENLAYER, operator - ); + _linglongSubsets.addOperatorToLinglongSubsets(_linglongSubsetIds, operator); } + /// @notice Deregisters an operator from the EigenLayer protocol + /// @param operator Address of the operator to deregister + /// @param _linglongSubsetIds Array of subset IDs to deregister from function _deregisterOperatorForEigenlayer( address operator, - uint32[] memory operatorSetIds + uint32[] memory _linglongSubsetIds ) internal { @@ -793,25 +723,22 @@ contract TaiyiRegistryCoordinator is require(operatorInfo.status == OperatorStatus.REGISTERED, OperatorNotRegistered()); operatorInfo.status = OperatorStatus.DEREGISTERED; - uint32[] memory baseOperatorSetIds = new uint32[](operatorSetIds.length); - for (uint256 i = 0; i < operatorSetIds.length; i++) { - (, uint32 baseId) = operatorSetIds[i].decodeOperatorSetId32(); - baseOperatorSetIds[i] = baseId; + for (uint256 i = 0; i < _linglongSubsetIds.length; i++) { + require( + OperatorSubsetLib.isEigenlayerProtocolID(_linglongSubsetIds[i]), + "Invalid eigenlayer subset ID" + ); } - _operatorSets.removeOperatorFromSets32( - baseOperatorSetIds, RestakingProtocol.EIGENLAYER, operator - ); + _linglongSubsets.removeOperatorFromLinglongSubsets(_linglongSubsetIds, operator); } - /// @notice Register an operator for the Symbiotic protocol - /// @dev Handles mapping of base subnetwork ID to appropriate operator set IDs - /// @param operator The operator to register - /// @param baseSubnetworkIds The base subnetwork ID (will be mapped to operator sets) + /// @notice Registers an operator for the Symbiotic protocol + /// @param operator Address of the operator to register + /// @param linglongSubsetIds Array of subset IDs to register for function _registerOperatorForSymbiotic( address operator, - uint96[] memory baseSubnetworkIds, - bytes calldata /*data*/ + uint32[] memory linglongSubsetIds ) internal { @@ -821,62 +748,52 @@ contract TaiyiRegistryCoordinator is ); _operatorInfo[operator].status = OperatorStatus.REGISTERED; - - uint96[] memory operatorSetIds = new uint96[](baseSubnetworkIds.length); - for (uint256 i = 0; i < baseSubnetworkIds.length; i++) { - operatorSetIds[i] = - baseSubnetworkIds[i].encodeOperatorSetId96(RestakingProtocol.SYMBIOTIC); + for (uint256 i = 0; i < linglongSubsetIds.length; i++) { + require( + OperatorSubsetLib.isSymbioticProtocolID(linglongSubsetIds[i]), + "Invalid symbiotic subset ID" + ); } - _operatorSets.addOperatorToSets96( - operatorSetIds, RestakingProtocol.SYMBIOTIC, operator - ); + _linglongSubsets.addOperatorToLinglongSubsets(linglongSubsetIds, operator); } - /// @notice Deregister an operator from the Symbiotic protocol - /// @dev Handles mapping of subnetwork ID to appropriate operator set IDs for deregistration - /// @param operator The operator to deregister - /// @param subnetworkIds The subnetwork IDs (will be mapped to operator sets) - function _deregisterOperatorForSymbiotic( - address operator, - uint96[] memory subnetworkIds - ) - internal - { + /// @notice Deregisters an operator from the Symbiotic protocol + /// @param operator Address of the operator to deregister + function _deregisterOperatorForSymbiotic(address operator) internal { OperatorInfo storage operatorInfo = _operatorInfo[operator]; require(operatorInfo.status == OperatorStatus.REGISTERED, OperatorNotRegistered()); operatorInfo.status = OperatorStatus.DEREGISTERED; - // Use the library function to remove operator from sets - _operatorSets.removeOperatorFromSets96( - subnetworkIds, RestakingProtocol.SYMBIOTIC, operator - ); + uint32[] memory linglongSubsetIds = new uint32[](2); + linglongSubsetIds[0] = OperatorSubsetLib.SYMBIOTIC_VALIDATOR_SUBSET_ID; + linglongSubsetIds[1] = OperatorSubsetLib.SYMBIOTIC_UNDERWRITER_SUBSET_ID; + + _linglongSubsets.removeOperatorFromLinglongSubsets(linglongSubsetIds, operator); } /// @notice Checks the initial EigenLayer stake for an operator - /// @param operator The operator to check - /// @param operatorSetIds The operator sets to check - /// @return stakesPerSet Array of stake amounts per operatorSetId + /// @param operator Address of the operator to check + /// @param _linglongSubsetIds Array of subset IDs to check + /// @return stakesPerSet Array of stake amounts per subset function _checkInitialEigenStake( address operator, - uint32[] memory operatorSetIds + uint32[] memory _linglongSubsetIds ) internal view returns (uint256[] memory stakesPerSet) { - stakesPerSet = new uint256[](operatorSetIds.length); + stakesPerSet = new uint256[](_linglongSubsetIds.length); - // Access DelegationManager through AllocationManager's immutable variable IDelegationManager deleg = AllocationManager(address(allocationManager)).delegation(); - // Loop over each operator set we're registering for - for (uint256 k = 0; k < operatorSetIds.length; ++k) { - uint32 encodedSetId = operatorSetIds[k]; + for (uint256 k = 0; k < _linglongSubsetIds.length; ++k) { + uint32 subsetId = _linglongSubsetIds[k]; OperatorSet memory opSet = - OperatorSet({ avs: eigenLayerMiddleware, id: encodedSetId }); + OperatorSet({ avs: eigenLayerMiddleware, id: subsetId }); IStrategy[] memory strategies = allocationManager.getAllocatedStrategies(operator, opSet); @@ -894,7 +811,7 @@ contract TaiyiRegistryCoordinator is if (alloc.currentMagnitude == 0) continue; uint64 maxMag = allocationManager.getMaxMagnitude(operator, strategies[i]); - if (maxMag == 0) continue; // avoid div-by-zero, also implies no stake + if (maxMag == 0) continue; uint256 stakePortion = (shares[i] * uint256(alloc.currentMagnitude)) / uint256(maxMag); diff --git a/src/slasher/LinglongSlasher.sol b/src/slasher/LinglongSlasher.sol index 1f64121..56721c0 100644 --- a/src/slasher/LinglongSlasher.sol +++ b/src/slasher/LinglongSlasher.sol @@ -40,7 +40,6 @@ contract LinglongSlasher is Initializable, OwnableUpgradeable, LinglongSlasherSt using ECDSA for bytes32; using EnumerableSet for EnumerableSet.AddressSet; using EnumerableSet for EnumerableSet.Bytes32Set; - using OperatorSubsetLib for uint96; /// @dev Modifier to check that the contract is properly initialized modifier onlyInitialized() { @@ -374,12 +373,12 @@ contract LinglongSlasher is Initializable, OwnableUpgradeable, LinglongSlasherSt /// @dev Check if slashing is already in progress /// @param operator The operator address - /// @param operatorSetId The operator set ID + /// @param linglongSubsetId The operator set ID /// @param challengerContract The challenger contract address /// @return notInProgress True if slashing is not already in progress function _checkSlashingNotInProgress( address operator, - uint96 operatorSetId, + uint32 linglongSubsetId, address challengerContract ) internal @@ -394,7 +393,7 @@ contract LinglongSlasher is Initializable, OwnableUpgradeable, LinglongSlasherSt } (bool inProgress,) = - this.isSlashingInProgress(operator, operatorSetId, challengerContract); + this.isSlashingInProgress(operator, linglongSubsetId, challengerContract); return !inProgress; } @@ -433,11 +432,7 @@ contract LinglongSlasher is Initializable, OwnableUpgradeable, LinglongSlasherSt } // Check if slashing is already in progress - if ( - !_checkSlashingNotInProgress( - operator, uint96(operatorSetId), challengerContract - ) - ) { + if (!_checkSlashingNotInProgress(operator, operatorSetId, challengerContract)) { revert SlashingInProgress(); } @@ -483,15 +478,16 @@ contract LinglongSlasher is Initializable, OwnableUpgradeable, LinglongSlasherSt revert ProofVerificationFailed(); } - uint96 subnetwork; - uint96[] memory subnetworks = ISymbioticNetworkMiddleware(SYMBIOTIC_MIDDLEWARE) - .getOperatorAllocatedSubnetworks(operator); + uint32 subnetwork; + uint32[] memory subnetworks = new uint32[](2); + subnetworks[0] = OperatorSubsetLib.SYMBIOTIC_VALIDATOR_SUBSET_ID; + subnetworks[1] = OperatorSubsetLib.SYMBIOTIC_UNDERWRITER_SUBSET_ID; for (uint256 i = 0; i < subnetworks.length; i++) { - (, uint96 baseId) = subnetworks[i].decodeOperatorSetId96(); + uint32 baseId = subnetworks[i]; if ( ITaiyiRegistryCoordinator(TAIYI_REGISTRY_COORDINATOR) - .getSymbioticOperatorFromOperatorSet(baseId, operator) + .isOperatorInLinglongSubset(baseId, operator) ) { subnetwork = subnetworks[i]; break; @@ -634,7 +630,7 @@ contract LinglongSlasher is Initializable, OwnableUpgradeable, LinglongSlasherSt /// @inheritdoc ILinglongSlasher function isSlashingInProgress( address operator, - uint96 operatorSetId, + uint32 linglongSubsetId, address challengeContract ) external @@ -643,7 +639,7 @@ contract LinglongSlasher is Initializable, OwnableUpgradeable, LinglongSlasherSt returns (bool inProgress, uint256 slashingId) { return ILinglongChallenger(challengeContract).isSlashingInProgress( - operator, operatorSetId + operator, linglongSubsetId ); } } diff --git a/src/storage/TaiyiRegistryCoordinatorStorage.sol b/src/storage/TaiyiRegistryCoordinatorStorage.sol index 463fe39..e184c60 100644 --- a/src/storage/TaiyiRegistryCoordinatorStorage.sol +++ b/src/storage/TaiyiRegistryCoordinatorStorage.sol @@ -68,7 +68,7 @@ abstract contract TaiyiRegistryCoordinatorStorage is ITaiyiRegistryCoordinator { IAllocationManager public allocationManager; /// @notice operator sets with protocol type information - OperatorSubsetLib.OperatorSets internal _operatorSets; + OperatorSubsetLib.LinglongSubsets internal _linglongSubsets; /// @notice maps operator address => operator id and status mapping(address => OperatorInfo) internal _operatorInfo; diff --git a/src/symbiotic-network/SymbioticNetworkMiddleware.sol b/src/symbiotic-network/SymbioticNetworkMiddleware.sol index 4db897a..1f00963 100644 --- a/src/symbiotic-network/SymbioticNetworkMiddleware.sol +++ b/src/symbiotic-network/SymbioticNetworkMiddleware.sol @@ -44,6 +44,8 @@ import { SlashingLib } from "../libs/SlashingLib.sol"; import { SymbioticNetworkMiddlewareLib } from "../libs/SymbioticNetworkMiddlewareLib.sol"; import { SymbioticNetworkStorage } from "../storage/SymbioticNetworkStorage.sol"; import { DelegationStore } from "../types/CommonTypes.sol"; + +import { SafeCast } from "@openzeppelin-contracts/contracts/utils/math/SafeCast.sol"; import { EnumerableSetLib } from "@solady/utils/EnumerableSetLib.sol"; import "forge-std/console.sol"; @@ -62,7 +64,6 @@ contract SymbioticNetworkMiddleware is using EnumerableSetLib for EnumerableSetLib.AddressSet; using Subnetwork for address; using Subnetwork for bytes32; - using OperatorSubsetLib for uint96; using SafeCast96To32Lib for uint96[]; using SlashingLib for DelegationStore; @@ -72,8 +73,8 @@ contract SymbioticNetworkMiddleware is modifier onlyValidatorSubnetwork() { if ( - !REGISTRY_COORDINATOR.isSymbioticOperatorInSubnetwork( - VALIDATOR_SUBNETWORK, msg.sender + !REGISTRY_COORDINATOR.isOperatorInLinglongSubset( + OperatorSubsetLib.SYMBIOTIC_VALIDATOR_SUBSET_ID, msg.sender ) ) { revert @@ -119,20 +120,22 @@ contract SymbioticNetworkMiddleware is // ============================================================================================== /// @notice Creates a new subnetwork with the given ID - /// @param minStake The minimum stake required for the subnetwork - /// @param baseSubnetworkId The ID of the base subnetwork to create + /// @param linglongSubsetId The ID of the base subnetwork to create function createNewSubnetwork( - uint96 baseSubnetworkId, + uint32 linglongSubsetId, uint256 minStake ) external checkAccess { - uint96 encodedSubnetworkId = baseSubnetworkId.encodeOperatorSetId96( - ITaiyiRegistryCoordinator.RestakingProtocol.SYMBIOTIC + require( + linglongSubsetId == OperatorSubsetLib.SYMBIOTIC_VALIDATOR_SUBSET_ID + || linglongSubsetId == OperatorSubsetLib.SYMBIOTIC_UNDERWRITER_SUBSET_ID, + "Invalid subnetwork" ); + uint96 encodedSubnetworkId = SafeCast.toUint96(linglongSubsetId); super._registerSubnetwork(encodedSubnetworkId); - REGISTRY_COORDINATOR.createSubnetwork(encodedSubnetworkId, minStake); + REGISTRY_COORDINATOR.createLinglongSubset(linglongSubsetId, minStake); SUBNETWORK_COUNT = SUBNETWORK_COUNT + 1; } diff --git a/src/taiyi/TaiyiInteractiveChallenger.sol b/src/taiyi/TaiyiInteractiveChallenger.sol index 5a44f98..1e1c18f 100644 --- a/src/taiyi/TaiyiInteractiveChallenger.sol +++ b/src/taiyi/TaiyiInteractiveChallenger.sol @@ -515,7 +515,7 @@ contract TaiyiInteractiveChallenger is /// @inheritdoc ILinglongChallenger function isSlashingInProgress( address operator, - uint96 operatorSetId + uint32 linglongSubsetId ) external view diff --git a/test/DeployTest.t.sol b/test/DeployTest.t.sol index d541832..70d1765 100644 --- a/test/DeployTest.t.sol +++ b/test/DeployTest.t.sol @@ -34,7 +34,7 @@ contract DeployTest is Test { vm.deal(deployer, 1000 ether); vm.deal(implOwner, 1000 ether); - deploy.run("deploy-test-config.json"); + deploy.run("deploy-test-config.json", 0.1 ether); setRegistry.run(); setupContract.run(); } diff --git a/test/EigenLayerMiddleware.t.sol b/test/EigenLayerMiddleware.t.sol index e58bc1b..22ec551 100644 --- a/test/EigenLayerMiddleware.t.sol +++ b/test/EigenLayerMiddleware.t.sol @@ -460,10 +460,10 @@ contract EigenlayerMiddlewareTest is Test, G2Operations { middleware.updateAVSMetadataURI("https://taiyi.wtf"); validatorOperatorSetId = middleware.createOperatorSet( - strategies, OperatorSubsetLib.VALIDATOR_SUBSET_TYPE, 0 + strategies, OperatorSubsetLib.EIGENLAYER_VALIDATOR_SUBSET_ID, 0 ); underwriterOperatorSetId = middleware.createOperatorSet( - strategies, OperatorSubsetLib.UNDERWRITER_SUBSET_TYPE, 0 + strategies, OperatorSubsetLib.EIGENLAYER_UNDERWRITER_SUBSET_ID, 0 ); vm.stopPrank(); @@ -590,11 +590,9 @@ contract EigenlayerMiddlewareTest is Test, G2Operations { assertTrue(operatorFound, "Operator should be found in operator set members"); // Check the operator is in the operator set from the registry coordinator - (, uint32 baseOperatorSetId) = opSet.id.decodeOperatorSetId32(); + uint32 baseOperatorSetId = opSet.id; assertTrue( - registryCoordinator.getEigenLayerOperatorFromOperatorSet( - baseOperatorSetId, operator - ), + registryCoordinator.isOperatorInLinglongSubset(baseOperatorSetId, operator), "Operator should be in the operator set" ); assertEq(baseOperatorSetId, uint32(0), "Operator set ID should match"); @@ -638,28 +636,17 @@ contract EigenlayerMiddlewareTest is Test, G2Operations { ); // 2. Verify they are members of the operatorSet - (, uint32 opSetId) = underwriterOperatorSetId.decodeOperatorSetId32(); - address[] memory opSetMembers = - registryCoordinator.getEigenLayerOperatorSetOperators(opSetId); - - bool primaryOpFound = false; - bool underwriterOpFound = false; - - for (uint256 i = 0; i < opSetMembers.length; i++) { - if (opSetMembers[i] == primaryOp) { - primaryOpFound = true; - } - if (opSetMembers[i] == underwriterOp) { - underwriterOpFound = true; - } - } assertFalse( - primaryOpFound, + registryCoordinator.isOperatorInLinglongSubset( + underwriterOperatorSetId, primaryOp + ), "Primary operator should not be a member of the underwriter operator set" ); assertTrue( - underwriterOpFound, + registryCoordinator.isOperatorInLinglongSubset( + underwriterOperatorSetId, underwriterOp + ), "Underwriter operator should be a member of the underwriter operator set" ); } diff --git a/test/OperatorSubsetLib.t.sol b/test/OperatorSubsetLib.t.sol index a8589a3..da52bc7 100644 --- a/test/OperatorSubsetLib.t.sol +++ b/test/OperatorSubsetLib.t.sol @@ -10,556 +10,268 @@ import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableS import { Test } from "forge-std/Test.sol"; contract OperatorSubsetLibTest is Test { - using OperatorSubsetLib for OperatorSubsetLib.OperatorSets; + using OperatorSubsetLib for OperatorSubsetLib.LinglongSubsets; using EnumerableSet for EnumerableSet.AddressSet; using EnumerableSet for EnumerableSet.UintSet; - using SafeCast for uint96; - OperatorSubsetLib.OperatorSets internal operatorSets; + OperatorSubsetLib.LinglongSubsets internal linglongSubsets; - uint96 internal constant TEST_BASE_ID_1 = 12_345; - uint96 internal constant TEST_BASE_ID_2 = 67_890; - uint96 internal constant MAX_BASE_ID = (uint96(1) << 91) - 1; - uint96 internal constant TOO_LARGE_BASE_ID = (uint96(1) << 91); - - // Constants for uint32 tests - uint32 internal constant TEST_BASE_ID_32_1 = 12_345; - uint32 internal constant TEST_BASE_ID_32_2 = 67_890; - uint32 internal constant MAX_BASE_ID_32 = (uint32(1) << 27) - 1; - uint32 internal constant TOO_LARGE_BASE_ID_32 = (uint32(1) << 27); - - ITaiyiRegistryCoordinator.RestakingProtocol internal constant PROTOCOL_1 = - ITaiyiRegistryCoordinator.RestakingProtocol.EIGENLAYER; - ITaiyiRegistryCoordinator.RestakingProtocol internal constant PROTOCOL_2 = - ITaiyiRegistryCoordinator.RestakingProtocol.SYMBIOTIC; + // Constants for subset IDs + uint32 internal constant EIGENLAYER_VALIDATOR_SUBSET_ID = 0; + uint32 internal constant EIGENLAYER_UNDERWRITER_SUBSET_ID = 1; + uint32 internal constant SYMBIOTIC_VALIDATOR_SUBSET_ID = 2; + uint32 internal constant SYMBIOTIC_UNDERWRITER_SUBSET_ID = 3; address internal constant OPERATOR_1 = address(0x1001); address internal constant OPERATOR_2 = address(0x1002); address internal constant OPERATOR_3 = address(0x1003); function setUp() public { - // Create a new instance of OperatorSets for each test - delete operatorSets; + // Create a new instance of LinglongSubsets for each test + delete linglongSubsets; } - // --- Encoding & Decoding Tests --- - - function testEncodeDecode96() public pure { - uint96 encodedId96_1 = - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1); - uint96 encodedId96_2 = - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_2, PROTOCOL_2); - uint96 encodedId96Max = - OperatorSubsetLib.encodeOperatorSetId96(MAX_BASE_ID, PROTOCOL_1); - - ( - ITaiyiRegistryCoordinator.RestakingProtocol decodedProtocol, - uint96 decodedBaseId - ) = OperatorSubsetLib.decodeOperatorSetId96(encodedId96_1); - assertEq(uint8(decodedProtocol), uint8(PROTOCOL_1), "Decoded protocol 1 mismatch"); - assertEq(decodedBaseId, TEST_BASE_ID_1, "Decoded baseId 1 mismatch"); - - (decodedProtocol, decodedBaseId) = - OperatorSubsetLib.decodeOperatorSetId96(encodedId96_2); - assertEq(uint8(decodedProtocol), uint8(PROTOCOL_2), "Decoded protocol 2 mismatch"); - assertEq(decodedBaseId, TEST_BASE_ID_2, "Decoded baseId 2 mismatch"); - - (decodedProtocol, decodedBaseId) = - OperatorSubsetLib.decodeOperatorSetId96(encodedId96Max); - assertEq( - uint8(decodedProtocol), uint8(PROTOCOL_1), "Decoded protocol max mismatch" - ); - assertEq(decodedBaseId, MAX_BASE_ID, "Decoded baseId max mismatch"); - } - - function testEncodeDecode32() public pure { - uint32 encodedId32_1 = - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1); - uint32 encodedId32_2 = - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_2, PROTOCOL_2); - uint32 encodedId32Max = - OperatorSubsetLib.encodeOperatorSetId32(MAX_BASE_ID_32, PROTOCOL_1); - - ( - ITaiyiRegistryCoordinator.RestakingProtocol decodedProtocol, - uint32 decodedBaseId - ) = OperatorSubsetLib.decodeOperatorSetId32(encodedId32_1); - assertEq( - uint8(decodedProtocol), uint8(PROTOCOL_1), "Decoded protocol 1 mismatch (32)" - ); - assertEq(decodedBaseId, TEST_BASE_ID_32_1, "Decoded baseId 1 mismatch (32)"); - - (decodedProtocol, decodedBaseId) = - OperatorSubsetLib.decodeOperatorSetId32(encodedId32_2); - assertEq( - uint8(decodedProtocol), uint8(PROTOCOL_2), "Decoded protocol 2 mismatch (32)" - ); - assertEq(decodedBaseId, TEST_BASE_ID_32_2, "Decoded baseId 2 mismatch (32)"); + // --- Protocol ID Tests --- - (decodedProtocol, decodedBaseId) = - OperatorSubsetLib.decodeOperatorSetId32(encodedId32Max); - assertEq( - uint8(decodedProtocol), - uint8(PROTOCOL_1), - "Decoded protocol max mismatch (32)" - ); - assertEq(decodedBaseId, MAX_BASE_ID_32, "Decoded baseId max mismatch (32)"); - } - - function testGetters96() public pure { - uint96 encodedId96_1 = - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1); - uint96 encodedId96_2 = - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_2, PROTOCOL_2); - - assertEq( - uint8(OperatorSubsetLib.getProtocolType96(encodedId96_1)), - uint8(PROTOCOL_1), - "getProtocolType 1 mismatch" + function testIsEigenlayerProtocolID() public pure { + assertTrue( + OperatorSubsetLib.isEigenlayerProtocolID(EIGENLAYER_VALIDATOR_SUBSET_ID) ); - assertEq( - OperatorSubsetLib.getBaseId96(encodedId96_1), - TEST_BASE_ID_1, - "getBaseId 1 mismatch" + assertTrue( + OperatorSubsetLib.isEigenlayerProtocolID(EIGENLAYER_UNDERWRITER_SUBSET_ID) ); - - assertEq( - uint8(OperatorSubsetLib.getProtocolType96(encodedId96_2)), - uint8(PROTOCOL_2), - "getProtocolType 2 mismatch" + assertFalse( + OperatorSubsetLib.isEigenlayerProtocolID(SYMBIOTIC_VALIDATOR_SUBSET_ID) ); - assertEq( - OperatorSubsetLib.getBaseId96(encodedId96_2), - TEST_BASE_ID_2, - "getBaseId 2 mismatch" + assertFalse( + OperatorSubsetLib.isEigenlayerProtocolID(SYMBIOTIC_UNDERWRITER_SUBSET_ID) ); } - function testGetters32() public pure { - uint32 encodedId32_1 = - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1); - uint32 encodedId32_2 = - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_2, PROTOCOL_2); - - assertEq( - uint8(OperatorSubsetLib.getProtocolType32(encodedId32_1)), - uint8(PROTOCOL_1), - "getProtocolType 1 mismatch (32)" - ); - assertEq( - OperatorSubsetLib.getBaseId32(encodedId32_1), - TEST_BASE_ID_32_1, - "getBaseId 1 mismatch (32)" + function testIsSymbioticProtocolID() public pure { + assertFalse( + OperatorSubsetLib.isSymbioticProtocolID(EIGENLAYER_VALIDATOR_SUBSET_ID) ); - - assertEq( - uint8(OperatorSubsetLib.getProtocolType32(encodedId32_2)), - uint8(PROTOCOL_2), - "getProtocolType 2 mismatch (32)" + assertFalse( + OperatorSubsetLib.isSymbioticProtocolID(EIGENLAYER_UNDERWRITER_SUBSET_ID) ); - assertEq( - OperatorSubsetLib.getBaseId32(encodedId32_2), - TEST_BASE_ID_32_2, - "getBaseId 2 mismatch (32)" + assertTrue(OperatorSubsetLib.isSymbioticProtocolID(SYMBIOTIC_VALIDATOR_SUBSET_ID)); + assertTrue( + OperatorSubsetLib.isSymbioticProtocolID(SYMBIOTIC_UNDERWRITER_SUBSET_ID) ); } // --- Set Management Tests --- - function testCreateSet() public { - uint96 encodedId96_1 = - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1); - uint96 encodedId96_2 = - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_2, PROTOCOL_2); - uint32 encodedId32_1 = - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1); - uint32 encodedId32_2 = - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_2, PROTOCOL_2); - - assertTrue( - operatorSets.createOperatorSet96(encodedId96_1, 0), "Create set 96_1 failed" - ); - assertTrue( - operatorSets.createOperatorSet96(encodedId96_2, 0), "Create set 96_2 failed" - ); + function testCreateLinglongSubset() public { + uint256 minStake = 1000; assertTrue( - operatorSets.createOperatorSet32(encodedId32_1, 0), "Create set 32_1 failed" + linglongSubsets.createLinglongSubset(EIGENLAYER_VALIDATOR_SUBSET_ID, minStake) ); - assertTrue( - operatorSets.createOperatorSet32(encodedId32_2, 0), "Create set 32_2 failed" - ); - } - - function testGetOperatorSetsEmpty() public view { - uint96[] memory sets96 = operatorSets.getOperatorSets96(); - assertEq(sets96.length, 0, "Should return empty array when no 96-bit sets"); + assertEq(linglongSubsets.getMinStake(EIGENLAYER_VALIDATOR_SUBSET_ID), minStake); - uint32[] memory sets32 = operatorSets.getOperatorSets32(); - assertEq(sets32.length, 0, "Should return empty array when no 32-bit sets"); - } - - function testGetOperatorSets() public { - // Create sets with consistent protocol types - uint96 encodedId96_1 = - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1); - uint96 encodedId96_2 = - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_2, PROTOCOL_1); - uint32 encodedId32_1 = - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1); - uint32 encodedId32_2 = - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_2, PROTOCOL_1); - - operatorSets.createOperatorSet96(encodedId96_1, 0); - operatorSets.createOperatorSet96(encodedId96_2, 0); - operatorSets.createOperatorSet32(encodedId32_1, 0); - operatorSets.createOperatorSet32(encodedId32_2, 0); - - uint96[] memory sets96 = operatorSets.getOperatorSets96(); - assertEq(sets96.length, 2, "Incorrect number of 96-bit sets returned"); - bool found96_1 = false; - bool found96_2 = false; - for (uint256 i = 0; i < sets96.length; i++) { - if (sets96[i] == encodedId96_1) found96_1 = true; - if (sets96[i] == encodedId96_2) found96_2 = true; - } - assertTrue(found96_1, "Encoded ID 96_1 not found in getOperatorSets96 result"); - assertTrue(found96_2, "Encoded ID 96_2 not found in getOperatorSets96 result"); - - uint32[] memory sets32 = operatorSets.getOperatorSets32(); - assertEq(sets32.length, 2, "Incorrect number of 32-bit sets returned"); - bool found32_1 = false; - bool found32_2 = false; - for (uint256 i = 0; i < sets32.length; i++) { - if (sets32[i] == encodedId32_1) found32_1 = true; - if (sets32[i] == encodedId32_2) found32_2 = true; - } - assertTrue(found32_1, "Encoded ID 32_1 not found in getOperatorSets32 result"); - assertTrue(found32_2, "Encoded ID 32_2 not found in getOperatorSets32 result"); + // Test creating duplicate subset + assertFalse( + linglongSubsets.createLinglongSubset(EIGENLAYER_VALIDATOR_SUBSET_ID, minStake) + ); } // --- Operator Management Tests --- + /// forge-config: default.allow_internal_expect_revert = true + function testAddOperatorToLinglongSubset() public { + // Create subset first + linglongSubsets.createLinglongSubset(EIGENLAYER_VALIDATOR_SUBSET_ID, 0); - function testAddOperatorToSet() public { - // Test 96-bit set - operatorSets.createOperatorSet96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1), 0 - ); - assertTrue( - operatorSets.addOperatorToSet96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1), - OPERATOR_1 - ), - "Add operator 1 to 96-bit set failed" - ); - assertTrue( - operatorSets.isOperatorInSet96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1), - OPERATOR_1 - ), - "Operator 1 not in 96-bit set after add" - ); - assertEq( - operatorSets.getOperatorSetLength96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1) - ), - 1, - "96-bit set length mismatch after add 1" - ); - - // Test 32-bit set - operatorSets.createOperatorSet32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1), 0 - ); + // Test adding operator assertTrue( - operatorSets.addOperatorToSet32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1), - OPERATOR_1 - ), - "Add operator 1 to 32-bit set failed" + linglongSubsets.addOperatorToLinglongSubset( + EIGENLAYER_VALIDATOR_SUBSET_ID, OPERATOR_1 + ) ); assertTrue( - operatorSets.isOperatorInSet32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1), - OPERATOR_1 - ), - "Operator 1 not in 32-bit set after add" + linglongSubsets.isOperatorInLinglongSubset( + EIGENLAYER_VALIDATOR_SUBSET_ID, OPERATOR_1 + ) ); assertEq( - operatorSets.getOperatorSetLength32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1) - ), - 1, - "32-bit set length mismatch after add 1" + linglongSubsets.getLinglongSubsetLength(EIGENLAYER_VALIDATOR_SUBSET_ID), 1 ); - // Test duplicate additions + // Test adding duplicate operator assertFalse( - operatorSets.addOperatorToSet96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1), - OPERATOR_1 - ), - "Add existing operator to 96-bit set should return false" - ); - assertFalse( - operatorSets.addOperatorToSet32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1), - OPERATOR_1 - ), - "Add existing operator to 32-bit set should return false" + linglongSubsets.addOperatorToLinglongSubset( + EIGENLAYER_VALIDATOR_SUBSET_ID, OPERATOR_1 + ) ); - // Add second operator to both sets - assertTrue( - operatorSets.addOperatorToSet96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1), - OPERATOR_2 - ), - "Add operator 2 to 96-bit set failed" - ); - assertTrue( - operatorSets.addOperatorToSet32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1), - OPERATOR_2 - ), - "Add operator 2 to 32-bit set failed" + // Test adding to non-existent subset + // First ensure the subset doesn't exist + assertFalse( + linglongSubsets.isLinglongSubsetIdCreated(SYMBIOTIC_VALIDATOR_SUBSET_ID) ); - // Verify operators in both sets - address[] memory operators96 = operatorSets.getOperatorsInSet96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1) + vm.expectRevert( + OperatorSubsetLib.OperatorSetLib__OperatorSetDoesNotExist.selector ); - address[] memory operators32 = operatorSets.getOperatorsInSet32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1) + linglongSubsets.addOperatorToLinglongSubset( + SYMBIOTIC_VALIDATOR_SUBSET_ID, OPERATOR_1 ); - assertEq(operators96.length, 2, "Incorrect number of operators in 96-bit set"); - assertEq(operators32.length, 2, "Incorrect number of operators in 32-bit set"); } - function testRemoveOperatorFromSet() public { - // Setup for 96-bit set - operatorSets.createOperatorSet96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1), 0 - ); - operatorSets.addOperatorToSet96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1), - OPERATOR_1 + /// forge-config: default.allow_internal_expect_revert = true + function testRemoveOperatorFromLinglongSubset() public { + // Setup + linglongSubsets.createLinglongSubset(EIGENLAYER_VALIDATOR_SUBSET_ID, 0); + linglongSubsets.addOperatorToLinglongSubset( + EIGENLAYER_VALIDATOR_SUBSET_ID, OPERATOR_1 ); - operatorSets.addOperatorToSet96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1), - OPERATOR_2 + linglongSubsets.addOperatorToLinglongSubset( + EIGENLAYER_VALIDATOR_SUBSET_ID, OPERATOR_2 ); - // Setup for 32-bit set - operatorSets.createOperatorSet32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1), 0 + // Test removing operator + assertTrue( + linglongSubsets.removeOperatorFromLinglongSubset( + EIGENLAYER_VALIDATOR_SUBSET_ID, OPERATOR_1 + ) ); - operatorSets.addOperatorToSet32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1), - OPERATOR_1 + assertFalse( + linglongSubsets.isOperatorInLinglongSubset( + EIGENLAYER_VALIDATOR_SUBSET_ID, OPERATOR_1 + ) ); - operatorSets.addOperatorToSet32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1), - OPERATOR_2 + assertTrue( + linglongSubsets.isOperatorInLinglongSubset( + EIGENLAYER_VALIDATOR_SUBSET_ID, OPERATOR_2 + ) ); // Test removing non-existent operator assertFalse( - operatorSets.removeOperatorFromSet96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1), - OPERATOR_3 - ), - "Remove non-existent operator from 96-bit set should return false" - ); - assertFalse( - operatorSets.removeOperatorFromSet32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1), - OPERATOR_3 - ), - "Remove non-existent operator from 32-bit set should return false" + linglongSubsets.removeOperatorFromLinglongSubset( + EIGENLAYER_VALIDATOR_SUBSET_ID, OPERATOR_3 + ) ); - // Test removing operators - assertTrue( - operatorSets.removeOperatorFromSet96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1), - OPERATOR_1 - ), - "Remove operator 1 from 96-bit set failed" + // Test removing from non-existent subset + vm.expectRevert( + OperatorSubsetLib.OperatorSetLib__OperatorSetDoesNotExist.selector ); - assertTrue( - operatorSets.removeOperatorFromSet32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1), - OPERATOR_1 - ), - "Remove operator 1 from 32-bit set failed" + linglongSubsets.removeOperatorFromLinglongSubset( + SYMBIOTIC_VALIDATOR_SUBSET_ID, OPERATOR_1 ); + } - // Verify removals - assertFalse( - operatorSets.isOperatorInSet96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1), - OPERATOR_1 - ), - "Operator 1 still in 96-bit set after remove" - ); - assertFalse( - operatorSets.isOperatorInSet32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1), - OPERATOR_1 - ), - "Operator 1 still in 32-bit set after remove" - ); + function testAddOperatorToLinglongSubsets() public { + // Setup + uint32[] memory subsetIds = new uint32[](2); + subsetIds[0] = EIGENLAYER_VALIDATOR_SUBSET_ID; + subsetIds[1] = EIGENLAYER_UNDERWRITER_SUBSET_ID; - // Verify remaining operators - assertTrue( - operatorSets.isOperatorInSet96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1), - OPERATOR_2 - ), - "Operator 2 affected by remove in 96-bit set" - ); - assertTrue( - operatorSets.isOperatorInSet32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1), - OPERATOR_2 - ), - "Operator 2 affected by remove in 32-bit set" - ); + linglongSubsets.createLinglongSubset(subsetIds[0], 0); + linglongSubsets.createLinglongSubset(subsetIds[1], 0); - // Remove remaining operators - assertTrue( - operatorSets.removeOperatorFromSet96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1), - OPERATOR_2 - ), - "Remove operator 2 from 96-bit set failed" + // Test adding operator to multiple subsets + linglongSubsets.addOperatorToLinglongSubsets(subsetIds, OPERATOR_1); + + assertTrue(linglongSubsets.isOperatorInLinglongSubset(subsetIds[0], OPERATOR_1)); + assertTrue(linglongSubsets.isOperatorInLinglongSubset(subsetIds[1], OPERATOR_1)); + } + + function testRemoveOperatorFromLinglongSubsets() public { + // Setup + uint32[] memory subsetIds = new uint32[](2); + subsetIds[0] = EIGENLAYER_VALIDATOR_SUBSET_ID; + subsetIds[1] = EIGENLAYER_UNDERWRITER_SUBSET_ID; + + linglongSubsets.createLinglongSubset(subsetIds[0], 0); + linglongSubsets.createLinglongSubset(subsetIds[1], 0); + linglongSubsets.addOperatorToLinglongSubset(subsetIds[0], OPERATOR_1); + linglongSubsets.addOperatorToLinglongSubset(subsetIds[1], OPERATOR_1); + + // Test removing operator from multiple subsets + linglongSubsets.removeOperatorFromLinglongSubsets(subsetIds, OPERATOR_1); + + assertFalse(linglongSubsets.isOperatorInLinglongSubset(subsetIds[0], OPERATOR_1)); + assertFalse(linglongSubsets.isOperatorInLinglongSubset(subsetIds[1], OPERATOR_1)); + } + + /// forge-config: default.allow_internal_expect_revert = true + function testGetOperatorsInLinglongSubset() public { + // Setup + linglongSubsets.createLinglongSubset(EIGENLAYER_VALIDATOR_SUBSET_ID, 0); + linglongSubsets.addOperatorToLinglongSubset( + EIGENLAYER_VALIDATOR_SUBSET_ID, OPERATOR_1 ); - assertTrue( - operatorSets.removeOperatorFromSet32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1), - OPERATOR_2 - ), - "Remove operator 2 from 32-bit set failed" + linglongSubsets.addOperatorToLinglongSubset( + EIGENLAYER_VALIDATOR_SUBSET_ID, OPERATOR_2 ); - // Verify empty sets - assertEq( - operatorSets.getOperatorSetLength96( - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1) - ), - 0, - "96-bit set length should be 0 after removing all operators" - ); - assertEq( - operatorSets.getOperatorSetLength32( - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1) - ), - 0, - "32-bit set length should be 0 after removing all operators" + // Test getting operators + address[] memory operators = + linglongSubsets.getOperatorsInLinglongSubset(EIGENLAYER_VALIDATOR_SUBSET_ID); + assertEq(operators.length, 2); + assertTrue(operators[0] == OPERATOR_1 || operators[1] == OPERATOR_1); + assertTrue(operators[0] == OPERATOR_2 || operators[1] == OPERATOR_2); + + // Test getting from non-existent subset + vm.expectRevert( + OperatorSubsetLib.OperatorSetLib__OperatorSetDoesNotExist.selector ); + linglongSubsets.getOperatorsInLinglongSubset(SYMBIOTIC_VALIDATOR_SUBSET_ID); } - function testAddOperatorToSets() public { - // Setup for 96-bit sets - uint96[] memory encodedIds96 = new uint96[](2); - encodedIds96[0] = - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1); - encodedIds96[1] = - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_2, PROTOCOL_1); - - // Create the sets first using encoded IDs - operatorSets.createOperatorSet96(encodedIds96[0], 0); - operatorSets.createOperatorSet96(encodedIds96[1], 0); - - // Setup for 32-bit sets - uint32[] memory encodedIds32 = new uint32[](2); - encodedIds32[0] = - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1); - encodedIds32[1] = - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_2, PROTOCOL_1); - - // Create the sets first using encoded IDs - operatorSets.createOperatorSet32(encodedIds32[0], 0); - operatorSets.createOperatorSet32(encodedIds32[1], 0); - - // Add operator to multiple sets using encoded IDs - operatorSets.addOperatorToSets96(encodedIds96, PROTOCOL_1, OPERATOR_1); - operatorSets.addOperatorToSets32(encodedIds32, PROTOCOL_1, OPERATOR_1); - - // Verify additions using encoded IDs - assertTrue( - operatorSets.isOperatorInSet96(encodedIds96[0], OPERATOR_1), - "Operator 1 not in 96-bit set 1 after multi-add" + function testGetLinglongSubsetsFromOperator() public { + // Setup + linglongSubsets.createLinglongSubset(EIGENLAYER_VALIDATOR_SUBSET_ID, 0); + linglongSubsets.createLinglongSubset(EIGENLAYER_UNDERWRITER_SUBSET_ID, 0); + linglongSubsets.addOperatorToLinglongSubset( + EIGENLAYER_VALIDATOR_SUBSET_ID, OPERATOR_1 ); - assertTrue( - operatorSets.isOperatorInSet96(encodedIds96[1], OPERATOR_1), - "Operator 1 not in 96-bit set 2 after multi-add" + linglongSubsets.addOperatorToLinglongSubset( + EIGENLAYER_UNDERWRITER_SUBSET_ID, OPERATOR_1 ); + + // Test getting subsets for operator + uint32[] memory subsets = + linglongSubsets.getLinglongSubsetsFromOperator(OPERATOR_1); + assertEq(subsets.length, 2); assertTrue( - operatorSets.isOperatorInSet32(encodedIds32[0], OPERATOR_1), - "Operator 1 not in 32-bit set 1 after multi-add" + subsets[0] == EIGENLAYER_VALIDATOR_SUBSET_ID + || subsets[1] == EIGENLAYER_VALIDATOR_SUBSET_ID ); assertTrue( - operatorSets.isOperatorInSet32(encodedIds32[1], OPERATOR_1), - "Operator 1 not in 32-bit set 2 after multi-add" + subsets[0] == EIGENLAYER_UNDERWRITER_SUBSET_ID + || subsets[1] == EIGENLAYER_UNDERWRITER_SUBSET_ID ); } - function testRemoveOperatorFromSets() public { - // Setup for 96-bit sets - uint96[] memory baseIds96 = new uint96[](2); - baseIds96[0] = TEST_BASE_ID_1; - baseIds96[1] = TEST_BASE_ID_2; - - uint96[] memory encodedIds96 = new uint96[](2); - encodedIds96[0] = - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_1, PROTOCOL_1); - encodedIds96[1] = - OperatorSubsetLib.encodeOperatorSetId96(TEST_BASE_ID_2, PROTOCOL_1); - - // Create and populate 96-bit sets using encoded IDs - operatorSets.createOperatorSet96(encodedIds96[0], 0); - operatorSets.createOperatorSet96(encodedIds96[1], 0); - operatorSets.addOperatorToSet96(encodedIds96[0], OPERATOR_1); - operatorSets.addOperatorToSet96(encodedIds96[1], OPERATOR_1); - - // Setup for 32-bit sets - uint32[] memory baseIds32 = new uint32[](2); - baseIds32[0] = TEST_BASE_ID_32_1; - baseIds32[1] = TEST_BASE_ID_32_2; - - uint32[] memory encodedIds32 = new uint32[](2); - encodedIds32[0] = - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_1, PROTOCOL_1); - encodedIds32[1] = - OperatorSubsetLib.encodeOperatorSetId32(TEST_BASE_ID_32_2, PROTOCOL_1); - - // Create and populate 32-bit sets using encoded IDs - operatorSets.createOperatorSet32(encodedIds32[0], 0); - operatorSets.createOperatorSet32(encodedIds32[1], 0); - operatorSets.addOperatorToSet32(encodedIds32[0], OPERATOR_1); - operatorSets.addOperatorToSet32(encodedIds32[1], OPERATOR_1); - - // Remove operator from multiple sets using base IDs - operatorSets.removeOperatorFromSets96(baseIds96, PROTOCOL_1, OPERATOR_1); - operatorSets.removeOperatorFromSets32(baseIds32, PROTOCOL_1, OPERATOR_1); - - // Verify removals using encoded IDs - assertFalse( - operatorSets.isOperatorInSet96(encodedIds96[0], OPERATOR_1), - "Operator 1 still in 96-bit set 1 after multi-remove" + /// forge-config: default.allow_internal_expect_revert = true + function testGetLinglongSubsetLength() public { + // Setup + linglongSubsets.createLinglongSubset(EIGENLAYER_VALIDATOR_SUBSET_ID, 0); + linglongSubsets.addOperatorToLinglongSubset( + EIGENLAYER_VALIDATOR_SUBSET_ID, OPERATOR_1 ); - assertFalse( - operatorSets.isOperatorInSet96(encodedIds96[1], OPERATOR_1), - "Operator 1 still in 96-bit set 2 after multi-remove" + linglongSubsets.addOperatorToLinglongSubset( + EIGENLAYER_VALIDATOR_SUBSET_ID, OPERATOR_2 ); - assertFalse( - operatorSets.isOperatorInSet32(encodedIds32[0], OPERATOR_1), - "Operator 1 still in 32-bit set 1 after multi-remove" + + // Test getting length + assertEq( + linglongSubsets.getLinglongSubsetLength(EIGENLAYER_VALIDATOR_SUBSET_ID), 2 ); - assertFalse( - operatorSets.isOperatorInSet32(encodedIds32[1], OPERATOR_1), - "Operator 1 still in 32-bit set 2 after multi-remove" + + // Test getting length of non-existent subset + vm.expectRevert( + OperatorSubsetLib.OperatorSetLib__OperatorSetDoesNotExist.selector ); + linglongSubsets.getLinglongSubsetLength(SYMBIOTIC_VALIDATOR_SUBSET_ID); + } + + function testGetMinStake() public { + uint256 minStake = 1000; + linglongSubsets.createLinglongSubset(EIGENLAYER_VALIDATOR_SUBSET_ID, minStake); + assertEq(linglongSubsets.getMinStake(EIGENLAYER_VALIDATOR_SUBSET_ID), minStake); } } diff --git a/test/SymbioticMiddleware.t.sol b/test/SymbioticMiddleware.t.sol index 38fa258..a57b49c 100644 --- a/test/SymbioticMiddleware.t.sol +++ b/test/SymbioticMiddleware.t.sol @@ -136,13 +136,13 @@ contract SymbioticMiddlewareTest is POCBaseTest { _optInToVault(operator, address(vault4)); // Register operator with middleware - bytes memory key = abi.encode(operator); - bytes memory signature = _generateKeySignature(key, operatorSecretKey); + bytes memory operatorEncoded = abi.encode(operator); + bytes memory signature = _generateKeySignature(operatorEncoded, operatorSecretKey); uint96[] memory subnetworks = _createSubnetworksArray(validatorSubnetworkId, underwriterSubnetworkId); vm.startPrank(operator); - middleware.registerOperator(key, signature, subnetworks); + middleware.registerOperator(operatorEncoded, signature, subnetworks); vm.stopPrank(); // Verify that the mocked getOperatorAllocatedSubnetworks returns what we expect @@ -300,8 +300,9 @@ contract SymbioticMiddlewareTest is POCBaseTest { bytes memory evidence = abi.encode("Mock evidence"); // Check which protocol the operator is registered with - bool isSymbioticOperator = - registry.isSymbioticOperatorInSubnetwork(validatorSubnetworkId, operator); + bool isSymbioticOperator = registry.isOperatorInLinglongSubset( + OperatorSubsetLib.SYMBIOTIC_VALIDATOR_SUBSET_ID, operator + ); console.log("Is Symbiotic Operator:", isSymbioticOperator); // Perform the slashing based on the operator's restaking protocol @@ -541,11 +542,13 @@ contract SymbioticMiddlewareTest is POCBaseTest { } function _setupSubnetworks() internal impersonate(owner) { - middleware.createNewSubnetwork(VALIDATOR_SUBNETWORK, 0); - middleware.createNewSubnetwork(UNDERWRITER_SUBNETWORK, 0); + middleware.createNewSubnetwork(OperatorSubsetLib.SYMBIOTIC_VALIDATOR_SUBSET_ID, 0); + middleware.createNewSubnetwork( + OperatorSubsetLib.SYMBIOTIC_UNDERWRITER_SUBSET_ID, 0 + ); - validatorSubnetworkId = VALIDATOR_SUBNETWORK; - underwriterSubnetworkId = UNDERWRITER_SUBNETWORK; + validatorSubnetworkId = OperatorSubsetLib.SYMBIOTIC_VALIDATOR_SUBSET_ID; + underwriterSubnetworkId = OperatorSubsetLib.SYMBIOTIC_UNDERWRITER_SUBSET_ID; } // Helper functions for working with uint32/uint96 arrays diff --git a/test/utils/MockChallenger.sol b/test/utils/MockChallenger.sol index 20ab6a2..2eb20d6 100644 --- a/test/utils/MockChallenger.sol +++ b/test/utils/MockChallenger.sol @@ -72,7 +72,7 @@ contract MockLinglongChallenger is ILinglongChallenger { function isSlashingInProgress( address, - uint96 + uint32 ) external view From 88d00827ca75dd1836ce5d93271b4fa225823f77 Mon Sep 17 00:00:00 2001 From: WillQ Date: Tue, 13 May 2025 11:25:32 +0800 Subject: [PATCH 3/4] address comments --- script/Deployments.s.sol | 4 +++- src/operator-registries/TaiyiRegistryCoordinator.sol | 11 +++++++++++ src/storage/TaiyiRegistryCoordinatorStorage.sol | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/script/Deployments.s.sol b/script/Deployments.s.sol index c0ab390..72deae2 100644 --- a/script/Deployments.s.sol +++ b/script/Deployments.s.sol @@ -54,6 +54,8 @@ import { StdStorage, stdStorage } from "forge-std/Test.sol"; import { IEigenLayerMiddleware } from "src/interfaces/IEigenLayerMiddleware.sol"; +import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol"; + contract Deploy is Script, Test { using stdStorage for StdStorage; @@ -367,7 +369,7 @@ contract Deploy is Script, Test { deployEigenLayer(configFileName); vm.startBroadcast(); IRegistry.Config memory registryConfig = IRegistry.Config({ - minCollateralWei: uint80(urcMinCollateral), + minCollateralWei: SafeCast.toUint80(urcMinCollateral), fraudProofWindow: 7200, unregistrationDelay: 7200, slashWindow: 7200, diff --git a/src/operator-registries/TaiyiRegistryCoordinator.sol b/src/operator-registries/TaiyiRegistryCoordinator.sol index 826b406..4eb6c81 100644 --- a/src/operator-registries/TaiyiRegistryCoordinator.sol +++ b/src/operator-registries/TaiyiRegistryCoordinator.sol @@ -722,6 +722,17 @@ contract TaiyiRegistryCoordinator is OperatorInfo storage operatorInfo = _operatorInfo[operator]; require(operatorInfo.status == OperatorStatus.REGISTERED, OperatorNotRegistered()); + require( + _linglongSubsetIds.length == 2, + "Eigenlayer deregistration requires exactly one subset" + ); + + require( + _linglongSubsetIds[0] == OperatorSubsetLib.EIGENLAYER_VALIDATOR_SUBSET_ID + && _linglongSubsetIds[1] == OperatorSubsetLib.EIGENLAYER_UNDERWRITER_SUBSET_ID, + "Invalid eigenlayer subset IDs" + ); + operatorInfo.status = OperatorStatus.DEREGISTERED; for (uint256 i = 0; i < _linglongSubsetIds.length; i++) { require( diff --git a/src/storage/TaiyiRegistryCoordinatorStorage.sol b/src/storage/TaiyiRegistryCoordinatorStorage.sol index e184c60..2baf590 100644 --- a/src/storage/TaiyiRegistryCoordinatorStorage.sol +++ b/src/storage/TaiyiRegistryCoordinatorStorage.sol @@ -29,7 +29,7 @@ import { EnumerableSet } from // |----------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------------------------| // | allocationManager | contract IAllocationManager | 3 | 0 | 20 | src/storage/TaiyiRegistryCoordinatorStorage.sol:TaiyiRegistryCoordinatorStorage | // |----------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------------------------| -// | _operatorSets | struct OperatorSubsetLib.OperatorSets | 4 | 0 | 32 | src/storage/TaiyiRegistryCoordinatorStorage.sol:TaiyiRegistryCoordinatorStorage | +// | _linglongSubsets | struct OperatorSubsetLib.LinglongSubsets | 4 | 0 | 32 | src/storage/TaiyiRegistryCoordinatorStorage.sol:TaiyiRegistryCoordinatorStorage | // |----------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------------------------| // | _operatorInfo | mapping(address => struct ITaiyiRegistryCoordinator.OperatorInfo) | 5 | 0 | 32 | src/storage/TaiyiRegistryCoordinatorStorage.sol:TaiyiRegistryCoordinatorStorage | // |----------------------+----------------------------------------------------------------------+------+--------+-------+---------------------------------------------------------------------------------| From f38fc81eb20f512743908723acc29e9733ecee22 Mon Sep 17 00:00:00 2001 From: WillQ Date: Tue, 13 May 2025 12:47:33 +0800 Subject: [PATCH 4/4] fix test --- .../TaiyiRegistryCoordinator.sol | 46 +++++++++++++------ 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/src/operator-registries/TaiyiRegistryCoordinator.sol b/src/operator-registries/TaiyiRegistryCoordinator.sol index 4eb6c81..72ddc53 100644 --- a/src/operator-registries/TaiyiRegistryCoordinator.sol +++ b/src/operator-registries/TaiyiRegistryCoordinator.sol @@ -713,6 +713,7 @@ contract TaiyiRegistryCoordinator is /// @notice Deregisters an operator from the EigenLayer protocol /// @param operator Address of the operator to deregister /// @param _linglongSubsetIds Array of subset IDs to deregister from + function _deregisterOperatorForEigenlayer( address operator, uint32[] memory _linglongSubsetIds @@ -722,18 +723,6 @@ contract TaiyiRegistryCoordinator is OperatorInfo storage operatorInfo = _operatorInfo[operator]; require(operatorInfo.status == OperatorStatus.REGISTERED, OperatorNotRegistered()); - require( - _linglongSubsetIds.length == 2, - "Eigenlayer deregistration requires exactly one subset" - ); - - require( - _linglongSubsetIds[0] == OperatorSubsetLib.EIGENLAYER_VALIDATOR_SUBSET_ID - && _linglongSubsetIds[1] == OperatorSubsetLib.EIGENLAYER_UNDERWRITER_SUBSET_ID, - "Invalid eigenlayer subset IDs" - ); - - operatorInfo.status = OperatorStatus.DEREGISTERED; for (uint256 i = 0; i < _linglongSubsetIds.length; i++) { require( OperatorSubsetLib.isEigenlayerProtocolID(_linglongSubsetIds[i]), @@ -742,6 +731,21 @@ contract TaiyiRegistryCoordinator is } _linglongSubsets.removeOperatorFromLinglongSubsets(_linglongSubsetIds, operator); + // Check if the operator is still in any Linglong subset + bool stillInAnySubset = false; + uint256[] memory allSubsetIds = _linglongSubsets.linglongSubsetIds.values(); + for (uint256 i = 0; i < allSubsetIds.length; i++) { + uint32 subsetId = uint32(allSubsetIds[i]); + if (_linglongSubsets.isOperatorInLinglongSubset(subsetId, operator)) { + stillInAnySubset = true; + break; + } + } + + // Only set status to DEREGISTERED if not in any subset + if (!stillInAnySubset) { + operatorInfo.status = OperatorStatus.DEREGISTERED; + } } /// @notice Registers an operator for the Symbiotic protocol @@ -775,13 +779,27 @@ contract TaiyiRegistryCoordinator is OperatorInfo storage operatorInfo = _operatorInfo[operator]; require(operatorInfo.status == OperatorStatus.REGISTERED, OperatorNotRegistered()); - operatorInfo.status = OperatorStatus.DEREGISTERED; - uint32[] memory linglongSubsetIds = new uint32[](2); linglongSubsetIds[0] = OperatorSubsetLib.SYMBIOTIC_VALIDATOR_SUBSET_ID; linglongSubsetIds[1] = OperatorSubsetLib.SYMBIOTIC_UNDERWRITER_SUBSET_ID; _linglongSubsets.removeOperatorFromLinglongSubsets(linglongSubsetIds, operator); + + // Check if the operator is still in any Linglong subset + bool stillInAnySubset = false; + uint256[] memory allSubsetIds = _linglongSubsets.linglongSubsetIds.values(); + for (uint256 i = 0; i < allSubsetIds.length; i++) { + uint32 subsetId = uint32(allSubsetIds[i]); + if (_linglongSubsets.isOperatorInLinglongSubset(subsetId, operator)) { + stillInAnySubset = true; + break; + } + } + + // Only set status to DEREGISTERED if not in any subset + if (!stillInAnySubset) { + operatorInfo.status = OperatorStatus.DEREGISTERED; + } } /// @notice Checks the initial EigenLayer stake for an operator