From 46c83ca552fc96f035aec5672ee1e862a9b2994d Mon Sep 17 00:00:00 2001 From: John Cairns Date: Mon, 12 Aug 2024 15:56:46 -0500 Subject: [PATCH] feat: improve deployment script --- .gitignore | 1 + README.md | 88 +++- .../M2_deploy_from_scratch.devnet.config.json | 44 ++ script/deploy/devnet/DeploymentDetails.sol | 152 +++++++ .../devnet/M2_Deploy_From_Scratch.s.sol | 400 +++++++++++------- .../M2_from_scratch_deployment_data.json | 48 +-- 6 files changed, 554 insertions(+), 179 deletions(-) create mode 100644 script/configs/devnet/M2_deploy_from_scratch.devnet.config.json create mode 100644 script/deploy/devnet/DeploymentDetails.sol diff --git a/.gitignore b/.gitignore index c8e5b6075..65859fc51 100644 --- a/.gitignore +++ b/.gitignore @@ -37,6 +37,7 @@ script/output/M1_deployment_data.json /docs/docgen/ script/misc +script/output test.sh diff --git a/README.md b/README.md index 431f58c8c..ae41bc7a5 100644 --- a/README.md +++ b/README.md @@ -102,7 +102,93 @@ surya mdreport surya_report.md ./src/contracts/**/*.sol make bindings ``` -## Deployments +## Deploy EigenLayer Contracts + +### Deploy to Anvil + +1\. Start `anvil` + +```bash +$ anvil --host 0.0.0.0 --accounts 1 --balance 100 +``` + +2\. Make a note of your RPC_URL + +```bash +$ RPC_URL=http://localhost:8545 +``` + +3\. Make a note of your account and private key + +```bash +$ PUBLIC_KEY=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 +$ PRIVATE_KEY=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 +``` + +4\. check your connection + +```bash +$ cast balance ${PUBLIC_KEY} --rpc-url ${RPC_URL} +``` + +5\. Deploy M2 Contracts + +```bash +$ forge script script/deploy/devnet/M2_Deploy_From_Scratch.s.sol --rpc-url ${RPC_URL} \ + --private-key ${PRIVATE_KEY} --broadcast \ + --sig "run(string)" -- M2_deploy_from_scratch.anvil.config.json +``` + +6\. Upgrade M2 Contracts + +```bash +$ forge script script/deploy/devnet/M2_Deploy_From_Scratch.s.sol --rpc-url ${RPC_URL} \ + --private-key ${PRIVATE_KEY} --broadcast \ + --sig "upgrade(string,string)" -- M2_deploy_from_scratch.anvil.config.json M2_deploy_from_scratch_deployment_data.json +``` + + +Contracts deployment information is saved in `script/output/devnet/M2_from_scratch_deployment_data.json` + +### Deploy to DevNet + +Devnet can be started locally or contact the protocol team for a public url + +1\. Make a note of the devnet `RPC_URL` + +```bash +$ RPC_URL=http://devnet...:8545 +``` + +2. Make a note of the deployer account and private key + +```bash +$ PUBLIC_KEY=0x4a3Ee341f8ceEdB790F511A18899fBC1fdEb35af +$ PRIVATE_KEY=... +``` + +4\. check your connection + +```bash +$ cast balance ${PUBLIC_KEY} --rpc-url ${RPC_URL} +``` + +5\. Deploy M2 Contracts + +```bash +$ forge script script/deploy/devnet/M2_Deploy_From_Scratch.s.sol --rpc-url ${RPC_URL} \ + --private-key ${PRIVATE_KEY} --broadcast \ + --sig "run(string)" -- M2_deploy_from_scratch.devnet.config.json +``` + +6\. Upgrade Contracts +```bash +$ forge script script/deploy/devnet/M2_Deploy_From_Scratch.s.sol --rpc-url ${RPC_URL} \ + --private-key ${PRIVATE_KEY} --broadcast \ + --sig "upgrade(string,string)" -- M2_deploy_from_scratch.devnet.config.json M2_deploy_from_scratch.devnet.config.json +``` + +Contracts deployment information is saved in `script/output/devnet/M2_from_scratch_deployment_data.json` ### Current Mainnet Deployment diff --git a/script/configs/devnet/M2_deploy_from_scratch.devnet.config.json b/script/configs/devnet/M2_deploy_from_scratch.devnet.config.json new file mode 100644 index 000000000..4b799845b --- /dev/null +++ b/script/configs/devnet/M2_deploy_from_scratch.devnet.config.json @@ -0,0 +1,44 @@ +{ + "maintainer": "protocol@eigenlabs.org", + "multisig_addresses": { + "operationsMultisig": "0x4a3Ee341f8ceEdB790F511A18899fBC1fdEb35af", + "pauserMultisig": "0x4a3Ee341f8ceEdB790F511A18899fBC1fdEb35af", + "executorMultisig": "0x4a3Ee341f8ceEdB790F511A18899fBC1fdEb35af" + }, + "strategies": [], + "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": { + "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 + }, + "ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa" +} \ No newline at end of file diff --git a/script/deploy/devnet/DeploymentDetails.sol b/script/deploy/devnet/DeploymentDetails.sol new file mode 100644 index 000000000..bc1cecf94 --- /dev/null +++ b/script/deploy/devnet/DeploymentDetails.sol @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.12; +// solhint-disable no-console + +import {stdJson} from "forge-std/StdJson.sol"; +import {console2} from "forge-std/console2.sol"; +import {VmSafe} from "forge-std/Vm.sol"; + +struct ContractDeployment { + address avsDirectory; + address avsDirectoryImplementation; + address baseStrategyImplementation; + address delegationManager; + address delegationManagerImplementation; + address eigenPodBeacon; + address eigenPodImplementation; + address eigenPodManager; + address eigenPodManagerImplementation; + address emptyContract; + address pauserRegistry; + address proxyAdmin; + address rewardsCoordinator; + address rewardsCoordinatorImplementation; + address slasher; + address slasherImplementation; + address strategyManager; + address strategyManagerImplementation; + address ethDepositAddress; +} + +library DeploymentDetails { + VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code"))))); + + function write( + ContractDeployment calldata deploymentDetails, + address executorMultisig, + address operationsMultisig, + address nilContract + ) external { + // WRITE JSON DATA + string memory parentObject = "parent object"; + + string memory deployedAddresses = "address"; + vm.serializeAddress(deployedAddresses, "proxyAdmin", deploymentDetails.proxyAdmin); + vm.serializeAddress(deployedAddresses, "pauserRegistry", deploymentDetails.pauserRegistry); + vm.serializeAddress(deployedAddresses, "slasher", deploymentDetails.slasher); + vm.serializeAddress(deployedAddresses, "slasherImplementation", deploymentDetails.slasherImplementation); + vm.serializeAddress(deployedAddresses, "delegationManager", deploymentDetails.delegationManager); + vm.serializeAddress( + deployedAddresses, + "delegationManagerImplementation", + deploymentDetails.delegationManagerImplementation + ); + vm.serializeAddress(deployedAddresses, "avsDirectory", deploymentDetails.avsDirectory); + vm.serializeAddress( + deployedAddresses, + "avsDirectoryImplementation", + deploymentDetails.avsDirectoryImplementation + ); + vm.serializeAddress(deployedAddresses, "strategyManager", deploymentDetails.strategyManager); + vm.serializeAddress( + deployedAddresses, + "strategyManagerImplementation", + deploymentDetails.strategyManagerImplementation + ); + vm.serializeAddress(deployedAddresses, "eigenPodManager", deploymentDetails.eigenPodManager); + vm.serializeAddress( + deployedAddresses, + "eigenPodManagerImplementation", + deploymentDetails.eigenPodManagerImplementation + ); + vm.serializeAddress(deployedAddresses, "rewardsCoordinator", deploymentDetails.rewardsCoordinator); + vm.serializeAddress( + deployedAddresses, + "rewardsCoordinatorImplementation", + deploymentDetails.rewardsCoordinatorImplementation + ); + vm.serializeAddress(deployedAddresses, "eigenPodBeacon", deploymentDetails.eigenPodBeacon); + vm.serializeAddress(deployedAddresses, "eigenPodImplementation", deploymentDetails.eigenPodImplementation); + vm.serializeAddress( + deployedAddresses, + "baseStrategyImplementation", + deploymentDetails.baseStrategyImplementation + ); + vm.serializeAddress(deployedAddresses, "emptyContract", nilContract); + vm.serializeAddress(deployedAddresses, "ethDepositAddress", deploymentDetails.ethDepositAddress); + + string memory deployedAddressesOutput = vm.serializeString(deployedAddresses, "strategies", ""); + + string memory parameters = "parameters"; + vm.serializeAddress(parameters, "executorMultisig", executorMultisig); + string memory parametersOutput = vm.serializeAddress(parameters, "operationsMultisig", operationsMultisig); + + string memory chainInfo = "chainInfo"; + vm.serializeUint(chainInfo, "deploymentBlock", block.number); + string memory chainInfo_output = vm.serializeUint(chainInfo, "chainId", block.chainid); + + // serialize all the data + vm.serializeString(parentObject, deployedAddresses, deployedAddressesOutput); + vm.serializeString(parentObject, chainInfo, chainInfo_output); + string memory finalJson = vm.serializeString(parentObject, parameters, parametersOutput); + // TODO: should output to different file depending on configFile passed to run() + // so that we don't override mainnet output by deploying to goerli for eg. + vm.writeJson(finalJson, "script/output/devnet/M2_deploy_from_scratch_deployment_data.json"); + console2.log("Deployment data written to script/output/devnet/M2_deploy_from_scratch_deployment_data.json"); + } + + function read(string memory deploymentFileName) external returns (ContractDeployment memory) { + string memory deployDetailsPath = string(bytes(string.concat("script/output/devnet/", deploymentFileName))); + string memory deployData = vm.readFile(deployDetailsPath); + ContractDeployment memory deploymentDetails; + deploymentDetails.avsDirectory = stdJson.readAddress(deployData, ".address.avsDirectory"); + deploymentDetails.avsDirectoryImplementation = stdJson.readAddress( + deployData, + ".address.avsDirectoryImplementation" + ); + deploymentDetails.baseStrategyImplementation = stdJson.readAddress( + deployData, + ".address.baseStrategyImplementation" + ); + deploymentDetails.delegationManager = stdJson.readAddress(deployData, ".address.delegationManager"); + deploymentDetails.delegationManagerImplementation = stdJson.readAddress( + deployData, + ".address.delegationManagerImplementation" + ); + deploymentDetails.eigenPodBeacon = stdJson.readAddress(deployData, ".address.eigenPodBeacon"); + deploymentDetails.eigenPodImplementation = stdJson.readAddress(deployData, ".address.eigenPodImplementation"); + deploymentDetails.eigenPodManager = stdJson.readAddress(deployData, ".address.eigenPodManager"); + deploymentDetails.eigenPodManagerImplementation = stdJson.readAddress( + deployData, + ".address.eigenPodManagerImplementation" + ); + deploymentDetails.emptyContract = stdJson.readAddress(deployData, ".address.emptyContract"); + deploymentDetails.pauserRegistry = stdJson.readAddress(deployData, ".address.pauserRegistry"); + deploymentDetails.proxyAdmin = stdJson.readAddress(deployData, ".address.proxyAdmin"); + deploymentDetails.rewardsCoordinator = stdJson.readAddress(deployData, ".address.rewardsCoordinator"); + deploymentDetails.rewardsCoordinatorImplementation = stdJson.readAddress( + deployData, + ".address.rewardsCoordinatorImplementation" + ); + deploymentDetails.slasher = stdJson.readAddress(deployData, ".address.slasher"); + deploymentDetails.slasherImplementation = stdJson.readAddress(deployData, ".address.slasherImplementation"); + deploymentDetails.strategyManager = stdJson.readAddress(deployData, ".address.strategyManager"); + deploymentDetails.strategyManagerImplementation = stdJson.readAddress( + deployData, + ".address.strategyManagerImplementation" + ); + deploymentDetails.ethDepositAddress = stdJson.readAddress(deployData, ".address.ethDepositAddress"); + + return deploymentDetails; + } +} diff --git a/script/deploy/devnet/M2_Deploy_From_Scratch.s.sol b/script/deploy/devnet/M2_Deploy_From_Scratch.s.sol index 55510a7c9..71fedc7fc 100644 --- a/script/deploy/devnet/M2_Deploy_From_Scratch.s.sol +++ b/script/deploy/devnet/M2_Deploy_From_Scratch.s.sol @@ -1,5 +1,11 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.12; +// solhint-disable no-console + +import {Script} from "forge-std/Script.sol"; +import {VmSafe} from "forge-std/Vm.sol"; +import {stdJson} from "forge-std/StdJson.sol"; +import {console2} from "forge-std/console2.sol"; import "@openzeppelin/contracts/token/ERC20/presets/ERC20PresetFixedSupply.sol"; import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; @@ -24,16 +30,15 @@ import "../../../src/contracts/permissions/PauserRegistry.sol"; import "../../../src/test/mocks/EmptyContract.sol"; import "../../../src/test/mocks/ETHDepositMock.sol"; -import "forge-std/Script.sol"; -import "forge-std/Test.sol"; +import {ContractDeployment, DeploymentDetails} from "./DeploymentDetails.sol"; // # To load the variables in the .env file // source .env // # To deploy and verify our contract // forge script script/deploy/devnet/M2_Deploy_From_Scratch.s.sol --rpc-url $RPC_URL --private-key $PRIVATE_KEY --broadcast --sig "run(string memory configFile)" -- M2_deploy_from_scratch.anvil.config.json -contract Deployer_M2 is Script, Test { - Vm cheats = Vm(HEVM_ADDRESS); +contract Deployer_M2 is Script { + address public constant ETH_DEPOSIT_ADDRESS_MAINNET = 0x00000000219ab540356cBB839Cbe05303d7705Fa; // struct used to encode token info in config file struct StrategyConfig { @@ -43,15 +48,13 @@ contract Deployer_M2 is Script, Test { string tokenSymbol; } - string public deployConfigPath; - // EigenLayer Contracts ProxyAdmin public eigenLayerProxyAdmin; PauserRegistry public eigenLayerPauserReg; Slasher public slasher; Slasher public slasherImplementation; - DelegationManager public delegation; - DelegationManager public delegationImplementation; + DelegationManager public delegationManager; + DelegationManager public delegationManagerImplementation; StrategyManager public strategyManager; StrategyManager public strategyManagerImplementation; RewardsCoordinator public rewardsCoordinator; @@ -64,8 +67,6 @@ contract Deployer_M2 is Script, Test { EigenPod public eigenPodImplementation; StrategyBase public baseStrategyImplementation; - EmptyContract public emptyContract; - address executorMultisig; address operationsMultisig; address pauserMultisig; @@ -79,6 +80,8 @@ contract Deployer_M2 is Script, Test { // IMMUTABLES TO SET uint64 GOERLI_GENESIS_TIME = 1616508000; + address ETH_DEPOSIT_ADDRESS = ETH_DEPOSIT_ADDRESS_MAINNET; + // OTHER DEPLOYMENT PARAMETERS uint256 STRATEGY_MANAGER_INIT_PAUSED_STATUS; uint256 SLASHER_INIT_PAUSED_STATUS; @@ -102,56 +105,17 @@ contract Deployer_M2 is Script, Test { function run(string memory configFileName) external { // read and log the chainID - uint256 chainId = block.chainid; - emit log_named_uint("You are deploying on ChainID", chainId); + console2.log("You are deploying on ChainID", block.chainid); + console2.log("account is ", msg.sender); - // READ JSON CONFIG DATA - deployConfigPath = string(bytes(string.concat("script/configs/devnet/", configFileName))); - string memory config_data = vm.readFile(deployConfigPath); - // bytes memory parsedData = vm.parseJson(config_data); - - STRATEGY_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".strategyManager.init_paused_status"); - SLASHER_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".slasher.init_paused_status"); - DELEGATION_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".delegation.init_paused_status"); - DELEGATION_WITHDRAWAL_DELAY_BLOCKS = stdJson.readUint(config_data, ".delegation.init_withdrawal_delay_blocks"); - EIGENPOD_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint(config_data, ".eigenPodManager.init_paused_status"); - REWARDS_COORDINATOR_INIT_PAUSED_STATUS = stdJson.readUint( - config_data, - ".rewardsCoordinator.init_paused_status" - ); - REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS = uint32( - stdJson.readUint(config_data, ".rewardsCoordinator.CALCULATION_INTERVAL_SECONDS") - ); - REWARDS_COORDINATOR_MAX_REWARDS_DURATION = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.MAX_REWARDS_DURATION")); - REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.MAX_RETROACTIVE_LENGTH")); - REWARDS_COORDINATOR_MAX_FUTURE_LENGTH = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.MAX_FUTURE_LENGTH")); - REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.GENESIS_REWARDS_TIMESTAMP")); - REWARDS_COORDINATOR_UPDATER = stdJson.readAddress(config_data, ".rewardsCoordinator.rewards_updater_address"); - REWARDS_COORDINATOR_ACTIVATION_DELAY = uint32(stdJson.readUint(config_data, ".rewardsCoordinator.activation_delay")); - REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS = uint32( - stdJson.readUint(config_data, ".rewardsCoordinator.calculation_interval_seconds") - ); - REWARDS_COORDINATOR_GLOBAL_OPERATOR_COMMISSION_BIPS = uint32( - stdJson.readUint(config_data, ".rewardsCoordinator.global_operator_commission_bips") - ); - - STRATEGY_MANAGER_INIT_WITHDRAWAL_DELAY_BLOCKS = uint32( - stdJson.readUint(config_data, ".strategyManager.init_withdrawal_delay_blocks") - ); + string memory configData = _readConfig(configFileName); // tokens to deploy strategies for StrategyConfig[] memory strategyConfigs; - - executorMultisig = stdJson.readAddress(config_data, ".multisig_addresses.executorMultisig"); - operationsMultisig = stdJson.readAddress(config_data, ".multisig_addresses.operationsMultisig"); - pauserMultisig = stdJson.readAddress(config_data, ".multisig_addresses.pauserMultisig"); // load token list - bytes memory strategyConfigsRaw = stdJson.parseRaw(config_data, ".strategies"); + bytes memory strategyConfigsRaw = stdJson.parseRaw(configData, ".strategies"); strategyConfigs = abi.decode(strategyConfigsRaw, (StrategyConfig[])); - require(executorMultisig != address(0), "executorMultisig address not configured correctly!"); - require(operationsMultisig != address(0), "operationsMultisig address not configured correctly!"); - // START RECORDING TRANSACTIONS FOR DEPLOYMENT vm.startBroadcast(); @@ -167,59 +131,55 @@ contract Deployer_M2 is Script, Test { eigenLayerPauserReg = new PauserRegistry(pausers, executorMultisig); } + address nilContract = address(new EmptyContract()); + /** * First, deploy upgradeable proxy contracts that **will point** to the implementations. Since the implementation contracts are * not yet deployed, we give these proxies an empty contract as the initial implementation, to act as if they have no code. */ - emptyContract = new EmptyContract(); - delegation = DelegationManager( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + delegationManager = DelegationManager( + address(new TransparentUpgradeableProxy(nilContract, address(eigenLayerProxyAdmin), "")) ); strategyManager = StrategyManager( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + address(new TransparentUpgradeableProxy(nilContract, address(eigenLayerProxyAdmin), "")) ); avsDirectory = AVSDirectory( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - slasher = Slasher( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + address(new TransparentUpgradeableProxy(nilContract, address(eigenLayerProxyAdmin), "")) ); + slasher = Slasher(address(new TransparentUpgradeableProxy(nilContract, address(eigenLayerProxyAdmin), ""))); eigenPodManager = EigenPodManager( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + address(new TransparentUpgradeableProxy(nilContract, address(eigenLayerProxyAdmin), "")) ); rewardsCoordinator = RewardsCoordinator( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + address(new TransparentUpgradeableProxy(nilContract, address(eigenLayerProxyAdmin), "")) ); // if on mainnet, use the ETH2 deposit contract address - if (chainId == 1) { - ethPOSDeposit = IETHPOSDeposit(0x00000000219ab540356cBB839Cbe05303d7705Fa); + if (block.chainid == 1) { + ethPOSDeposit = IETHPOSDeposit(ETH_DEPOSIT_ADDRESS_MAINNET); + ETH_DEPOSIT_ADDRESS = ETH_DEPOSIT_ADDRESS_MAINNET; // if not on mainnet, deploy a mock } else { - ethPOSDeposit = IETHPOSDeposit(stdJson.readAddress(config_data, ".ethPOSDepositAddress")); + ethPOSDeposit = IETHPOSDeposit(ETH_DEPOSIT_ADDRESS); } - eigenPodImplementation = new EigenPod( - ethPOSDeposit, - eigenPodManager, - GOERLI_GENESIS_TIME - ); + eigenPodImplementation = new EigenPod(ethPOSDeposit, eigenPodManager, GOERLI_GENESIS_TIME); eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs - delegationImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); - strategyManagerImplementation = new StrategyManager(delegation, eigenPodManager, slasher); - avsDirectoryImplementation = new AVSDirectory(delegation); - slasherImplementation = new Slasher(strategyManager, delegation); + delegationManagerImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); + strategyManagerImplementation = new StrategyManager(delegationManager, eigenPodManager, slasher); + avsDirectoryImplementation = new AVSDirectory(delegationManager); + slasherImplementation = new Slasher(strategyManager, delegationManager); eigenPodManagerImplementation = new EigenPodManager( ethPOSDeposit, eigenPodBeacon, strategyManager, slasher, - delegation + delegationManager ); rewardsCoordinatorImplementation = new RewardsCoordinator( - delegation, + delegationManager, strategyManager, REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, REWARDS_COORDINATOR_MAX_REWARDS_DURATION, @@ -233,8 +193,8 @@ contract Deployer_M2 is Script, Test { IStrategy[] memory _strategies; uint256[] memory _withdrawalDelayBlocks; eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(delegation))), - address(delegationImplementation), + TransparentUpgradeableProxy(payable(address(delegationManager))), + address(delegationManagerImplementation), abi.encodeWithSelector( DelegationManager.initialize.selector, executorMultisig, @@ -245,6 +205,7 @@ contract Deployer_M2 is Script, Test { _withdrawalDelayBlocks ) ); + delegationManager.transferOwnership(executorMultisig); } eigenLayerProxyAdmin.upgradeAndCall( TransparentUpgradeableProxy(payable(address(strategyManager))), @@ -327,14 +288,14 @@ contract Deployer_M2 is Script, Test { // CHECK CORRECTNESS OF DEPLOYMENT _verifyContractsPointAtOneAnother( - delegationImplementation, + delegationManagerImplementation, strategyManagerImplementation, slasherImplementation, eigenPodManagerImplementation, rewardsCoordinatorImplementation ); _verifyContractsPointAtOneAnother( - delegation, + delegationManager, strategyManager, slasher, eigenPodManager, @@ -343,75 +304,103 @@ contract Deployer_M2 is Script, Test { _verifyImplementationsSetCorrectly(); _verifyInitialOwners(); _checkPauserInitializations(); - _verifyInitializationParams(); + _verifyInitializationParams(configData); - // WRITE JSON DATA - string memory parent_object = "parent object"; + _writeJsonDeployment(nilContract); + } - string memory deployed_strategies = "strategies"; - for (uint256 i = 0; i < strategyConfigs.length; ++i) { - vm.serializeAddress(deployed_strategies, strategyConfigs[i].tokenSymbol, address(deployedStrategyArray[i])); + function upgrade(string memory configFileName, string memory deploymentDetailsFilename) external { + // read and log the chainID + console2.log("You are upgrading ChainID", block.chainid); + console2.log("account is ", msg.sender); + + string memory configData = _readConfig(configFileName); + + ContractDeployment memory contractDeployment = _readJsonDeployment(deploymentDetailsFilename); + // tokens to deploy strategies for + StrategyConfig[] memory strategyConfigs; + + vm.startBroadcast(); + eigenPodImplementation = new EigenPod(ethPOSDeposit, eigenPodManager, GOERLI_GENESIS_TIME); + + // if on mainnet, use the ETH2 deposit contract address + if (block.chainid == 1) { + ethPOSDeposit = IETHPOSDeposit(ETH_DEPOSIT_ADDRESS_MAINNET); + ETH_DEPOSIT_ADDRESS = ETH_DEPOSIT_ADDRESS_MAINNET; + // if not on mainnet, deploy a mock + } else { + ethPOSDeposit = IETHPOSDeposit(ETH_DEPOSIT_ADDRESS); } - string memory deployed_strategies_output = strategyConfigs.length == 0 - ? "" - : vm.serializeAddress( - deployed_strategies, - strategyConfigs[strategyConfigs.length - 1].tokenSymbol, - address(deployedStrategyArray[strategyConfigs.length - 1]) - ); + eigenPodImplementation = new EigenPod(ethPOSDeposit, eigenPodManager, GOERLI_GENESIS_TIME); - string memory deployed_addresses = "addresses"; - vm.serializeAddress(deployed_addresses, "eigenLayerProxyAdmin", address(eigenLayerProxyAdmin)); - vm.serializeAddress(deployed_addresses, "eigenLayerPauserReg", address(eigenLayerPauserReg)); - vm.serializeAddress(deployed_addresses, "slasher", address(slasher)); - vm.serializeAddress(deployed_addresses, "slasherImplementation", address(slasherImplementation)); - vm.serializeAddress(deployed_addresses, "delegation", address(delegation)); - vm.serializeAddress(deployed_addresses, "delegationImplementation", address(delegationImplementation)); - vm.serializeAddress(deployed_addresses, "avsDirectory", address(avsDirectory)); - vm.serializeAddress(deployed_addresses, "avsDirectoryImplementation", address(avsDirectoryImplementation)); - vm.serializeAddress(deployed_addresses, "strategyManager", address(strategyManager)); - vm.serializeAddress( - deployed_addresses, - "strategyManagerImplementation", + // Second, deploy the *implementation* contracts, using the *proxy contracts* as inputs + delegationManagerImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); + strategyManagerImplementation = new StrategyManager(delegationManager, eigenPodManager, slasher); + avsDirectoryImplementation = new AVSDirectory(delegationManager); + slasherImplementation = new Slasher(strategyManager, delegationManager); + eigenPodManagerImplementation = new EigenPodManager( + ethPOSDeposit, + eigenPodBeacon, + strategyManager, + slasher, + delegationManager + ); + rewardsCoordinatorImplementation = new RewardsCoordinator( + delegationManager, + strategyManager, + REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS, + REWARDS_COORDINATOR_MAX_REWARDS_DURATION, + REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH, + REWARDS_COORDINATOR_MAX_FUTURE_LENGTH, + REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP + ); + + // Second, upgrade the proxy contracts to point to the implementations + + console2.log("ProxyAdmin is owned by", eigenLayerProxyAdmin.owner()); + + // DelegationManager + eigenLayerProxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(delegationManager))), + address(delegationManagerImplementation) + ); + // StrategyManager + eigenLayerProxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(strategyManager))), address(strategyManagerImplementation) ); - vm.serializeAddress(deployed_addresses, "eigenPodManager", address(eigenPodManager)); - vm.serializeAddress( - deployed_addresses, - "eigenPodManagerImplementation", + // Slasher + eigenLayerProxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(slasher))), + address(slasherImplementation) + ); + // EigenPodManager + eigenLayerProxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(eigenPodManager))), address(eigenPodManagerImplementation) ); - vm.serializeAddress(deployed_addresses, "rewardsCoordinator", address(rewardsCoordinator)); - vm.serializeAddress( - deployed_addresses, - "rewardsCoordinatorImplementation", - address(rewardsCoordinatorImplementation) - ); - vm.serializeAddress(deployed_addresses, "eigenPodBeacon", address(eigenPodBeacon)); - vm.serializeAddress(deployed_addresses, "eigenPodImplementation", address(eigenPodImplementation)); - vm.serializeAddress(deployed_addresses, "baseStrategyImplementation", address(baseStrategyImplementation)); - vm.serializeAddress(deployed_addresses, "emptyContract", address(emptyContract)); - string memory deployed_addresses_output = vm.serializeString( - deployed_addresses, - "strategies", - deployed_strategies_output - ); - - string memory parameters = "parameters"; - vm.serializeAddress(parameters, "executorMultisig", executorMultisig); - string memory parameters_output = vm.serializeAddress(parameters, "operationsMultisig", operationsMultisig); - - string memory chain_info = "chainInfo"; - vm.serializeUint(chain_info, "deploymentBlock", block.number); - string memory chain_info_output = vm.serializeUint(chain_info, "chainId", chainId); - - // serialize all the data - vm.serializeString(parent_object, deployed_addresses, deployed_addresses_output); - vm.serializeString(parent_object, chain_info, chain_info_output); - string memory finalJson = vm.serializeString(parent_object, parameters, parameters_output); - // TODO: should output to different file depending on configFile passed to run() - // so that we don't override mainnet output by deploying to goerli for eg. - vm.writeJson(finalJson, "script/output/devnet/M2_from_scratch_deployment_data.json"); + // AVSDirectory, upgrade and initalized + eigenLayerProxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(avsDirectory))), + address(avsDirectoryImplementation) + ); + + // Create base strategy implementation and deploy a few strategies + baseStrategyImplementation = new StrategyBase(strategyManager); + + // Upgrade All deployed strategy contracts to new base strategy + for (uint i = 0; i < strategyConfigs.length; i++) { + // Upgrade existing strategy + eigenLayerProxyAdmin.upgrade( + TransparentUpgradeableProxy(payable(address(deployedStrategyArray[i]))), + address(baseStrategyImplementation) + ); + } + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); + + _writeJsonDeployment(contractDeployment.emptyContract); } function _verifyContractsPointAtOneAnother( @@ -429,7 +418,7 @@ contract Deployer_M2 is Script, Test { require(strategyManagerContract.slasher() == slasher, "strategyManager: slasher address not set correctly"); require( - strategyManagerContract.delegation() == delegation, + strategyManagerContract.delegation() == delegationManager, "strategyManager: delegation address not set correctly" ); require( @@ -459,20 +448,21 @@ contract Deployer_M2 is Script, Test { ); require( - rewardsCoordinatorContract.delegationManager() == delegation, + rewardsCoordinatorContract.delegationManager() == delegationManager, "rewardsCoordinator: delegation address not set correctly" ); require( - rewardsCoordinatorContract.strategyManager() == strategyManager, + rewardsCoordinatorContract.strategyManager() == strategyManager, "rewardsCoordinator: strategyManager address not set correctly" ); } function _verifyImplementationsSetCorrectly() internal view { require( - eigenLayerProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(delegation)))) == - address(delegationImplementation), + eigenLayerProxyAdmin.getProxyImplementation( + TransparentUpgradeableProxy(payable(address(delegationManager))) + ) == address(delegationManagerImplementation), "delegation: implementation set incorrectly" ); require( @@ -516,7 +506,7 @@ contract Deployer_M2 is Script, Test { function _verifyInitialOwners() internal view { require(strategyManager.owner() == executorMultisig, "strategyManager: owner not set correctly"); - require(delegation.owner() == executorMultisig, "delegation: owner not set correctly"); + require(delegationManager.owner() == executorMultisig, "delegation: owner not set correctly"); // removing slasher requirements because there is no slasher as part of m2-mainnet release // require(slasher.owner() == executorMultisig, "slasher: owner not set correctly"); require(eigenPodManager.owner() == executorMultisig, "eigenPodManager: owner not set correctly"); @@ -526,7 +516,10 @@ contract Deployer_M2 is Script, Test { } function _checkPauserInitializations() internal view { - require(delegation.pauserRegistry() == eigenLayerPauserReg, "delegation: pauser registry not set correctly"); + require( + delegationManager.pauserRegistry() == eigenLayerPauserReg, + "delegation: pauser registry not set correctly" + ); require( strategyManager.pauserRegistry() == eigenLayerPauserReg, "strategyManager: pauser registry not set correctly" @@ -573,7 +566,7 @@ contract Deployer_M2 is Script, Test { // require(eigenPodManager.paused() == 30, "eigenPodManager: init paused status set incorrectly"); } - function _verifyInitializationParams() internal { + function _verifyInitializationParams(string memory configData) internal { // // one week in blocks -- 50400 // uint32 STRATEGY_MANAGER_INIT_WITHDRAWAL_DELAY_BLOCKS = 7 days / 12 seconds; // require(strategyManager.withdrawalDelayBlocks() == 7 days / 12 seconds, @@ -599,14 +592,13 @@ contract Deployer_M2 is Script, Test { " eigenPodImplementation: eigenPodManager contract address not set correctly" ); - string memory config_data = vm.readFile(deployConfigPath); for (uint i = 0; i < deployedStrategyArray.length; i++) { uint256 maxPerDeposit = stdJson.readUint( - config_data, + configData, string.concat(".strategies[", vm.toString(i), "].max_per_deposit") ); uint256 maxDeposits = stdJson.readUint( - config_data, + configData, string.concat(".strategies[", vm.toString(i), "].max_deposits") ); (uint256 setMaxPerDeposit, uint256 setMaxDeposits) = deployedStrategyArray[i].getTVLLimits(); @@ -614,4 +606,106 @@ contract Deployer_M2 is Script, Test { require(setMaxDeposits == maxDeposits, "setMaxDeposits not set correctly"); } } + + function _readConfig(string memory configFileName) internal returns (string memory) { + string memory deployConfigPath = string(bytes(string.concat("script/configs/devnet/", configFileName))); + string memory configData = vm.readFile(deployConfigPath); + + // READ JSON CONFIG DATA + // bytes memory parsedData = vm.parseJson(configData); + STRATEGY_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint(configData, ".strategyManager.init_paused_status"); + SLASHER_INIT_PAUSED_STATUS = stdJson.readUint(configData, ".slasher.init_paused_status"); + DELEGATION_INIT_PAUSED_STATUS = stdJson.readUint(configData, ".delegation.init_paused_status"); + DELEGATION_WITHDRAWAL_DELAY_BLOCKS = stdJson.readUint(configData, ".delegation.init_withdrawal_delay_blocks"); + EIGENPOD_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint(configData, ".eigenPodManager.init_paused_status"); + REWARDS_COORDINATOR_INIT_PAUSED_STATUS = stdJson.readUint(configData, ".rewardsCoordinator.init_paused_status"); + REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS = uint32( + stdJson.readUint(configData, ".rewardsCoordinator.CALCULATION_INTERVAL_SECONDS") + ); + REWARDS_COORDINATOR_MAX_REWARDS_DURATION = uint32( + stdJson.readUint(configData, ".rewardsCoordinator.MAX_REWARDS_DURATION") + ); + REWARDS_COORDINATOR_MAX_RETROACTIVE_LENGTH = uint32( + stdJson.readUint(configData, ".rewardsCoordinator.MAX_RETROACTIVE_LENGTH") + ); + REWARDS_COORDINATOR_MAX_FUTURE_LENGTH = uint32( + stdJson.readUint(configData, ".rewardsCoordinator.MAX_FUTURE_LENGTH") + ); + REWARDS_COORDINATOR_GENESIS_REWARDS_TIMESTAMP = uint32( + stdJson.readUint(configData, ".rewardsCoordinator.GENESIS_REWARDS_TIMESTAMP") + ); + REWARDS_COORDINATOR_UPDATER = stdJson.readAddress(configData, ".rewardsCoordinator.rewards_updater_address"); + REWARDS_COORDINATOR_ACTIVATION_DELAY = uint32( + stdJson.readUint(configData, ".rewardsCoordinator.activation_delay") + ); + REWARDS_COORDINATOR_CALCULATION_INTERVAL_SECONDS = uint32( + stdJson.readUint(configData, ".rewardsCoordinator.calculation_interval_seconds") + ); + REWARDS_COORDINATOR_GLOBAL_OPERATOR_COMMISSION_BIPS = uint32( + stdJson.readUint(configData, ".rewardsCoordinator.global_operator_commission_bips") + ); + + STRATEGY_MANAGER_INIT_WITHDRAWAL_DELAY_BLOCKS = uint32( + stdJson.readUint(configData, ".strategyManager.init_withdrawal_delay_blocks") + ); + + ETH_DEPOSIT_ADDRESS = stdJson.readAddress(configData, ".ethPOSDepositAddress"); + + executorMultisig = stdJson.readAddress(configData, ".multisig_addresses.executorMultisig"); + operationsMultisig = stdJson.readAddress(configData, ".multisig_addresses.operationsMultisig"); + pauserMultisig = stdJson.readAddress(configData, ".multisig_addresses.pauserMultisig"); + + require(executorMultisig != address(0), "executorMultisig address not configured correctly!"); + require(operationsMultisig != address(0), "operationsMultisig address not configured correctly!"); + + return configData; + } + + function _writeJsonDeployment(address nilContract) internal { + ContractDeployment memory contractDeployment = ContractDeployment({ + avsDirectory: address(avsDirectory), + avsDirectoryImplementation: address(avsDirectoryImplementation), + baseStrategyImplementation: address(baseStrategyImplementation), + delegationManager: address(delegationManager), + delegationManagerImplementation: address(delegationManagerImplementation), + eigenPodBeacon: address(eigenPodBeacon), + eigenPodImplementation: address(eigenPodImplementation), + eigenPodManager: address(eigenPodManager), + eigenPodManagerImplementation: address(eigenPodManagerImplementation), + emptyContract: nilContract, + pauserRegistry: address(eigenLayerPauserReg), + proxyAdmin: address(eigenLayerProxyAdmin), + rewardsCoordinator: address(rewardsCoordinator), + rewardsCoordinatorImplementation: address(rewardsCoordinatorImplementation), + slasher: address(slasher), + slasherImplementation: address(slasherImplementation), + strategyManager: address(strategyManager), + strategyManagerImplementation: address(strategyManagerImplementation), + ethDepositAddress: ETH_DEPOSIT_ADDRESS + }); + DeploymentDetails.write(contractDeployment, executorMultisig, operationsMultisig, nilContract); + } + + function _readJsonDeployment(string memory deploymentDetailsFilename) internal returns (ContractDeployment memory) { + ContractDeployment memory contractDeployment = DeploymentDetails.read(deploymentDetailsFilename); + console2.log("proxyAdmin", contractDeployment.proxyAdmin); + eigenLayerProxyAdmin = ProxyAdmin(contractDeployment.proxyAdmin); + eigenLayerPauserReg = PauserRegistry(contractDeployment.pauserRegistry); + slasher = Slasher(contractDeployment.slasher); + slasherImplementation = Slasher(contractDeployment.slasherImplementation); + delegationManager = DelegationManager(contractDeployment.delegationManager); + delegationManagerImplementation = DelegationManager(contractDeployment.delegationManagerImplementation); + strategyManager = StrategyManager(contractDeployment.strategyManager); + strategyManagerImplementation = StrategyManager(contractDeployment.strategyManagerImplementation); + rewardsCoordinator = RewardsCoordinator(contractDeployment.rewardsCoordinator); + rewardsCoordinatorImplementation = RewardsCoordinator(contractDeployment.rewardsCoordinatorImplementation); + avsDirectory = AVSDirectory(contractDeployment.avsDirectory); + avsDirectoryImplementation = AVSDirectory(contractDeployment.avsDirectoryImplementation); + eigenPodManager = EigenPodManager(contractDeployment.eigenPodManager); + eigenPodManagerImplementation = EigenPodManager(contractDeployment.eigenPodManagerImplementation); + eigenPodBeacon = UpgradeableBeacon(contractDeployment.eigenPodBeacon); + eigenPodImplementation = EigenPod(payable(contractDeployment.eigenPodImplementation)); + baseStrategyImplementation = StrategyBase(contractDeployment.baseStrategyImplementation); + ETH_DEPOSIT_ADDRESS = contractDeployment.ethDepositAddress; + } } diff --git a/script/output/devnet/M2_from_scratch_deployment_data.json b/script/output/devnet/M2_from_scratch_deployment_data.json index 5c47c3720..5db5edefc 100644 --- a/script/output/devnet/M2_from_scratch_deployment_data.json +++ b/script/output/devnet/M2_from_scratch_deployment_data.json @@ -1,33 +1,31 @@ { - "addresses": { - "avsDirectory": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707", - "avsDirectoryImplementation": "0x9A676e781A523b5d0C0e43731313A708CB607508", - "baseStrategyImplementation": "0x7a2088a1bFc9d81c55368AE168C2C02570cB814F", - "delayedWithdrawalRouter": "0x2279B7A0a67DB372996a5FaB50D91eAA73d2eBe6", - "delayedWithdrawalRouterImplementation": "0x9A9f2CCfdE556A7E9Ff0848998Aa4a0CFD8863AE", - "delegation": "0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9", - "delegationImplementation": "0xA51c1fc2f0D1a1b8494Ed1FE312d7C3a78Ed91C0", - "eigenLayerPauserReg": "0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512", - "eigenLayerProxyAdmin": "0x5FbDB2315678afecb367f032d93F642f64180aa3", - "eigenPodBeacon": "0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e", - "eigenPodImplementation": "0x610178dA211FEF7D417bC0e6FeD39F05609AD788", - "eigenPodManager": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", - "eigenPodManagerImplementation": "0x959922bE3CAee4b8Cd9a407cc3ac1C251C2007B1", - "emptyContract": "0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0", - "rewardsCoordinator": "0x8A791620dd6260079BF849Dc5567aDC3F2FdC318", - "rewardsCoordinatorImplementation": "0x68B1D87F95878fE05B998F19b66F4baba5De1aed", - "slasher": "0x0165878A594ca255338adfa4d48449f69242Eb8F", - "slasherImplementation": "0x0B306BF915C4d645ff596e518fAf3F9669b97016", + "address": { + "avsDirectory": "0x831533Ab19a39Cecd1809bfa76Ef90b050472706", + "avsDirectoryImplementation": "0x0F4319CA038E1FA284A9fDA7fD73498d5395480E", + "baseStrategyImplementation": "0x538f67a8631e85839229c528cEd6bacb42eEafE3", + "delegation": "0xd0140a90e0353f6368078b0447f5a2fe6a83B5f4", + "delegationImplementation": "0xef2aA4024Cb97B364d414F63DA89F98Bb7e1DCb1", + "eigenLayerPauserReg": "0x6Cd7Bb5E5a533c2EEF1b4cD67a23ee11B9F00223", + "eigenLayerProxyAdmin": "0x7375491a31DBc110086d2B87AFcFC6e501fFCD77", + "eigenPodBeacon": "0x98E351eEFE180054990352072D1FC9EAafdFa4Df", + "eigenPodImplementation": "0x3B5429b9aca4c0dAE2c646B73C75E08b6c7341b4", + "eigenPodManager": "0x128CBf55ECc325752368dFAafB6f11C6E7718457", + "eigenPodManagerImplementation": "0x2f3A8e3242Ad40C2618216130caB145d89fc1a39", + "emptyContract": "0xcCcc666eF06274bf6ad79e28541679A72354fd0C", + "rewardsCoordinator": "0x0FA540A978ba8B600A2F525600412a86a155D0F9", + "rewardsCoordinatorImplementation": "0x7Ea931F76CeFaF9962D4E23225F139898257809E", + "slasher": "0xc197a40A916Bb8EeBD154751180891341A614e0C", + "slasherImplementation": "0xf977D94c69B95eA756E7f43A6f04E1108cc2E446", "strategies": "", - "strategyManager": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", - "strategyManagerImplementation": "0x0DCd1Bf9A1b36cE34237eEaFef220932846BCD82" + "strategyManager": "0xa2ab5e1f78bFB3FDb97eD221051B4675101Fb995", + "strategyManagerImplementation": "0x14FBE812727dF14973A67BE1BbC3E00fB21F085d" }, "chainInfo": { - "chainId": 31337, - "deploymentBlock": 0 + "chainId": 11155151, + "deploymentBlock": 982 }, "parameters": { - "executorMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", - "operationsMultisig": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + "executorMultisig": "0x4a3Ee341f8ceEdB790F511A18899fBC1fdEb35af", + "operationsMultisig": "0x4a3Ee341f8ceEdB790F511A18899fBC1fdEb35af" } } \ No newline at end of file