diff --git a/README.md b/README.md index 38519cc..2569a01 100644 --- a/README.md +++ b/README.md @@ -260,6 +260,34 @@ docker run --rm --network host -v ./.nodes:/root/.nodes \ | `REGISTRY_ADDRESS` | if not mounted | From `.nodes/avs_deploy.json` | Volume | AVS registrar address | | `FUNDED_KEY` | if not mounted | From `.nodes/deployer` | Volume | Deployer private key | +### Transfer Ownership + +Transfers ownership of the service contracts to new owners. + +```bash +PROXY_OWNER=$(cast wallet new --json | jq -r '.[0].private_key') +PROXY_OWNER_ADDRESS=$(cast wallet addr --private-key "$PROXY_OWNER") +echo "Proxy owner address: $PROXY_OWNER_ADDRESS" +AVS_OWNER=$(cast wallet new --json | jq -r '.[0].private_key') +AVS_OWNER_ADDRESS=$(cast wallet addr --private-key "$AVS_OWNER") +echo "Avs owner address: $AVS_OWNER_ADDRESS" + +# WAVS_SERVICE_MANAGER_ADDRESS=$(jq -r '.addresses.WavsServiceManager' .nodes/avs_deploy.json) + +docker run --rm --network host -v ./.nodes:/root/.nodes \ + --env-file .env \ + wavs-middleware transfer_ownership ${PROXY_OWNER} ${AVS_OWNER} +``` + +| Environment Variable | Required | Default | Source | Description | +| ------------------------------ | --------------------- | ----------------------------- | ------ | ---------------------------------------------- | +| `DEPLOY_ENV` | for non-default value | `LOCAL` | `.env` | Deployment environment (`LOCAL` or `TESTNET`) | +| `RPC_URL` | for non-default value | `http://localhost:8545` | `.env` | RPC URL | +| `WAVS_SERVICE_MANAGER_ADDRESS` | if not mounted | From `.nodes/avs_deploy.json` | volume | Service manager contract address | +| `FUNDED_KEY` | if not mounted | From `.nodes/deployer` | Volume | Deployer private key | +| `PROXY_OWNER` | Yes | - | Params | New owner for proxy admin | +| `AVS_OWNER` | Yes | - | Params | New owner for AVS registrar and stake registry | + ### Delegate to Operator Delegates tokens to an operator. @@ -433,6 +461,32 @@ docker run --rm --network host -v ./.nodes:/root/.nodes \ | `DEPLOY_FILE_MOCK` | for non-default value | `mock` | Command line | File name to store mock deployment | | `CONFIGURE_FILE` | for non-default value | `wavs-mock-config` | Command line | File name to read configuration data | +### 5. Mock Transfer Ownership + +Transfers ownership of the mock service contracts to new owners. + +```bash +PROXY_OWNER=$(cast wallet new --json | jq -r '.[0].private_key') +PROXY_OWNER_ADDRESS=$(cast wallet addr --private-key "$PROXY_OWNER") +echo "Proxy owner address: $PROXY_OWNER_ADDRESS" +AVS_OWNER=$(cast wallet new --json | jq -r '.[0].private_key') +AVS_OWNER_ADDRESS=$(cast wallet addr --private-key "$AVS_OWNER") +echo "Avs owner address: $AVS_OWNER_ADDRESS" + +docker run --rm --network host -v ./.nodes:/root/.nodes \ + --env-file .env \ + wavs-middleware -m mock transfer_ownership ${PROXY_OWNER} ${AVS_OWNER} +``` + +| Environment Variable | Required | Default | Source | Description | +| ------------------------------ | --------------------- | --------------------------- | ------------ | ---------------------------------------------- | +| `DEPLOY_ENV` | for non-default value | `LOCAL` | `.env` | Deployment environment (`LOCAL` or `TESTNET`) | +| `MOCK_RPC_URL` | for non-default value | `http://localhost:8546` | Command line | RPC URL for mock blockchain | +| `MOCK_DEPLOYER_KEY` | if not mounted | From `.nodes/mock-deployer` | Volume | Deployer private key | +| `WAVS_SERVICE_MANAGER_ADDRESS` | if not mounted | From `.nodes/mock.json` | Volume | Service manager contract address | +| `PROXY_OWNER` | Yes | - | Params | New owner for proxy admin | +| `AVS_OWNER` | Yes | - | Params | New owner for AVS registrar and stake registry | + ## Deploy Testnet Same as the local deploy, change `DEPLOY_ENV` to `"TESTNET"` and make sure the `FUNDED_KEY` is actually funded on testnet diff --git a/contracts/script/eigenlayer/bls/WavsListOperators.s.sol b/contracts/script/eigenlayer/bls/WavsListOperators.s.sol index 19cbf3d..3b3adec 100644 --- a/contracts/script/eigenlayer/bls/WavsListOperators.s.sol +++ b/contracts/script/eigenlayer/bls/WavsListOperators.s.sol @@ -2,13 +2,8 @@ pragma solidity ^0.8.27; import {Script} from "forge-std/Script.sol"; -import {console} from "forge-std/console.sol"; -import {IStakeRegistry} from "@eigenlayer-middleware/src/interfaces/IStakeRegistry.sol"; -import {IAllocationManager} from "@eigenlayer/contracts/interfaces/IAllocationManager.sol"; -import {OperatorSet} from "@eigenlayer/contracts/libraries/OperatorSetLib.sol"; -import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; -import {WavsServiceManager} from "src/eigenlayer/bls/WavsServiceManager.sol"; +import {WavsListOperatorsLib} from "script/eigenlayer/bls/utils/WavsListOperatorsLib.sol"; /** * @title WavsListOperators @@ -17,182 +12,21 @@ import {WavsServiceManager} from "src/eigenlayer/bls/WavsServiceManager.sol"; * @dev This script is used to list the operators for the WAVS service manager. */ contract WavsListOperators is Script { - /** - * @notice The operator info struct. - * @param stakeRegistry The stake registry address. - * @param totalWeight The total weight of the operators. - * @param minimumStake The minimum stake of the operators. - * @param operators The operators. - * @param weights The weights of the operators. - * @param strategies The strategies of the operators. - */ - struct OperatorInfo { - address stakeRegistry; - uint96 totalWeight; - uint96 minimumStake; - address[] operators; - uint96[] weights; - IStakeRegistry.StrategyParams[] strategies; - } - /// @notice The environment variable for the WAVS service manager address. string public constant ENV_SERVICE_MANAGER = "WAVS_SERVICE_MANAGER_ADDRESS"; - WavsServiceManager private serviceManager; - uint256 private _quorumNumerator; - uint256 private _quorumDenominator; + address private _serviceManager; /// @notice The setup function for the script. function setUp() public virtual { - serviceManager = WavsServiceManager(vm.envAddress(ENV_SERVICE_MANAGER)); + _serviceManager = vm.envAddress(ENV_SERVICE_MANAGER); } /// @notice The run function for the script. function run() external { - vm.startBroadcast(); - OperatorInfo memory opInfo = _listOperators(serviceManager.getStakeRegistry()); - _quorumNumerator = serviceManager.quorumNumerator(); - _quorumDenominator = serviceManager.quorumDenominator(); - _writeOperatorListJson(opInfo); - vm.stopBroadcast(); - - console.log("=== List Operators ==="); - console.log("Service Manager Address:", address(serviceManager)); - console.log("Stake Registry Address:", serviceManager.getStakeRegistry()); - console.log("Strategies:"); - for (uint256 i = 0; i < opInfo.strategies.length; ++i) { - console.log( - string.concat( - "Strategy ", - Strings.toString(i), - ": ", - Strings.toHexString(uint160(address(opInfo.strategies[i].strategy)), 20), - " (", - Strings.toString(opInfo.strategies[i].multiplier), - ")" - ) - ); - } - - console.log(" "); // Blank line for separation - console.log("=== Quorum Information ==="); - console.log(string.concat("Total Weight: ", Strings.toString(uint256(opInfo.totalWeight)))); - console.log( - string.concat("Minimum Stake: ", Strings.toString(uint256(opInfo.minimumStake))) - ); - - console.log(" "); // Blank line for separation - console.log("=== Registered Operators ==="); - for (uint256 i = 0; i < opInfo.operators.length; ++i) { - string memory op = string.concat( - "Operator ", - Strings.toString(i + 1), - ": ", - Strings.toHexString(uint160(opInfo.operators[i]), 20) - ); - string memory weight = string.concat("= ", Strings.toString(uint256(opInfo.weights[i]))); - console.log(op, weight); - } - - console.log(" "); // Blank line for separation - console.log("=== Service Manager Quorum Information ==="); - console.log(string.concat("Quorum Numerator: ", Strings.toString(_quorumNumerator))); - console.log(string.concat("Quorum Denominator: ", Strings.toString(_quorumDenominator))); - } - - /** - * @notice The list operators function. - * @param _stakeRegistry The stake registry address. - * @return opInfo The operator info. - */ - function _listOperators( - address _stakeRegistry - ) private view returns (OperatorInfo memory) { - IStakeRegistry stakeRegistry = IStakeRegistry(_stakeRegistry); - - uint96 totalWeight = stakeRegistry.getCurrentTotalStake(0); - - IAllocationManager allocationManager = - IAllocationManager(serviceManager.getAllocationManager()); - OperatorSet memory opSetQuery = OperatorSet({avs: address(serviceManager), id: 0}); - address[] memory operators = allocationManager.getMembers(opSetQuery); - - uint96[] memory weights = new uint96[](operators.length); - for (uint256 i = 0; i < operators.length; ++i) { - weights[i] = stakeRegistry.weightOfOperatorForQuorum(0, operators[i]); - } - - uint256 strategyParamsLength = stakeRegistry.strategyParamsLength(0); - IStakeRegistry.StrategyParams[] memory strategies = - new IStakeRegistry.StrategyParams[](strategyParamsLength); - for (uint256 i = 0; i < strategyParamsLength; ++i) { - strategies[i] = stakeRegistry.strategyParamsByIndex(uint8(0), i); - } - - return OperatorInfo({ - stakeRegistry: address(stakeRegistry), - totalWeight: totalWeight, - minimumStake: stakeRegistry.minimumStakeForQuorum(0), - operators: operators, - weights: weights, - strategies: strategies - }); - } - - /** - * @notice The write operator list JSON function. - * @param opInfo The operator info. - */ - function _writeOperatorListJson( - OperatorInfo memory opInfo - ) internal { - if (!vm.exists("deployments/wavs-bls")) { - vm.createDir("deployments/wavs-bls", true); - } - - string memory json = "{\"serviceManager\":\""; - json = string.concat(json, Strings.toHexString(uint160(address(serviceManager)), 20)); - json = string.concat(json, "\",\"stakeRegistry\":\""); - json = string.concat(json, Strings.toHexString(uint160(opInfo.stakeRegistry), 20)); - json = string.concat(json, "\",\"totalWeight\":\""); - json = string.concat(json, Strings.toString(opInfo.totalWeight)); - json = string.concat(json, "\",\"minimumStake\":\""); - json = string.concat(json, Strings.toString(opInfo.minimumStake)); - json = string.concat(json, "\",\"strategies\":["); - - for (uint256 i = 0; i < opInfo.strategies.length; ++i) { - if (i > 0) { - json = string.concat(json, ","); - } - json = string.concat(json, "{\"strategy\":\""); - json = string.concat( - json, Strings.toHexString(uint160(address(opInfo.strategies[i].strategy)), 20) - ); - json = string.concat(json, "\",\"multiplier\":\""); - json = string.concat(json, Strings.toString(opInfo.strategies[i].multiplier)); - json = string.concat(json, "\"}"); - } - - json = string.concat(json, "],\"operators\":["); - - for (uint256 i = 0; i < opInfo.operators.length; ++i) { - if (i > 0) { - json = string.concat(json, ","); - } - json = string.concat(json, "{\"operator\":\""); - json = string.concat(json, Strings.toHexString(uint160(opInfo.operators[i]), 20)); - json = string.concat(json, "\",\"weight\":\""); - json = string.concat(json, Strings.toString(opInfo.weights[i])); - json = string.concat(json, "\"}"); - } - - json = string.concat(json, "],\"quorumNumerator\":\""); - json = string.concat(json, Strings.toString(_quorumNumerator)); - json = string.concat(json, "\",\"quorumDenominator\":\""); - json = string.concat(json, Strings.toString(_quorumDenominator)); - json = string.concat(json, "\""); - json = string.concat(json, "}"); - - vm.writeFile("deployments/wavs-bls/list_operators.json", json); + address[] memory operators = WavsListOperatorsLib.getOperators(_serviceManager, uint8(0)); + WavsListOperatorsLib.ConfigData memory configData = + WavsListOperatorsLib.getConfigData(_serviceManager, uint8(0), operators); + WavsListOperatorsLib.writeOperatorListJson(configData); } } diff --git a/contracts/script/eigenlayer/bls/WavsMiddlewareDeployer.s.sol b/contracts/script/eigenlayer/bls/WavsMiddlewareDeployer.s.sol index 306af39..5ee09b4 100644 --- a/contracts/script/eigenlayer/bls/WavsMiddlewareDeployer.s.sol +++ b/contracts/script/eigenlayer/bls/WavsMiddlewareDeployer.s.sol @@ -3,13 +3,14 @@ pragma solidity ^0.8.27; import {Script} from "forge-std/Script.sol"; -import {RegistryCoordinator} from "@eigenlayer-middleware/src/RegistryCoordinator.sol"; import {StakeRegistry} from "@eigenlayer-middleware/src/StakeRegistry.sol"; import {BLSApkRegistry} from "@eigenlayer-middleware/src/BLSApkRegistry.sol"; import {IndexRegistry} from "@eigenlayer-middleware/src/IndexRegistry.sol"; import {SocketRegistry} from "@eigenlayer-middleware/src/SocketRegistry.sol"; import {PauserRegistry} from "@eigenlayer/contracts/permissions/PauserRegistry.sol"; import {IStakeRegistryTypes} from "@eigenlayer-middleware/src/interfaces/IStakeRegistry.sol"; +import {SlashingRegistryCoordinator} from + "@eigenlayer-middleware/src/SlashingRegistryCoordinator.sol"; import {WavsMiddlewareDeploymentLib} from "./utils/WavsMiddlewareDeploymentLib.sol"; import {WavsServiceManager} from "src/eigenlayer/bls/WavsServiceManager.sol"; @@ -100,8 +101,8 @@ contract WavsMiddlewareDeployer is Script { WavsServiceManager wavsServiceManager = WavsServiceManager(wavsMiddlewareDeployment.wavsServiceManager); StakeRegistry stakeRegistry = StakeRegistry(wavsMiddlewareDeployment.stakeRegistry); - RegistryCoordinator registryCoordinator = - RegistryCoordinator(wavsMiddlewareDeployment.registryCoordinator); + SlashingRegistryCoordinator registryCoordinator = + SlashingRegistryCoordinator(wavsMiddlewareDeployment.registryCoordinator); BLSApkRegistry blsApkRegistry = BLSApkRegistry(wavsMiddlewareDeployment.blsApkRegistry); IndexRegistry indexRegistry = IndexRegistry(wavsMiddlewareDeployment.indexRegistry); SocketRegistry socketRegistry = SocketRegistry(wavsMiddlewareDeployment.socketRegistry); @@ -120,10 +121,7 @@ contract WavsMiddlewareDeployer is Script { revert WavsMiddlewareDeployer__StakeRegistryMismatch(); } if ( - address(registryCoordinator.serviceManager()) - != wavsMiddlewareDeployment.wavsServiceManager - || address(registryCoordinator.stakeRegistry()) - != wavsMiddlewareDeployment.stakeRegistry + address(registryCoordinator.stakeRegistry()) != wavsMiddlewareDeployment.stakeRegistry || address(registryCoordinator.blsApkRegistry()) != wavsMiddlewareDeployment.blsApkRegistry || address(registryCoordinator.indexRegistry()) diff --git a/contracts/script/eigenlayer/bls/utils/WavsListOperatorsLib.sol b/contracts/script/eigenlayer/bls/utils/WavsListOperatorsLib.sol new file mode 100644 index 0000000..685bb5e --- /dev/null +++ b/contracts/script/eigenlayer/bls/utils/WavsListOperatorsLib.sol @@ -0,0 +1,318 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.27; + +import {Vm} from "forge-std/Vm.sol"; +import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; +import {BN254} from "@eigenlayer-middleware/src/libraries/BN254.sol"; +import {ISlashingRegistryCoordinator} from + "@eigenlayer-middleware/src/interfaces/ISlashingRegistryCoordinator.sol"; +import { + IStakeRegistry, + IStakeRegistryTypes +} from "@eigenlayer-middleware/src/interfaces/IStakeRegistry.sol"; +import {IBLSApkRegistry} from "@eigenlayer-middleware/src/interfaces/IBLSApkRegistry.sol"; +import {ISocketRegistry} from "@eigenlayer-middleware/src/interfaces/ISocketRegistry.sol"; +import {IAllocationManager} from "@eigenlayer/contracts/interfaces/IAllocationManager.sol"; +import {OperatorSet} from "@eigenlayer/contracts/libraries/OperatorSetLib.sol"; +import {IStrategy} from "@eigenlayer/contracts/interfaces/IStrategy.sol"; +import {WavsServiceManager} from "src/eigenlayer/bls/WavsServiceManager.sol"; + +/** + * @title WavsListOperatorsLib + * @author Lay3rLabs + * @notice This library contains the functions for listing the operators for the WAVS service manager. + * @dev This library is used to list the operators for the WAVS service manager. + */ +library WavsListOperatorsLib { + /* solhint-disable gas-struct-packing */ + /** + * @notice The operator data struct. + * @param operator The operator address. + * @param operatorId The operator ID. + * @param pubkey The public key. + * @param pubkeyG2 The G2 public key. + * @param socket The socket information. + * @param stake The stake amount. + */ + struct OperatorData { + address operator; + bytes32 operatorId; + BN254.G1Point pubkey; + BN254.G2Point pubkeyG2; + string socket; + uint96 stake; + } + /* solhint-enable gas-struct-packing */ + + /** + * @notice The config data struct. + * @param totalWeight The total weight. + * @param minimumStake The minimum stake. + * @param strategies The strategy parameters. + * @param operators The operator data. + * @param quorumNumerator The quorum numerator. + * @param quorumDenominator The quorum denominator. + */ + struct ConfigData { + uint96 totalWeight; + uint96 minimumStake; + IStakeRegistry.StrategyParams[] strategies; + OperatorData[] operators; + uint256 quorumNumerator; + uint256 quorumDenominator; + } + + Vm internal constant VM = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + + /// @notice The error for the config file not found. + error WavsListOperatorsLib__ConfigFileNotFound(); + + /** + * @notice The get config data function. + * @param _serviceManager The service manager address. + * @param _quorumNumber The quorum number. + * @param _operators The operators. + * @return configData The config data. + */ + function getConfigData( + address _serviceManager, + uint8 _quorumNumber, + address[] memory _operators + ) internal view returns (ConfigData memory configData) { + WavsServiceManager serviceManager = WavsServiceManager(_serviceManager); + configData.quorumNumerator = serviceManager.quorumNumerator(); + configData.quorumDenominator = serviceManager.quorumDenominator(); + + ISlashingRegistryCoordinator slashingRegistryCoordinator = + ISlashingRegistryCoordinator(serviceManager.getRegistryCoordinator()); + IStakeRegistry stakeRegistry = slashingRegistryCoordinator.stakeRegistry(); + ISocketRegistry socketRegistry = slashingRegistryCoordinator.socketRegistry(); + IBLSApkRegistry blsApkRegistry = slashingRegistryCoordinator.blsApkRegistry(); + + configData.totalWeight = stakeRegistry.getCurrentTotalStake(_quorumNumber); + configData.minimumStake = stakeRegistry.minimumStakeForQuorum(_quorumNumber); + + uint256 operatorCount = _operators.length; + + OperatorData[] memory operatorData = new OperatorData[](operatorCount); + + for (uint256 i = 0; i < operatorCount; ++i) { + (BN254.G1Point memory pubkey, bytes32 operatorId) = + blsApkRegistry.getRegisteredPubkey(_operators[i]); + operatorData[i] = OperatorData({ + operator: _operators[i], + operatorId: operatorId, + pubkey: pubkey, + pubkeyG2: blsApkRegistry.getOperatorPubkeyG2(_operators[i]), + socket: socketRegistry.getOperatorSocket(operatorId), + stake: stakeRegistry.getCurrentStake(operatorId, _quorumNumber) + }); + } + + uint256 strategyParamsLength = stakeRegistry.strategyParamsLength(_quorumNumber); + IStakeRegistry.StrategyParams[] memory strategies = + new IStakeRegistry.StrategyParams[](strategyParamsLength); + for (uint256 i = 0; i < strategyParamsLength; ++i) { + strategies[i] = stakeRegistry.strategyParamsByIndex(_quorumNumber, i); + } + + configData.strategies = strategies; + configData.operators = operatorData; + + return configData; + } + + /** + * @notice The get operators function. + * @param _serviceManager The service manager address. + * @param _quorumNumber The quorum number. + * @return operators The operators. + */ + function getOperators( + address _serviceManager, + uint8 _quorumNumber + ) internal view returns (address[] memory) { + WavsServiceManager serviceManager = WavsServiceManager(_serviceManager); + + IAllocationManager allocationManager = + IAllocationManager(serviceManager.getAllocationManager()); + OperatorSet memory opSetQuery = + OperatorSet({avs: address(serviceManager), id: _quorumNumber}); + address[] memory operators = allocationManager.getMembers(opSetQuery); + + return operators; + } + + /** + * @notice The read config function. + * @param fileName The file name. + * @return configData The config data. + */ + function readConfig( + string memory fileName + ) internal returns (WavsListOperatorsLib.ConfigData memory) { + if (!VM.exists(fileName)) { + revert WavsListOperatorsLib__ConfigFileNotFound(); + } + + // load the complete config + string memory json = VM.readFile(fileName); + + // Parse basic config data + uint96 minimumStake = abi.decode(VM.parseJson(json, ".minimumStake"), (uint96)); + uint96 totalWeight = abi.decode(VM.parseJson(json, ".totalWeight"), (uint96)); + uint256 quorumNumerator = abi.decode(VM.parseJson(json, ".quorumNumerator"), (uint256)); + uint256 quorumDenominator = abi.decode(VM.parseJson(json, ".quorumDenominator"), (uint256)); + + // Parse the strategies array from the JSON + address[] memory strategies = + abi.decode(VM.parseJson(json, ".strategies[*].strategy"), (address[])); + uint256 strategyCount = strategies.length; + uint96[] memory multipliers = + abi.decode(VM.parseJson(json, ".strategies[*].multiplier"), (uint96[])); + + // Convert to strategy params + IStakeRegistryTypes.StrategyParams[] memory strategyParams = + new IStakeRegistryTypes.StrategyParams[](strategyCount); + for (uint256 i; i < strategyCount; ++i) { + strategyParams[i] = IStakeRegistryTypes.StrategyParams({ + strategy: IStrategy(strategies[i]), + multiplier: multipliers[i] + }); + } + + // Parse operators data + address[] memory operatorAddresses = + abi.decode(VM.parseJson(json, ".operators[*].operator"), (address[])); + bytes32[] memory operatorIds = + abi.decode(VM.parseJson(json, ".operators[*].operatorId"), (bytes32[])); + uint256[] memory pubkeyXs = + abi.decode(VM.parseJson(json, ".operators[*].pubkey.x"), (uint256[])); + uint256[] memory pubkeyYs = + abi.decode(VM.parseJson(json, ".operators[*].pubkey.y"), (uint256[])); + string[] memory sockets = abi.decode(VM.parseJson(json, ".operators[*].socket"), (string[])); + uint96[] memory stakes = abi.decode(VM.parseJson(json, ".operators[*].stake"), (uint96[])); + + // Parse G2 public keys (arrays of 2 uint256s) + uint256[2][] memory pubkeyG2Xs = + abi.decode(VM.parseJson(json, ".operators[*].pubkeyG2.x"), (uint256[2][])); + uint256[2][] memory pubkeyG2Ys = + abi.decode(VM.parseJson(json, ".operators[*].pubkeyG2.y"), (uint256[2][])); + + uint256 operatorCount = operatorAddresses.length; + + // Convert to operator data + OperatorData[] memory operators = new OperatorData[](operatorCount); + for (uint256 i; i < operatorCount; ++i) { + operators[i] = OperatorData({ + operator: operatorAddresses[i], + operatorId: operatorIds[i], + pubkey: BN254.G1Point({X: pubkeyXs[i], Y: pubkeyYs[i]}), + pubkeyG2: BN254.G2Point({X: pubkeyG2Xs[i], Y: pubkeyG2Ys[i]}), + socket: sockets[i], + stake: stakes[i] + }); + } + + return ConfigData({ + totalWeight: totalWeight, + minimumStake: minimumStake, + strategies: strategyParams, + operators: operators, + quorumNumerator: quorumNumerator, + quorumDenominator: quorumDenominator + }); + } + + /** + * @notice The write operator list JSON function. + * @param configData The config data. + */ + function writeOperatorListJson( + ConfigData memory configData + ) internal { + if (!VM.exists("deployments/wavs-bls")) { + VM.createDir("deployments/wavs-bls", true); + } + + string memory json = "{\"totalWeight\":\""; + json = string.concat(json, Strings.toString(configData.totalWeight)); + json = string.concat(json, "\",\"minimumStake\":\""); + json = string.concat(json, Strings.toString(configData.minimumStake)); + json = string.concat(json, "\",\"strategies\":["); + + for (uint256 i = 0; i < configData.strategies.length; ++i) { + if (i > 0) { + json = string.concat(json, ","); + } + json = string.concat(json, "{\"strategy\":\""); + json = string.concat( + json, Strings.toHexString(uint160(address(configData.strategies[i].strategy)), 20) + ); + json = string.concat(json, "\",\"multiplier\":\""); + json = string.concat(json, Strings.toString(configData.strategies[i].multiplier)); + json = string.concat(json, "\"}"); + } + + json = string.concat(json, "],\"operators\":["); + + for (uint256 i = 0; i < configData.operators.length; ++i) { + if (i > 0) { + json = string.concat(json, ","); + } + json = string.concat(json, "{\"operator\":\""); + json = string.concat( + json, Strings.toHexString(uint160(configData.operators[i].operator), 20) + ); + json = string.concat(json, "\",\"operatorId\":\""); + json = string.concat( + json, Strings.toHexString(uint256(configData.operators[i].operatorId), 32) + ); + json = string.concat(json, "\",\"pubkey\":{"); + json = string.concat(json, "\"x\":\""); + json = string.concat( + json, Strings.toHexString(uint256(configData.operators[i].pubkey.X), 32) + ); + json = string.concat(json, "\",\"y\":\""); + json = string.concat( + json, Strings.toHexString(uint256(configData.operators[i].pubkey.Y), 32) + ); + json = string.concat(json, "\"},"); + json = string.concat(json, "\"pubkeyG2\":{"); + json = string.concat(json, "\"x\":[\""); + json = string.concat( + json, Strings.toHexString(uint256(configData.operators[i].pubkeyG2.X[0]), 32) + ); + json = string.concat( + json, + "\",\"", + Strings.toHexString(uint256(configData.operators[i].pubkeyG2.X[1]), 32) + ); + json = string.concat(json, "\"],"); + json = string.concat(json, "\"y\":[\""); + json = string.concat( + json, Strings.toHexString(uint256(configData.operators[i].pubkeyG2.Y[0]), 32) + ); + json = string.concat( + json, + "\",\"", + Strings.toHexString(uint256(configData.operators[i].pubkeyG2.Y[1]), 32) + ); + json = string.concat(json, "\"]},"); + json = string.concat(json, "\"socket\":\""); + json = string.concat(json, configData.operators[i].socket); + json = string.concat(json, "\",\"stake\":\""); + json = string.concat(json, Strings.toString(configData.operators[i].stake)); + json = string.concat(json, "\"}"); + } + + json = string.concat(json, "],\"quorumNumerator\":\""); + json = string.concat(json, Strings.toString(configData.quorumNumerator)); + json = string.concat(json, "\",\"quorumDenominator\":\""); + json = string.concat(json, Strings.toString(configData.quorumDenominator)); + json = string.concat(json, "\""); + json = string.concat(json, "}"); + + VM.writeFile("deployments/wavs-bls/list_operators.json", json); + } +} diff --git a/contracts/script/eigenlayer/bls/utils/WavsMiddlewareDeploymentLib.sol b/contracts/script/eigenlayer/bls/utils/WavsMiddlewareDeploymentLib.sol index c9137b8..8e8e873 100644 --- a/contracts/script/eigenlayer/bls/utils/WavsMiddlewareDeploymentLib.sol +++ b/contracts/script/eigenlayer/bls/utils/WavsMiddlewareDeploymentLib.sol @@ -9,7 +9,6 @@ import {StakeRegistry} from "@eigenlayer-middleware/src/StakeRegistry.sol"; import {BLSApkRegistry} from "@eigenlayer-middleware/src/BLSApkRegistry.sol"; import {IndexRegistry} from "@eigenlayer-middleware/src/IndexRegistry.sol"; import {SocketRegistry} from "@eigenlayer-middleware/src/SocketRegistry.sol"; -import {RegistryCoordinator} from "@eigenlayer-middleware/src/RegistryCoordinator.sol"; import {SlashingRegistryCoordinator} from "@eigenlayer-middleware/src/SlashingRegistryCoordinator.sol"; import {InstantSlasher} from "@eigenlayer-middleware/src/slashers/InstantSlasher.sol"; @@ -22,9 +21,6 @@ import { import {IBLSApkRegistry} from "@eigenlayer-middleware/src/interfaces/IBLSApkRegistry.sol"; import {IIndexRegistry} from "@eigenlayer-middleware/src/interfaces/IIndexRegistry.sol"; import {ISocketRegistry} from "@eigenlayer-middleware/src/interfaces/ISocketRegistry.sol"; -import {IServiceManager} from "@eigenlayer-middleware/src/interfaces/IServiceManager.sol"; -import {IRegistryCoordinatorTypes} from - "@eigenlayer-middleware/src/interfaces/IRegistryCoordinator.sol"; import { ISlashingRegistryCoordinator, ISlashingRegistryCoordinatorTypes @@ -137,19 +133,15 @@ library WavsMiddlewareDeploymentLib { IAllocationManager(core.allocationManager) ) ); - address registryCoordinatorImpl = address( - new RegistryCoordinator( - IRegistryCoordinatorTypes.RegistryCoordinatorParams({ - serviceManager: IServiceManager(wavsServiceManager), - slashingParams: IRegistryCoordinatorTypes.SlashingRegistryParams({ - stakeRegistry: IStakeRegistry(stakeRegistry), - blsApkRegistry: IBLSApkRegistry(blsApkRegistry), - indexRegistry: IIndexRegistry(indexRegistry), - socketRegistry: ISocketRegistry(socketRegistry), - allocationManager: IAllocationManager(core.allocationManager), - pauserRegistry: IPauserRegistry(pauserRegistry) - }) - }) + address slashingRegistryCoordinatorImpl = address( + new SlashingRegistryCoordinator( + IStakeRegistry(stakeRegistry), + IBLSApkRegistry(blsApkRegistry), + IIndexRegistry(indexRegistry), + ISocketRegistry(socketRegistry), + IAllocationManager(core.allocationManager), + IPauserRegistry(pauserRegistry), + "1.0.0" ) ); @@ -175,7 +167,7 @@ library WavsMiddlewareDeploymentLib { UpgradeableProxyLib.upgrade(stakeRegistry, stakeRegistryImpl); UpgradeableProxyLib.upgradeAndCall( registryCoordinator, - registryCoordinatorImpl, + slashingRegistryCoordinatorImpl, abi.encodeCall( SlashingRegistryCoordinator.initialize, (msg.sender, msg.sender, msg.sender, 0, wavsServiceManager) diff --git a/contracts/script/eigenlayer/ecdsa/WavsListOperators.s.sol b/contracts/script/eigenlayer/ecdsa/WavsListOperators.s.sol index f7b366e..82599af 100644 --- a/contracts/script/eigenlayer/ecdsa/WavsListOperators.s.sol +++ b/contracts/script/eigenlayer/ecdsa/WavsListOperators.s.sol @@ -47,11 +47,10 @@ contract WavsListOperators is Script { /// @notice The run function for the script. function run() external { - vm.startBroadcast(); OperatorInfo memory opInfo = listOperators(); uint256 quorumNumerator = serviceManager.quorumNumerator(); uint256 quorumDenominator = serviceManager.quorumDenominator(); - vm.stopBroadcast(); + _writeOperatorListJson(opInfo); console.log("=== List Operators ==="); console.log("Service Manager Address:", address(serviceManager)); @@ -124,4 +123,42 @@ contract WavsListOperators is Script { weights: weights }); } + + /** + * @notice The write operator list JSON function. + * @param opInfo The operator info. + */ + function _writeOperatorListJson( + OperatorInfo memory opInfo + ) private { + if (!vm.exists("deployments/wavs-ecdsa")) { + vm.createDir("deployments/wavs-ecdsa", true); + } + + string memory json = string.concat("{"); + json = string.concat(json, "\"stakeRegistry\":\""); + json = string.concat(json, Strings.toHexString(uint160(address(opInfo.stakeRegistry)), 20)); + json = string.concat(json, "\",\"totalWeight\":\""); + json = string.concat(json, Strings.toString(opInfo.totalWeight)); + json = string.concat(json, "\",\"thresholdWeight\":\""); + json = string.concat(json, Strings.toString(opInfo.thresholdWeight)); + json = string.concat(json, "\",\"operators\":["); + for (uint256 i = 0; i < opInfo.operators.length; ++i) { + json = string.concat(json, "{\"operator\":\""); + json = string.concat(json, Strings.toHexString(uint160(opInfo.operators[i]), 20)); + json = string.concat(json, "\",\"signingKeyAddress\":\""); + json = + string.concat(json, Strings.toHexString(uint160(opInfo.signingKeyAddresses[i]), 20)); + json = string.concat(json, "\",\"weight\":\""); + json = string.concat(json, Strings.toString(opInfo.weights[i])); + json = string.concat(json, "\"}"); + if (i < opInfo.operators.length - 1) { + json = string.concat(json, ","); + } + } + json = string.concat(json, "]"); + json = string.concat(json, "}"); + + vm.writeFile("deployments/wavs-ecdsa/list_operators.json", json); + } } diff --git a/contracts/script/eigenlayer/ecdsa/WavsMirrorPrepareDeploy.s.sol b/contracts/script/eigenlayer/ecdsa/WavsMirrorPrepareDeploy.s.sol index 36ca0ba..b6ab573 100644 --- a/contracts/script/eigenlayer/ecdsa/WavsMirrorPrepareDeploy.s.sol +++ b/contracts/script/eigenlayer/ecdsa/WavsMirrorPrepareDeploy.s.sol @@ -32,15 +32,11 @@ contract WavsMirrorPrepareDeploy is Script, IECDSAStakeRegistryTypes { /// @notice The run function for the script. function run() external { - vm.startBroadcast(); - // Pass in the configuration as a file, load it WavsMirrorDeploymentLib.InitialConfiguration memory configuration = WavsMirrorDeploymentLib.loadConfigurationFromChain(serviceManagerAddress); // write the configuration to a file WavsMirrorDeploymentLib.writeConfiguration(configFile, configuration); - - vm.stopBroadcast(); } } diff --git a/docker/BLS_CLI.md b/docker/BLS_CLI.md index d264e8c..f8f7fc7 100644 --- a/docker/BLS_CLI.md +++ b/docker/BLS_CLI.md @@ -18,7 +18,7 @@ anvil --fork-url $FORK_RPC_URL --host 0.0.0.0 --port 8545 -```bash docci-output-contains="Quorum Numerator: 3" +```bash cd docker/ docker run --rm --network host -v ./.nodes:/root/.nodes \ diff --git a/docker/ECDSA_CLI.md b/docker/ECDSA_CLI.md index fbc8016..0835433 100644 --- a/docker/ECDSA_CLI.md +++ b/docker/ECDSA_CLI.md @@ -121,6 +121,17 @@ docker run --rm --network host -v ./.nodes:/root/.nodes \ docker run --rm --network host -v ./.nodes:/root/.nodes \ --env-file .env \ wavs-middleware unpause + +PROXY_OWNER=$(cast wallet new --json | jq -r '.[0].private_key') +PROXY_OWNER_ADDRESS=$(cast wallet addr --private-key "$PROXY_OWNER") +echo "Proxy owner address: $PROXY_OWNER_ADDRESS" +AVS_OWNER=$(cast wallet new --json | jq -r '.[0].private_key') +AVS_OWNER_ADDRESS=$(cast wallet addr --private-key "$AVS_OWNER") +echo "Avs owner address: $AVS_OWNER_ADDRESS" + +docker run --rm --network host -v ./.nodes:/root/.nodes \ + --env-file .env \ + wavs-middleware transfer_ownership ${PROXY_OWNER} ${AVS_OWNER} ``` ```bash @@ -128,7 +139,6 @@ MOCK_DEPLOYER_KEY=$(cast wallet new --json | jq -r '.[0].private_key') MOCK_DEPLOYER_ADDRESS=$(cast wallet addr --private-key "$MOCK_DEPLOYER_KEY") docker run --rm --network host -v ./.nodes:/root/.nodes \ - --env-file .env \ -e MOCK_DEPLOYER_KEY=${MOCK_DEPLOYER_KEY} \ wavs-middleware -m mock deploy @@ -137,4 +147,14 @@ docker run --rm --network host -v ./.nodes:/root/.nodes \ -v $LOCAL_CONFIG_PATH:/wavs/contracts/deployments/wavs-mock-config.json \ --env-file .env \ wavs-middleware -m mock configure + +PROXY_OWNER=$(cast wallet new --json | jq -r '.[0].private_key') +PROXY_OWNER_ADDRESS=$(cast wallet addr --private-key "$PROXY_OWNER") +echo "Proxy owner address: $PROXY_OWNER_ADDRESS" +AVS_OWNER=$(cast wallet new --json | jq -r '.[0].private_key') +AVS_OWNER_ADDRESS=$(cast wallet addr --private-key "$AVS_OWNER") +echo "Avs owner address: $AVS_OWNER_ADDRESS" + +docker run --rm --network host -v ./.nodes:/root/.nodes \ + wavs-middleware -m mock transfer_ownership ${PROXY_OWNER} ${AVS_OWNER} ``` diff --git a/justfile b/justfile index e817f2e..9c91bdc 100644 --- a/justfile +++ b/justfile @@ -5,4 +5,10 @@ help: # builds middleware docker-build TAG="local": - {{SUDO}} docker build . -t ghcr.io/lay3rlabs/wavs-middleware:{{TAG}} + {{SUDO}} docker build . -t ghcr.io/lay3rlabs/wavs-middleware:{{TAG}} + +docker-push TAG="local": + {{SUDO}} docker push ghcr.io/lay3rlabs/wavs-middleware:{{TAG}} + +dos2unix: + find ./scripts -type f -exec dos2unix {} + \ No newline at end of file diff --git a/scripts/bls/eigen/list_operators.sh b/scripts/bls/eigen/list_operators.sh index 8e96a60..874fe31 100755 --- a/scripts/bls/eigen/list_operators.sh +++ b/scripts/bls/eigen/list_operators.sh @@ -30,7 +30,7 @@ echo "Listing operators for service manager: $WAVS_SERVICE_MANAGER_ADDRESS" # List operators cd contracts || handle_error "Failed to change to contracts directory" -forge script script/eigenlayer/bls/WavsListOperators.s.sol -vvv --rpc-url "$RPC_URL" --broadcast --skip-simulation || handle_error "Failed to list operators" +forge script script/eigenlayer/bls/WavsListOperators.s.sol -vvv --rpc-url "$RPC_URL" --skip-simulation || handle_error "Failed to list operators" # Save operator list data -save_deployment_data "$HOME/.nodes/wavs-bls-list-operators.json" "$(cat "deployments/wavs-bls/list_operators.json")" +save_deployment_data "$HOME/.nodes/bls-list-operators.json" "$(cat "deployments/wavs-bls/list_operators.json")" diff --git a/scripts/ecdsa/eigen/list_operators.sh b/scripts/ecdsa/eigen/list_operators.sh index e6f1bf3..e06f5f1 100755 --- a/scripts/ecdsa/eigen/list_operators.sh +++ b/scripts/ecdsa/eigen/list_operators.sh @@ -30,4 +30,7 @@ echo "Listing operators for service manager: $WAVS_SERVICE_MANAGER_ADDRESS" # List operators cd contracts || handle_error "Failed to change to contracts directory" -forge script script/eigenlayer/ecdsa/WavsListOperators.s.sol -vvv --rpc-url "$RPC_URL" --broadcast --skip-simulation || handle_error "Failed to list operators" +forge script script/eigenlayer/ecdsa/WavsListOperators.s.sol -vvv --rpc-url "$RPC_URL" --skip-simulation || handle_error "Failed to list operators" + +# Save operator list data +save_deployment_data "$HOME/.nodes/ecdsa-list-operators.json" "$(cat "deployments/wavs-ecdsa/list_operators.json")" diff --git a/scripts/ecdsa/eigen/transfer_ownership.sh b/scripts/ecdsa/eigen/transfer_ownership.sh new file mode 100644 index 0000000..5b670b3 --- /dev/null +++ b/scripts/ecdsa/eigen/transfer_ownership.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# -x echos all lines for debug +# set -x + +set -o errexit -o nounset -o pipefail +command -v shellcheck >/dev/null && shellcheck "$0" + +SCRIPT_DIR="$(realpath "$(dirname "$0")")" +# shellcheck source=../../helper.sh +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/../../helper.sh" + +# shellcheck source=../foundry_profile.sh +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/../foundry_profile.sh" + +# Parse command line arguments in key=value format +parse_args "$@" + +# Check required parameters with defaults +check_param "DEPLOY_ENV" "${DEPLOY_ENV:-LOCAL}" +DEFAULT_SERVICE_MANAGER=$(jq -r '.addresses.WavsServiceManager' "$HOME/.nodes/avs_deploy.json" 2>/dev/null || true) +check_param "WAVS_SERVICE_MANAGER_ADDRESS" "${WAVS_SERVICE_MANAGER_ADDRESS:-$DEFAULT_SERVICE_MANAGER}" +check_param "PROXY_OWNER" "${PROXY_OWNER:-$1}" +check_param "AVS_OWNER" "${AVS_OWNER:-$2}" + +# Set up environment based on DEPLOY_ENV +setup_environment + +# Read the deployer private key +deployer_private_key=$(load_deployment_data "$HOME/.nodes/deployer") +check_param "FUNDED_KEY" "${FUNDED_KEY:-$deployer_private_key}" +deployer_address=$(cast wallet address "$FUNDED_KEY") +echo "Deployer address: $deployer_address" + +ensure_balance "$deployer_address" + +transfer_ecdsa_ownership "$WAVS_SERVICE_MANAGER_ADDRESS" "$PROXY_OWNER" "$AVS_OWNER" "$FUNDED_KEY" "eigen" diff --git a/scripts/ecdsa/mirror/deploy.sh b/scripts/ecdsa/mirror/deploy.sh index 4ab08c6..c4d7a17 100755 --- a/scripts/ecdsa/mirror/deploy.sh +++ b/scripts/ecdsa/mirror/deploy.sh @@ -47,7 +47,7 @@ echo "Reading source chain config:" # Prepare deployment cd contracts || handle_error "Failed to change to contracts directory" -forge script script/eigenlayer/ecdsa/WavsMirrorPrepareDeploy.s.sol --rpc-url "$SOURCE_RPC_URL" -vvv --broadcast --skip-simulation || handle_error "Failed to run WavsMirrorPrepareDeploy script" +forge script script/eigenlayer/ecdsa/WavsMirrorPrepareDeploy.s.sol --rpc-url "$SOURCE_RPC_URL" -vvv --skip-simulation || handle_error "Failed to run WavsMirrorPrepareDeploy script" echo "Got config:" cat "deployments/wavs-mirror-config.json" diff --git a/scripts/ecdsa/mirror/list_operators.sh b/scripts/ecdsa/mirror/list_operators.sh index 81b67b3..d087d6e 100755 --- a/scripts/ecdsa/mirror/list_operators.sh +++ b/scripts/ecdsa/mirror/list_operators.sh @@ -38,7 +38,7 @@ check_param "MIRROR_SERVICE_MANAGER_ADDRESS" "${MIRROR_SERVICE_MANAGER_ADDRESS:- # Change to contracts directory and run the script cd contracts || handle_error "Failed to change to contracts directory" -forge script script/eigenlayer/ecdsa/WavsMirrorListOperators.s.sol -vvv --broadcast --skip-simulation || handle_error "Failed to list operators" +forge script script/eigenlayer/ecdsa/WavsMirrorListOperators.s.sol -vvv --skip-simulation || handle_error "Failed to list operators" echo "Operator list:" cat "deployments/wavs-ecdsa/mirror_list_operators.json" | jq . diff --git a/scripts/ecdsa/mock/transfer_ownership.sh b/scripts/ecdsa/mock/transfer_ownership.sh new file mode 100644 index 0000000..6aa3c6d --- /dev/null +++ b/scripts/ecdsa/mock/transfer_ownership.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +# -x echos all lines for debug +# set -x + +set -o errexit -o nounset -o pipefail +command -v shellcheck >/dev/null && shellcheck "$0" + +SCRIPT_DIR="$(realpath "$(dirname "$0")")" +# shellcheck source=../../helper.sh +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/../../helper.sh" + +# shellcheck source=../foundry_profile.sh +# shellcheck disable=SC1091 +source "$SCRIPT_DIR/../foundry_profile.sh" + +# Parse command line arguments in key=value format +parse_args "$@" + +# Check required parameters with defaults +check_param "DEPLOY_ENV" "${DEPLOY_ENV:-LOCAL}" +DEFAULT_SERVICE_MANAGER=$(jq -r '.addresses.WavsServiceManager' "$HOME/.nodes/mock.json" 2>/dev/null || true) +check_param "WAVS_SERVICE_MANAGER_ADDRESS" "${WAVS_SERVICE_MANAGER_ADDRESS:-$DEFAULT_SERVICE_MANAGER}" +check_param "PROXY_OWNER" "${PROXY_OWNER:-$1}" +check_param "AVS_OWNER" "${AVS_OWNER:-$2}" + +# Set up environment based on DEPLOY_ENV +if [ "$DEPLOY_ENV" = "TESTNET" ]; then + check_param "RPC_URL" "${MOCK_RPC_URL:-}" +else + check_param "RPC_URL" "${MOCK_RPC_URL:-http://localhost:8546}" +fi + +# Read the deployer private key +deployer_private_key=$(load_deployment_data "$HOME/.nodes/mock-deployer") +check_param "MOCK_DEPLOYER_KEY" "${MOCK_DEPLOYER_KEY:-$deployer_private_key}" +mock_deployer_address=$(cast wallet address "$MOCK_DEPLOYER_KEY") +echo "Deployer address: $mock_deployer_address" + +ensure_balance "$mock_deployer_address" + +transfer_ecdsa_ownership "$WAVS_SERVICE_MANAGER_ADDRESS" "$PROXY_OWNER" "$AVS_OWNER" "$MOCK_DEPLOYER_KEY" "mock" diff --git a/scripts/helper.sh b/scripts/helper.sh index 5954da8..f9eb20a 100644 --- a/scripts/helper.sh +++ b/scripts/helper.sh @@ -144,3 +144,54 @@ load_deployment_data() { fi fi } + +transfer_ecdsa_ownership() { + # Arguments (all optional, will fallback to env/params if not provided) + # $1 - WAVS_SERVICE_MANAGER_ADDRESS + # $2 - PROXY_OWNER + # $3 - AVS_OWNER + # $4 - FUNDED_KEY + + local wsm_address="${1}" + local proxy_owner="${2}" + local avs_owner="${3}" + local funded_key="${4}" + local mode="${5}" + + local avs_registrar_address + if [ "$mode" == "eigen" ]; then + # Get the AllocationManager address from the WAVS Service Manager + local allocation_manager_address + allocation_manager_address=$(cast call "$wsm_address" "getAllocationManager()(address)" --rpc-url "$RPC_URL") + echo "Allocation manager address: $allocation_manager_address" + # Get the AVS Registrar address from the AllocationManager for the WAVS Service Manager + avs_registrar_address=$(cast call "$allocation_manager_address" "getAVSRegistrar(address)(address)" "$wsm_address" --rpc-url "$RPC_URL") + echo "AVS registrar address: $avs_registrar_address" + fi + # Get the StakeRegistry address from the WAVS Service Manager + local stake_registry_address + stake_registry_address=$(cast call "$wsm_address" "getStakeRegistry()(address)" --rpc-url "$RPC_URL") + echo "Stake registry address: $stake_registry_address" + + # Get the ProxyAdmin of the WAVS Service Manager + local proxy_admin_address + proxy_admin_address=$(cast storage "$wsm_address" "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103" --rpc-url "$RPC_URL" | tail -n1 | sed 's/^0x000000000000000000000000//') + proxy_admin_address="0x$proxy_admin_address" + echo "Proxy admin address: $proxy_admin_address" + + echo "Transferring proxy ownership to $proxy_owner" + cast send "$proxy_admin_address" "transferOwnership(address)" "$proxy_owner" --private-key "$funded_key" --rpc-url "$RPC_URL" + + if [ "$mode" == "eigen" ]; then + echo "Transferring avs registrar ownership to $avs_owner" + cast send "$avs_registrar_address" "transferOwnership(address)" "$avs_owner" --private-key "$funded_key" --rpc-url "$RPC_URL" + fi + + echo "Transferring stake registry ownership to $avs_owner" + cast send "$stake_registry_address" "transferOwnership(address)" "$avs_owner" --private-key "$funded_key" --rpc-url "$RPC_URL" + + echo "Transferring allocation manager ownership to $avs_owner" + cast send "$wsm_address" "transferOwnership(address)" "$avs_owner" --private-key "$funded_key" --rpc-url "$RPC_URL" + + echo "Ownership transferred successfully" +}