From 0fd79d6496c20501e88aed6eec8a7230ff2804f8 Mon Sep 17 00:00:00 2001 From: 8sunyuan Date: Mon, 11 Mar 2024 21:14:02 -0400 Subject: [PATCH 01/13] script: parser script helpers --- .env.example | 1 + ...M2_deploy_from_scratch.holesky.config.json | 52 +++ .../holesky/M2_Deploy_From_Scratch.s.sol | 27 ++ script/utils/ExistingDeploymentParser.sol | 438 +++++++++++++++++- 4 files changed, 501 insertions(+), 17 deletions(-) create mode 100644 script/configs/holesky/M2_deploy_from_scratch.holesky.config.json create mode 100644 script/deploy/holesky/M2_Deploy_From_Scratch.s.sol diff --git a/.env.example b/.env.example index 8985dacc60..948f166c8b 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,5 @@ RPC_MAINNET="https://eth.llamarpc.com" # RPC_MAINNET="https://mainnet.infura.io/v3/API-KEY" RPC_GOERLI="https://ethereum-goerli.publicnode.com" +RPC_HOLESKY="" ETHERSCAN_API_KEY="API-KEY" diff --git a/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json b/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json new file mode 100644 index 0000000000..4f8f8772a6 --- /dev/null +++ b/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json @@ -0,0 +1,52 @@ +{ + "chainInfo": { + "chainId": 17000 + }, + "multisig_addresses": { + "pauserMultisig": "0x53410249ec7d3a3F9F1ba3912D50D6A3Df6d10A7", + "communityMultisig": "0xCb8d2f9e55Bc7B1FA9d089f9aC80C583D2BDD5F7", + "operationsMultisig": "0xfaEF7338b7490b9E272d80A1a39f4657cAf2b97d", + "executorMultisig": "0x28Ade60640fdBDb2609D8d8734D1b5cBeFc0C348", + "timelock": "0xcF19CE0561052a7A7Ff21156730285997B350A7D" + }, + "strategies": [ + { + "token_address": "0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034", + "token_name": "Liquid staked Ether 2.0", + "token_symbol": "stETH" + }, + { + "token_address": "0x7322c24752f79c05FFD1E2a6FCB97020C1C264F1", + "token_name": "Rocket Pool ETH", + "token_symbol": "rETH" + } + ], + "strategyManager": { + "init_strategy_whitelister": "", + "init_paused_status": 0 + }, + "delegationManager": { + "init_paused_status": 0, + "init_minWithdrawalDelayBlocks": 50400 + }, + "avsDirectory": { + "init_paused_status": 0 + }, + "slasher": { + "init_paused_status": 0 + }, + "eigenPod": { + "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": 32000000000000000000, + "GENESIS_TIME": 1695902400 + }, + "eigenPodManager": { + "init_paused_status": 0, + "beaconOracleContract": "0x4C116BB629bff7A8373c2378bBd919f8349B8f25" + }, + "delayedWithdrawalRouter": { + "init_paused_status": 0, + "init_withdrawalDelayBlocks": 50400 + }, + "ethPOSDepositAddress": "0x4242424242424242424242424242424242424242", + "beaconOracleAddress": "0x4C116BB629bff7A8373c2378bBd919f8349B8f25" +} \ No newline at end of file diff --git a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol new file mode 100644 index 0000000000..05392888ea --- /dev/null +++ b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity =0.8.12; + +import "../../utils/ExistingDeploymentParser.sol"; + +contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { + function run() external { + _parseInitialDeploymentParams("script/configs/holesky/M2_deploy_from_scratch.holesky.config.json"); + + // // START RECORDING TRANSACTIONS FOR DEPLOYMENT + // vm.startBroadcast(); + // _deployFromScratch(); + + // // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + // vm.stopBroadcast(); + + // Sanity Checks + _verifyContractPointers(); + _verifyImplementations(); + _verifyContractsInitialized({isInitialDeployment: true}); + _verifyInitializationParams(); + + logContractAddresses(); + } + + function _deployFromScratch() internal {} +} diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol index 8d2544b265..3ad9bb75de 100644 --- a/script/utils/ExistingDeploymentParser.sol +++ b/script/utils/ExistingDeploymentParser.sol @@ -11,6 +11,7 @@ import "../../src/contracts/core/DelegationManager.sol"; import "../../src/contracts/core/AVSDirectory.sol"; import "../../src/contracts/strategies/StrategyBase.sol"; +import "../../src/contracts/strategies/StrategyBaseTVLLimits.sol"; import "../../src/contracts/pods/EigenPod.sol"; import "../../src/contracts/pods/EigenPodManager.sol"; @@ -24,7 +25,6 @@ import "forge-std/Script.sol"; import "forge-std/Test.sol"; contract ExistingDeploymentParser is Script, Test { - // EigenLayer Contracts ProxyAdmin public eigenLayerProxyAdmin; PauserRegistry public eigenLayerPauserReg; @@ -32,14 +32,15 @@ contract ExistingDeploymentParser is Script, Test { Slasher public slasherImplementation; AVSDirectory public avsDirectory; AVSDirectory public avsDirectoryImplementation; - DelegationManager public delegation; - DelegationManager public delegationImplementation; + DelegationManager public delegationManager; + DelegationManager public delegationManagerImplementation; StrategyManager public strategyManager; StrategyManager public strategyManagerImplementation; EigenPodManager public eigenPodManager; EigenPodManager public eigenPodManagerImplementation; DelayedWithdrawalRouter public delayedWithdrawalRouter; DelayedWithdrawalRouter public delayedWithdrawalRouterImplementation; + IBeaconChainOracle beaconOracle; UpgradeableBeacon public eigenPodBeacon; EigenPod public eigenPodImplementation; StrategyBase public baseStrategyImplementation; @@ -48,10 +49,42 @@ contract ExistingDeploymentParser is Script, Test { address executorMultisig; address operationsMultisig; + address communityMultisig; + address pauserMultisig; // strategies deployed StrategyBase[] public deployedStrategyArray; + // the ETH2 deposit contract -- if not on mainnet, we deploy a mock as stand-in + IETHPOSDeposit public ethPOSDeposit; + + // // IMMUTABLES TO SET + // uint64 MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR; + // uint64 GOERLI_GENESIS_TIME = 1616508000; + + /// @notice Initialization Params for first initial deployment scripts + // StrategyManager + uint256 STRATEGY_MANAGER_INIT_PAUSED_STATUS; + // SLasher + uint256 SLASHER_INIT_PAUSED_STATUS; + // DelegationManager + uint256 DELEGATION_MANAGER_INIT_PAUSED_STATUS; + uint256 DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS; + // AVSDirectory + uint256 AVS_DIRECTORY_INIT_PAUSED_STATUS; + // EigenPodManager + uint256 EIGENPOD_MANAGER_INIT_PAUSED_STATUS; + uint256 EIGENPOD_MANAGER_MAX_PODS; + // EigenPod + uint64 EIGENPOD_GENESIS_TIME; + uint64 EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR; + address ETHPOSDepositAddress; + uint256 DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS; + + // one week in blocks -- 50400 + uint32 DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS; + + /// @notice use for parsing already deployed EigenLayer contracts function _parseDeployedContracts(string memory existingDeploymentInfoPath) internal { // read and log the chainID uint256 currentChainId = block.chainid; @@ -67,25 +100,51 @@ contract ExistingDeploymentParser is Script, Test { // read all of the deployed addresses executorMultisig = stdJson.readAddress(existingDeploymentData, ".parameters.executorMultisig"); operationsMultisig = stdJson.readAddress(existingDeploymentData, ".parameters.operationsMultisig"); - - eigenLayerProxyAdmin = ProxyAdmin(stdJson.readAddress(existingDeploymentData, ".addresses.eigenLayerProxyAdmin")); - eigenLayerPauserReg = PauserRegistry(stdJson.readAddress(existingDeploymentData, ".addresses.eigenLayerPauserReg")); + communityMultisig = stdJson.readAddress(existingDeploymentData, ".parameters.communityMultisig"); + pauserMultisig = stdJson.readAddress(existingDeploymentData, ".parameters.pauserMultisig"); + + eigenLayerProxyAdmin = ProxyAdmin( + stdJson.readAddress(existingDeploymentData, ".addresses.eigenLayerProxyAdmin") + ); + eigenLayerPauserReg = PauserRegistry( + stdJson.readAddress(existingDeploymentData, ".addresses.eigenLayerPauserReg") + ); slasher = Slasher(stdJson.readAddress(existingDeploymentData, ".addresses.slasher")); - slasherImplementation = Slasher(stdJson.readAddress(existingDeploymentData, ".addresses.slasherImplementation")); - delegation = DelegationManager(stdJson.readAddress(existingDeploymentData, ".addresses.delegation")); - delegationImplementation = DelegationManager(stdJson.readAddress(existingDeploymentData, ".addresses.delegationImplementation")); + slasherImplementation = Slasher( + stdJson.readAddress(existingDeploymentData, ".addresses.slasherImplementation") + ); + delegationManager = DelegationManager(stdJson.readAddress(existingDeploymentData, ".addresses.delegation")); + delegationManagerImplementation = DelegationManager( + stdJson.readAddress(existingDeploymentData, ".addresses.delegationImplementation") + ); avsDirectory = AVSDirectory(stdJson.readAddress(existingDeploymentData, ".addresses.avsDirectory")); - avsDirectoryImplementation = AVSDirectory(stdJson.readAddress(existingDeploymentData, ".addresses.avsDirectoryImplementation")); + avsDirectoryImplementation = AVSDirectory( + stdJson.readAddress(existingDeploymentData, ".addresses.avsDirectoryImplementation") + ); strategyManager = StrategyManager(stdJson.readAddress(existingDeploymentData, ".addresses.strategyManager")); - strategyManagerImplementation = StrategyManager(stdJson.readAddress(existingDeploymentData, ".addresses.strategyManagerImplementation")); + strategyManagerImplementation = StrategyManager( + stdJson.readAddress(existingDeploymentData, ".addresses.strategyManagerImplementation") + ); eigenPodManager = EigenPodManager(stdJson.readAddress(existingDeploymentData, ".addresses.eigenPodManager")); - eigenPodManagerImplementation = EigenPodManager(stdJson.readAddress(existingDeploymentData, ".addresses.eigenPodManagerImplementation")); - delayedWithdrawalRouter = DelayedWithdrawalRouter(stdJson.readAddress(existingDeploymentData, ".addresses.delayedWithdrawalRouter")); - delayedWithdrawalRouterImplementation = - DelayedWithdrawalRouter(stdJson.readAddress(existingDeploymentData, ".addresses.delayedWithdrawalRouterImplementation")); + eigenPodManagerImplementation = EigenPodManager( + stdJson.readAddress(existingDeploymentData, ".addresses.eigenPodManagerImplementation") + ); + delayedWithdrawalRouter = DelayedWithdrawalRouter( + stdJson.readAddress(existingDeploymentData, ".addresses.delayedWithdrawalRouter") + ); + delayedWithdrawalRouterImplementation = DelayedWithdrawalRouter( + stdJson.readAddress(existingDeploymentData, ".addresses.delayedWithdrawalRouterImplementation") + ); + beaconOracle = IBeaconChainOracle( + stdJson.readAddress(existingDeploymentData, ".addresses.beaconOracleAddress") + ); eigenPodBeacon = UpgradeableBeacon(stdJson.readAddress(existingDeploymentData, ".addresses.eigenPodBeacon")); - eigenPodImplementation = EigenPod(payable(stdJson.readAddress(existingDeploymentData, ".addresses.eigenPodImplementation"))); - baseStrategyImplementation = StrategyBase(stdJson.readAddress(existingDeploymentData, ".addresses.baseStrategyImplementation")); + eigenPodImplementation = EigenPod( + payable(stdJson.readAddress(existingDeploymentData, ".addresses.eigenPodImplementation")) + ); + baseStrategyImplementation = StrategyBase( + stdJson.readAddress(existingDeploymentData, ".addresses.baseStrategyImplementation") + ); emptyContract = EmptyContract(stdJson.readAddress(existingDeploymentData, ".addresses.emptyContract")); /* @@ -103,4 +162,349 @@ contract ExistingDeploymentParser is Script, Test { } */ } + + /// @notice use for deploying a new set of EigenLayer contracts + /// Note that this does require multisigs to already be deployed + function _parseInitialDeploymentParams(string memory initialDeploymentParamsPath) internal { + // read and log the chainID + uint256 currentChainId = block.chainid; + emit log_named_uint("You are parsing on ChainID", currentChainId); + + // READ JSON CONFIG DATA + string memory initialDeploymentData = vm.readFile(initialDeploymentParamsPath); + + // check that the chainID matches the one in the config + uint256 configChainId = stdJson.readUint(initialDeploymentData, ".chainInfo.chainId"); + require(configChainId == currentChainId, "You are on the wrong chain for this config"); + + // read beacon oracle + beaconOracle = IBeaconChainOracle(stdJson.readAddress(initialDeploymentData, ".addresses.beaconOracleAddress")); + + // read all of the deployed addresses + executorMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.executorMultisig"); + operationsMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.operationsMultisig"); + communityMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.communityMultisig"); + pauserMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.pauserMultisig"); + + // Read initialize params for upgradeable contracts + STRATEGY_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint( + initialDeploymentData, + ".strategyManager.init_paused_status" + ); + SLASHER_INIT_PAUSED_STATUS = stdJson.readUint(initialDeploymentData, ".slasher.init_paused_status"); + // DelegationManager + DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS = stdJson.readUint( + initialDeploymentData, + ".delegationManager.init_minWithdrawalDelayBlocks" + ); + DELEGATION_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint( + initialDeploymentData, + ".delegationManager.init_paused_status" + ); + // AVSDirectory + AVS_DIRECTORY_INIT_PAUSED_STATUS = stdJson.readUint(initialDeploymentData, ".avsDirectory.init_paused_status"); + // EigenPodManager + EIGENPOD_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint( + initialDeploymentData, + ".eigenPodManager.init_paused_status" + ); + + // EigenPod + EIGENPOD_GENESIS_TIME = uint64(stdJson.readUint(initialDeploymentData, ".eigenPod.GENESIS_TIME")); + EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR = uint64( + stdJson.readUint(initialDeploymentData, ".eigenPod.MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR") + ); + ETHPOSDepositAddress = stdJson.readAddress(initialDeploymentData, ".ethPOSDepositAddress"); + // DelayedWithdrawalRouter + DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS = stdJson.readUint( + initialDeploymentData, + ".delayedWithdrawalRouter.init_paused_status" + ); + + // both set to one week in blocks 50400 + DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS = uint32( + stdJson.readUint(initialDeploymentData, ".delayedWithdrawalRouter.init_withdrawalDelayBlocks") + ); + + logInitialDeploymentParams(); + } + + /// @notice Ensure contracts point at each other correctly via constructors + function _verifyContractPointers() internal view { + // AVSDirectory + require( + avsDirectory.delegation() == delegationManager, + "avsDirectory: delegationManager address not set correctly" + ); + // DelegationManager + require(delegationManager.slasher() == slasher, "delegationManager: slasher address not set correctly"); + require( + delegationManager.strategyManager() == strategyManager, + "delegationManager: strategyManager address not set correctly" + ); + require( + delegationManager.eigenPodManager() == eigenPodManager, + "delegationManager: eigenPodManager address not set correctly" + ); + // StrategyManager + require(strategyManager.slasher() == slasher, "strategyManager: slasher address not set correctly"); + require( + strategyManager.delegation() == delegationManager, + "strategyManager: delegationManager address not set correctly" + ); + require( + strategyManager.eigenPodManager() == eigenPodManager, + "strategyManager: eigenPodManager address not set correctly" + ); + // EPM + require( + address(eigenPodManager.ethPOS()) == ETHPOSDepositAddress, + "eigenPodManager: ethPOSDeposit contract address not set correctly" + ); + require( + eigenPodManager.eigenPodBeacon() == eigenPodBeacon, + "eigenPodManager: eigenPodBeacon contract address not set correctly" + ); + require( + eigenPodManager.strategyManager() == strategyManager, + "eigenPodManager: strategyManager contract address not set correctly" + ); + require(eigenPodManager.slasher() == slasher, "eigenPodManager: slasher contract address not set correctly"); + require( + eigenPodManager.delegationManager() == delegationManager, + "eigenPodManager: delegationManager contract address not set correctly" + ); + // DelayedWithdrawalRouter + require( + delayedWithdrawalRouter.eigenPodManager() == eigenPodManager, + "delayedWithdrawalRouterContract: eigenPodManager address not set correctly" + ); + } + + /// @notice verify implementations for Transparent Upgradeable Proxies + function _verifyImplementations() internal view { + require( + eigenLayerProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(avsDirectory)))) == + address(avsDirectoryImplementation), + "avsDirectory: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + TransparentUpgradeableProxy(payable(address(delegationManager))) + ) == address(delegationManagerImplementation), + "delegationManager: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + TransparentUpgradeableProxy(payable(address(strategyManager))) + ) == address(strategyManagerImplementation), + "strategyManager: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(slasher)))) == + address(slasherImplementation), + "slasher: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + TransparentUpgradeableProxy(payable(address(eigenPodManager))) + ) == address(eigenPodManagerImplementation), + "eigenPodManager: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + TransparentUpgradeableProxy(payable(address(delayedWithdrawalRouter))) + ) == address(delayedWithdrawalRouterImplementation), + "delayedWithdrawalRouter: implementation set incorrectly" + ); + + for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { + require( + eigenLayerProxyAdmin.getProxyImplementation( + TransparentUpgradeableProxy(payable(address(deployedStrategyArray[i]))) + ) == address(baseStrategyImplementation), + "strategy: implementation set incorrectly" + ); + } + + require( + eigenPodBeacon.implementation() == address(eigenPodImplementation), + "eigenPodBeacon: implementation set incorrectly" + ); + } + + /** + * @notice Verify initialization of Transparent Upgradeable Proxies. Also check + * initialization params if this is the first deployment. + * @param isInitialDeployment True if this is the first deployment of contracts from scratch + */ + function _verifyContractsInitialized(bool isInitialDeployment) internal { + // AVSDirectory + vm.expectRevert(bytes("Initializable: contract is already initialized")); + avsDirectory.initialize(address(0), eigenLayerPauserReg, AVS_DIRECTORY_INIT_PAUSED_STATUS); + // DelegationManager + vm.expectRevert(bytes("Initializable: contract is already initialized")); + IStrategy[] memory initializeStrategiesToSetDelayBlocks = new IStrategy[](0); + uint256[] memory initializeWithdrawalDelayBlocks = new uint256[](0); + delegationManager.initialize( + address(0), + eigenLayerPauserReg, + 0, + 0, // minWithdrawalDelayBLocks + initializeStrategiesToSetDelayBlocks, + initializeWithdrawalDelayBlocks + ); + // StrategyManager + vm.expectRevert(bytes("Initializable: contract is already initialized")); + strategyManager.initialize(address(0), address(0), eigenLayerPauserReg, STRATEGY_MANAGER_INIT_PAUSED_STATUS); + // EigenPodManager + vm.expectRevert(bytes("Initializable: contract is already initialized")); + eigenPodManager.initialize( + EIGENPOD_MANAGER_MAX_PODS, + beaconOracle, + address(0), + eigenLayerPauserReg, + EIGENPOD_MANAGER_INIT_PAUSED_STATUS + ); + // DelayedWithdrawalRouter + vm.expectRevert(bytes("Initializable: contract is already initialized")); + delayedWithdrawalRouter.initialize( + address(0), + eigenLayerPauserReg, + DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS, + DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS + ); + // Strategies + for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { + vm.expectRevert(bytes("Initializable: contract is already initialized")); + StrategyBaseTVLLimits(address(deployedStrategyArray[i])).initialize( + 0, + 0, + IERC20(address(0)), + eigenLayerPauserReg + ); + } + } + + /// @notice Verify params based on config constants that are updated from calling `_parseInitialDeploymentParams` + function _verifyInitializationParams() internal { + // AVSDirectory + require( + avsDirectory.pauserRegistry() == eigenLayerPauserReg, + "avsdirectory: pauser registry not set correctly" + ); + require(avsDirectory.owner() == executorMultisig, "avsdirectory: owner not set correctly"); + require( + avsDirectory.paused() == AVS_DIRECTORY_INIT_PAUSED_STATUS, + "avsdirectory: init paused status set incorrectly" + ); + // DelegationManager + require( + delegationManager.pauserRegistry() == eigenLayerPauserReg, + "delegationManager: pauser registry not set correctly" + ); + require(delegationManager.owner() == executorMultisig, "delegationManager: owner not set correctly"); + require( + delegationManager.paused() == DELEGATION_MANAGER_INIT_PAUSED_STATUS, + "delegationManager: init paused status set incorrectly" + ); + require( + delegationManager.minWithdrawalDelayBlocks() == DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS, + "delegationManager: minWithdrawalDelayBlocks not set correctly" + ); + // StrategyManager + require( + strategyManager.pauserRegistry() == eigenLayerPauserReg, + "strategyManager: pauser registry not set correctly" + ); + require(strategyManager.owner() == executorMultisig, "strategyManager: owner not set correctly"); + require( + strategyManager.paused() == STRATEGY_MANAGER_INIT_PAUSED_STATUS, + "strategyManager: init paused status set incorrectly" + ); + // EigenPodManager + require( + eigenPodManager.pauserRegistry() == eigenLayerPauserReg, + "eigenPodManager: pauser registry not set correctly" + ); + require(eigenPodManager.owner() == executorMultisig, "eigenPodManager: owner not set correctly"); + require( + eigenPodManager.paused() == EIGENPOD_MANAGER_INIT_PAUSED_STATUS, + "eigenPodManager: init paused status set incorrectly" + ); + // EigenPodBeacon + require(eigenPodBeacon.owner() == executorMultisig, "eigenPodBeacon: owner not set correctly"); + // DelayedWithdrawalRouter + require( + delayedWithdrawalRouter.pauserRegistry() == eigenLayerPauserReg, + "delayedWithdrawalRouter: pauser registry not set correctly" + ); + require( + delayedWithdrawalRouter.owner() == executorMultisig, + "delayedWithdrawalRouter: owner not set correctly" + ); + require( + delayedWithdrawalRouter.paused() == DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS, + "delayedWithdrawalRouter: init paused status set incorrectly" + ); + require( + delayedWithdrawalRouter.withdrawalDelayBlocks() == DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS, + "delayedWithdrawalRouter: withdrawalDelayBlocks not set correctly" + ); + // Strategies + for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { + require( + deployedStrategyArray[i].pauserRegistry() == eigenLayerPauserReg, + "StrategyBaseTVLLimits: pauser registry not set correctly" + ); + require( + deployedStrategyArray[i].paused() == 0, + "StrategyBaseTVLLimits: init paused status set incorrectly" + ); + } + + // Pausing Permissions + require(eigenLayerPauserReg.isPauser(operationsMultisig), "pauserRegistry: operationsMultisig is not pauser"); + require(eigenLayerPauserReg.isPauser(executorMultisig), "pauserRegistry: executorMultisig is not pauser"); + require(eigenLayerPauserReg.isPauser(pauserMultisig), "pauserRegistry: pauserMultisig is not pauser"); + require(eigenLayerPauserReg.unpauser() == executorMultisig, "pauserRegistry: unpauser not set correctly"); + } + + function logInitialDeploymentParams() public { + emit log_string("==== Parsed Initilize Params for Initial Deployment ===="); + + emit log_named_address("executorMultisig", executorMultisig); + emit log_named_address("operationsMultisig", operationsMultisig); + emit log_named_address("communityMultisig", communityMultisig); + emit log_named_address("pauserMultisig", pauserMultisig); + + emit log_named_uint("STRATEGY_MANAGER_INIT_PAUSED_STATUS", STRATEGY_MANAGER_INIT_PAUSED_STATUS); + emit log_named_uint("SLASHER_INIT_PAUSED_STATUS", SLASHER_INIT_PAUSED_STATUS); + emit log_named_uint( + "DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS", + DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS + ); + emit log_named_uint("DELEGATION_MANAGER_INIT_PAUSED_STATUS", DELEGATION_MANAGER_INIT_PAUSED_STATUS); + emit log_named_uint("AVS_DIRECTORY_INIT_PAUSED_STATUS", AVS_DIRECTORY_INIT_PAUSED_STATUS); + emit log_named_uint("EIGENPOD_MANAGER_INIT_PAUSED_STATUS", EIGENPOD_MANAGER_INIT_PAUSED_STATUS); + emit log_named_uint("EIGENPOD_MANAGER_MAX_PODS", EIGENPOD_MANAGER_MAX_PODS); + emit log_named_uint("EIGENPOD_GENESIS_TIME", EIGENPOD_GENESIS_TIME); + emit log_named_uint( + "EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR", + EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR + ); + emit log_named_address("ETHPOSDepositAddress", ETHPOSDepositAddress); + emit log_named_uint( + "DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS", + DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS + ); + emit log_named_uint( + "DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS", + DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS + ); + } + + function logContractAddresses() public { + emit log_string("==== Contract Addresses from Deployment/Upgrade ===="); + } } From 3b0fb49dca93c33d1ba6957492a3dd10db57dc47 Mon Sep 17 00:00:00 2001 From: 8sunyuan Date: Tue, 12 Mar 2024 12:14:05 -0400 Subject: [PATCH 02/13] feat: holesky deploy scripts --- ...M2_deploy_from_scratch.holesky.config.json | 32 +-- .../holesky/M2_Deploy_From_Scratch.s.sol | 194 +++++++++++++++++- script/utils/ExistingDeploymentParser.sol | 132 +++++++++++- 3 files changed, 333 insertions(+), 25 deletions(-) diff --git a/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json b/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json index 4f8f8772a6..8fef056a6a 100644 --- a/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json +++ b/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json @@ -9,18 +9,24 @@ "executorMultisig": "0x28Ade60640fdBDb2609D8d8734D1b5cBeFc0C348", "timelock": "0xcF19CE0561052a7A7Ff21156730285997B350A7D" }, - "strategies": [ - { - "token_address": "0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034", - "token_name": "Liquid staked Ether 2.0", - "token_symbol": "stETH" - }, - { - "token_address": "0x7322c24752f79c05FFD1E2a6FCB97020C1C264F1", - "token_name": "Rocket Pool ETH", - "token_symbol": "rETH" - } - ], + "numStrategies": 2, + "strategies": { + "numStrategies": 2, + "MAX_PER_DEPOSIT": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "MAX_TOTAL_DEPOSITS": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "strategiesToDeploy": [ + { + "token_address": "0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034", + "token_name": "Liquid staked Ether 2.0", + "token_symbol": "stETH" + }, + { + "token_address": "0x7322c24752f79c05FFD1E2a6FCB97020C1C264F1", + "token_name": "Rocket Pool ETH", + "token_symbol": "rETH" + } + ] + }, "strategyManager": { "init_strategy_whitelister": "", "init_paused_status": 0 @@ -41,7 +47,7 @@ }, "eigenPodManager": { "init_paused_status": 0, - "beaconOracleContract": "0x4C116BB629bff7A8373c2378bBd919f8349B8f25" + "deneb_fork_timestamp": "1707323664" }, "delayedWithdrawalRouter": { "init_paused_status": 0, diff --git a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol index 05392888ea..4878f2bd95 100644 --- a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol +++ b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol @@ -3,16 +3,25 @@ pragma solidity =0.8.12; import "../../utils/ExistingDeploymentParser.sol"; +/** + * @notice Script used for the first deployment of EigenLayer core contracts to Holesky + * forge script script/deploy/holesky/M2_Deploy_From_Scratch.s.sol --rpc-url http://127.0.0.1:8545 --private-key $PRIVATE_KEY --broadcast -vvvv + * forge script script/deploy/holesky/M2_Deploy_From_Scratch.s.sol --rpc-url $RPC_HOLESKY --private-key $PRIVATE_KEY --broadcast -vvvv + * + */ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { function run() external { _parseInitialDeploymentParams("script/configs/holesky/M2_deploy_from_scratch.holesky.config.json"); - // // START RECORDING TRANSACTIONS FOR DEPLOYMENT - // vm.startBroadcast(); - // _deployFromScratch(); + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); - // // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT - // vm.stopBroadcast(); + emit log_named_address("Deployer Address", msg.sender); + + _deployFromScratch(); + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); // Sanity Checks _verifyContractPointers(); @@ -20,8 +29,179 @@ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { _verifyContractsInitialized({isInitialDeployment: true}); _verifyInitializationParams(); - logContractAddresses(); + logAndOutputContractAddresses("script/output/holesky/M2_deploy_from_scratch.holesky.config.json"); } - function _deployFromScratch() internal {} + /** + * @notice Deploy EigenLayer contracts from scratch for Holesky + */ + function _deployFromScratch() internal { + // Deploy ProxyAdmin, later set admins for all proxies to be executorMultisig + eigenLayerProxyAdmin = new ProxyAdmin(); + + // Set multisigs as pausers, executorMultisig as unpauser + address[] memory pausers = new address[](3); + pausers[0] = executorMultisig; + pausers[1] = operationsMultisig; + pausers[2] = pauserMultisig; + address unpauser = executorMultisig; + eigenLayerPauserReg = new PauserRegistry(pausers, unpauser); + + /** + * 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(); + avsDirectory = AVSDirectory( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + delegationManager = DelegationManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + strategyManager = StrategyManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + slasher = Slasher( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + eigenPodManager = EigenPodManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + delayedWithdrawalRouter = DelayedWithdrawalRouter( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + + // Deploy EigenPod Contracts + eigenPodImplementation = new EigenPod( + IETHPOSDeposit(ETHPOSDepositAddress), + delayedWithdrawalRouter, + eigenPodManager, + EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR, + EIGENPOD_GENESIS_TIME + ); + + eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); + avsDirectoryImplementation = new AVSDirectory(delegationManager); + delegationManagerImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); + strategyManagerImplementation = new StrategyManager(delegationManager, eigenPodManager, slasher); + slasherImplementation = new Slasher(strategyManager, delegationManager); + eigenPodManagerImplementation = new EigenPodManager( + IETHPOSDeposit(ETHPOSDepositAddress), + eigenPodBeacon, + strategyManager, + slasher, + delegationManager + ); + delayedWithdrawalRouterImplementation = new DelayedWithdrawalRouter(eigenPodManager); + + // Third, upgrade the proxy contracts to point to the implementations + IStrategy[] memory initializeStrategiesToSetDelayBlocks = new IStrategy[](0); + uint256[] memory initializeWithdrawalDelayBlocks = new uint256[](0); + // AVSDirectory + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(avsDirectory))), + address(avsDirectoryImplementation), + abi.encodeWithSelector( + AVSDirectory.initialize.selector, + executorMultisig, // initialOwner + eigenLayerPauserReg, + AVS_DIRECTORY_INIT_PAUSED_STATUS + ) + ); + // DelegationManager + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(delegationManager))), + address(delegationManagerImplementation), + abi.encodeWithSelector( + DelegationManager.initialize.selector, + executorMultisig, // initialOwner + eigenLayerPauserReg, + DELEGATION_MANAGER_INIT_PAUSED_STATUS, + DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS, + initializeStrategiesToSetDelayBlocks, + initializeWithdrawalDelayBlocks + ) + ); + // StrategyManager + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(strategyManager))), + address(strategyManagerImplementation), + abi.encodeWithSelector( + StrategyManager.initialize.selector, + executorMultisig, //initialOwner + executorMultisig, //initial whitelister + eigenLayerPauserReg, + STRATEGY_MANAGER_INIT_PAUSED_STATUS + ) + ); + // Slasher + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(slasher))), + address(slasherImplementation), + abi.encodeWithSelector( + Slasher.initialize.selector, + executorMultisig, + eigenLayerPauserReg, + SLASHER_INIT_PAUSED_STATUS + ) + ); + // EigenPodManager + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(eigenPodManager))), + address(eigenPodManagerImplementation), + abi.encodeWithSelector( + EigenPodManager.initialize.selector, + type(uint).max, // maxPods + beaconOracle, + msg.sender, // initialOwner is msg.sender for now to set forktimestamp later + eigenLayerPauserReg, + EIGENPOD_MANAGER_INIT_PAUSED_STATUS + ) + ); + // Delayed Withdrawal Router + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(delayedWithdrawalRouter))), + address(delayedWithdrawalRouterImplementation), + abi.encodeWithSelector( + DelayedWithdrawalRouter.initialize.selector, + executorMultisig, // initialOwner + eigenLayerPauserReg, + DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS, + DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS + ) + ); + + // Deploy Strategies + baseStrategyImplementation = new StrategyBaseTVLLimits(strategyManager); + uint256 numStrategiesToDeploy = strategiesToDeploy.length; + for (uint256 i = 0; i < numStrategiesToDeploy; i++) { + StrategyUnderlyingTokenConfig memory strategyConfig = strategiesToDeploy[i]; + + // Deploy and upgrade strategy + StrategyBaseTVLLimits strategy = StrategyBaseTVLLimits( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(strategy))), + address(baseStrategyImplementation), + abi.encodeWithSelector( + StrategyBaseTVLLimits.initialize.selector, + STRATEGY_MAX_PER_DEPOSIT, + STRATEGY_MAX_TOTAL_DEPOSITS, + IERC20(strategyConfig.tokenAddress), + eigenLayerPauserReg + ) + ); + + deployedStrategyArray.push(strategy); + } + + // Fork timestamp config + eigenPodManager.setDenebForkTimestamp(EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP); + + // Transfer ownership + eigenLayerProxyAdmin.transferOwnership(executorMultisig); + eigenPodManager.transferOwnership(executorMultisig); + eigenPodBeacon.transferOwnership(executorMultisig); + } } diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol index 3ad9bb75de..e25d11d1bf 100644 --- a/script/utils/ExistingDeploymentParser.sol +++ b/script/utils/ExistingDeploymentParser.sol @@ -24,6 +24,12 @@ import "../../src/test/mocks/EmptyContract.sol"; import "forge-std/Script.sol"; import "forge-std/Test.sol"; +struct StrategyUnderlyingTokenConfig { + address tokenAddress; + string tokenName; + string tokenSymbol; +} + contract ExistingDeploymentParser is Script, Test { // EigenLayer Contracts ProxyAdmin public eigenLayerProxyAdmin; @@ -54,9 +60,12 @@ contract ExistingDeploymentParser is Script, Test { // strategies deployed StrategyBase[] public deployedStrategyArray; + // Strategies to Deploy + uint256 numStrategiesToDeploy; + StrategyUnderlyingTokenConfig[] public strategiesToDeploy; // the ETH2 deposit contract -- if not on mainnet, we deploy a mock as stand-in - IETHPOSDeposit public ethPOSDeposit; + // IETHPOSDeposit public ethPOSDeposit; // // IMMUTABLES TO SET // uint64 MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR; @@ -75,6 +84,7 @@ contract ExistingDeploymentParser is Script, Test { // EigenPodManager uint256 EIGENPOD_MANAGER_INIT_PAUSED_STATUS; uint256 EIGENPOD_MANAGER_MAX_PODS; + uint64 EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP; // EigenPod uint64 EIGENPOD_GENESIS_TIME; uint64 EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR; @@ -84,6 +94,10 @@ contract ExistingDeploymentParser is Script, Test { // one week in blocks -- 50400 uint32 DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS; + // Strategy Deployment + uint256 STRATEGY_MAX_PER_DEPOSIT; + uint256 STRATEGY_MAX_TOTAL_DEPOSITS; + /// @notice use for parsing already deployed EigenLayer contracts function _parseDeployedContracts(string memory existingDeploymentInfoPath) internal { // read and log the chainID @@ -178,7 +192,7 @@ contract ExistingDeploymentParser is Script, Test { require(configChainId == currentChainId, "You are on the wrong chain for this config"); // read beacon oracle - beaconOracle = IBeaconChainOracle(stdJson.readAddress(initialDeploymentData, ".addresses.beaconOracleAddress")); + beaconOracle = IBeaconChainOracle(stdJson.readAddress(initialDeploymentData, ".beaconOracleAddress")); // read all of the deployed addresses executorMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.executorMultisig"); @@ -186,6 +200,26 @@ contract ExistingDeploymentParser is Script, Test { communityMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.communityMultisig"); pauserMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.pauserMultisig"); + // Strategies to Deploy, load strategy list + numStrategiesToDeploy = stdJson.readUint(initialDeploymentData, ".strategies.numStrategies"); + STRATEGY_MAX_PER_DEPOSIT = stdJson.readUint(initialDeploymentData, ".strategies.MAX_PER_DEPOSIT"); + STRATEGY_MAX_TOTAL_DEPOSITS = stdJson.readUint(initialDeploymentData, ".strategies.MAX_TOTAL_DEPOSITS"); + for (uint256 i = 0; i < numStrategiesToDeploy; ++i) { + // Form the key for the current element + string memory key = string.concat(".strategies.strategiesToDeploy[", vm.toString(i), "]"); + + // Use parseJson with the key to get the value for the current element + bytes memory tokenInfoBytes = stdJson.parseRaw(initialDeploymentData, key); + + // Decode the token information into the Token struct + StrategyUnderlyingTokenConfig memory tokenInfo = abi.decode( + tokenInfoBytes, + (StrategyUnderlyingTokenConfig) + ); + + strategiesToDeploy.push(tokenInfo); + } + // Read initialize params for upgradeable contracts STRATEGY_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint( initialDeploymentData, @@ -208,6 +242,10 @@ contract ExistingDeploymentParser is Script, Test { initialDeploymentData, ".eigenPodManager.init_paused_status" ); + EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP = uint64(stdJson.readUint( + initialDeploymentData, + ".eigenPodManager.deneb_fork_timestamp" + )); // EigenPod EIGENPOD_GENESIS_TIME = uint64(stdJson.readUint(initialDeploymentData, ".eigenPod.GENESIS_TIME")); @@ -487,7 +525,7 @@ contract ExistingDeploymentParser is Script, Test { emit log_named_uint("DELEGATION_MANAGER_INIT_PAUSED_STATUS", DELEGATION_MANAGER_INIT_PAUSED_STATUS); emit log_named_uint("AVS_DIRECTORY_INIT_PAUSED_STATUS", AVS_DIRECTORY_INIT_PAUSED_STATUS); emit log_named_uint("EIGENPOD_MANAGER_INIT_PAUSED_STATUS", EIGENPOD_MANAGER_INIT_PAUSED_STATUS); - emit log_named_uint("EIGENPOD_MANAGER_MAX_PODS", EIGENPOD_MANAGER_MAX_PODS); + emit log_named_uint("EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP", EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP); emit log_named_uint("EIGENPOD_GENESIS_TIME", EIGENPOD_GENESIS_TIME); emit log_named_uint( "EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR", @@ -502,9 +540,93 @@ contract ExistingDeploymentParser is Script, Test { "DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS", DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS ); + + emit log_string("==== Strategies to Deploy ===="); + for (uint256 i = 0; i < numStrategiesToDeploy; ++i) { + // Decode the token information into the Token struct + StrategyUnderlyingTokenConfig memory tokenInfo = strategiesToDeploy[i]; + + strategiesToDeploy.push(tokenInfo); + emit log_named_address("TOKEN ADDRESS", tokenInfo.tokenAddress); + emit log_named_string("TOKEN NAME", tokenInfo.tokenName); + emit log_named_string("TOKEN SYMBOL", tokenInfo.tokenSymbol); + } } - function logContractAddresses() public { - emit log_string("==== Contract Addresses from Deployment/Upgrade ===="); + /** + * @notice Log contract addresses and write to output json file + */ + function logAndOutputContractAddresses(string memory outputPath) public { + // WRITE JSON DATA + string memory parent_object = "parent object"; + + string memory deployed_strategies = "strategies"; + for (uint256 i = 0; i < numStrategiesToDeploy; ++i) { + vm.serializeAddress(deployed_strategies, strategiesToDeploy[i].tokenSymbol, address(deployedStrategyArray[i])); + } + string memory deployed_strategies_output = numStrategiesToDeploy == 0 + ? "" + : vm.serializeAddress( + deployed_strategies, + strategiesToDeploy[numStrategiesToDeploy - 1].tokenSymbol, + address(deployedStrategyArray[numStrategiesToDeploy - 1]) + ); + + 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, "avsDirectory", address(avsDirectory)); + vm.serializeAddress(deployed_addresses, "avsDirectoryImplementation", address(avsDirectoryImplementation)); + vm.serializeAddress(deployed_addresses, "delegationManager", address(delegationManager)); + vm.serializeAddress(deployed_addresses, "delegationManagerImplementation", address(delegationManagerImplementation)); + vm.serializeAddress(deployed_addresses, "strategyManager", address(strategyManager)); + vm.serializeAddress( + deployed_addresses, + "strategyManagerImplementation", + address(strategyManagerImplementation) + ); + vm.serializeAddress(deployed_addresses, "eigenPodManager", address(eigenPodManager)); + vm.serializeAddress( + deployed_addresses, + "eigenPodManagerImplementation", + address(eigenPodManagerImplementation) + ); + vm.serializeAddress(deployed_addresses, "delayedWithdrawalRouter", address(delayedWithdrawalRouter)); + vm.serializeAddress( + deployed_addresses, + "delayedWithdrawalRouterImplementation", + address(delayedWithdrawalRouterImplementation) + ); + vm.serializeAddress(deployed_addresses, "beaconOracle", address(beaconOracle)); + 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); + vm.serializeAddress(parameters, "operationsMultisig", operationsMultisig); + vm.serializeAddress(parameters, "communityMultisig", communityMultisig); + vm.serializeAddress(parameters, "pauserMultisig", pauserMultisig); + 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", block.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); + + vm.writeJson(finalJson, outputPath); + } } From 4f53c1cdb7159ce3c19cd7a4f113d596dbd2882f Mon Sep 17 00:00:00 2001 From: 8sunyuan Date: Tue, 12 Mar 2024 14:35:05 -0400 Subject: [PATCH 03/13] fix: config --- .../holesky/M2_deploy_from_scratch.holesky.config.json | 4 ++-- script/utils/ExistingDeploymentParser.sol | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json b/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json index 8fef056a6a..d143bf043c 100644 --- a/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json +++ b/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json @@ -28,7 +28,7 @@ ] }, "strategyManager": { - "init_strategy_whitelister": "", + "init_strategy_whitelister": "0xfaEF7338b7490b9E272d80A1a39f4657cAf2b97d", "init_paused_status": 0 }, "delegationManager": { @@ -47,7 +47,7 @@ }, "eigenPodManager": { "init_paused_status": 0, - "deneb_fork_timestamp": "1707323664" + "deneb_fork_timestamp": "1707305664" }, "delayedWithdrawalRouter": { "init_paused_status": 0, diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol index e25d11d1bf..bc86b86bf3 100644 --- a/script/utils/ExistingDeploymentParser.sol +++ b/script/utils/ExistingDeploymentParser.sol @@ -460,6 +460,10 @@ contract ExistingDeploymentParser is Script, Test { strategyManager.paused() == STRATEGY_MANAGER_INIT_PAUSED_STATUS, "strategyManager: init paused status set incorrectly" ); + require( + strategyManager.strategyWhitelister() == operationsMultisig, + "strategyManager: strategyWhitelister not set correctly" + ); // EigenPodManager require( eigenPodManager.pauserRegistry() == eigenLayerPauserReg, From 017584401ade7e1ad8b0c2b50d7b096b1788d4f1 Mon Sep 17 00:00:00 2001 From: 8sunyuan Date: Tue, 12 Mar 2024 16:12:32 -0400 Subject: [PATCH 04/13] fix: ops multisig whitelister --- script/deploy/holesky/M2_Deploy_From_Scratch.s.sol | 2 +- script/utils/ExistingDeploymentParser.sol | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol index 4878f2bd95..29369cffd6 100644 --- a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol +++ b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol @@ -129,7 +129,7 @@ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { abi.encodeWithSelector( StrategyManager.initialize.selector, executorMultisig, //initialOwner - executorMultisig, //initial whitelister + STRATEGY_MANAGER_WHITELISTER, //initial whitelister eigenLayerPauserReg, STRATEGY_MANAGER_INIT_PAUSED_STATUS ) diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol index bc86b86bf3..87b7264922 100644 --- a/script/utils/ExistingDeploymentParser.sol +++ b/script/utils/ExistingDeploymentParser.sol @@ -74,6 +74,7 @@ contract ExistingDeploymentParser is Script, Test { /// @notice Initialization Params for first initial deployment scripts // StrategyManager uint256 STRATEGY_MANAGER_INIT_PAUSED_STATUS; + uint256 STRATEGY_MANAGER_WHITELISTER; // SLasher uint256 SLASHER_INIT_PAUSED_STATUS; // DelegationManager @@ -225,6 +226,8 @@ contract ExistingDeploymentParser is Script, Test { initialDeploymentData, ".strategyManager.init_paused_status" ); + STRATEGY_MANAGER_WHITELISTER = stdJson.readUint(initialDeploymentData, ".strategyManager.init_strategy_whitelister"); + // Slasher SLASHER_INIT_PAUSED_STATUS = stdJson.readUint(initialDeploymentData, ".slasher.init_paused_status"); // DelegationManager DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS = stdJson.readUint( @@ -521,6 +524,7 @@ contract ExistingDeploymentParser is Script, Test { emit log_named_address("pauserMultisig", pauserMultisig); emit log_named_uint("STRATEGY_MANAGER_INIT_PAUSED_STATUS", STRATEGY_MANAGER_INIT_PAUSED_STATUS); + emit log_named_uint("STRATEGY_MANAGER_WHITELISTER", STRATEGY_MANAGER_WHITELISTER); emit log_named_uint("SLASHER_INIT_PAUSED_STATUS", SLASHER_INIT_PAUSED_STATUS); emit log_named_uint( "DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS", From 9ac0ef833ea03d97a25cefeb6bb26973e20e2075 Mon Sep 17 00:00:00 2001 From: Alex <18387287+wadealexc@users.noreply.github.com> Date: Tue, 12 Mar 2024 16:55:26 -0400 Subject: [PATCH 05/13] feat: track active validator count in pods (#474) --- src/contracts/pods/EigenPod.sol | 13 ++++++++++--- src/test/harnesses/EigenPodHarness.sol | 8 ++++++++ src/test/unit/EigenPodUnit.t.sol | 19 ++++++++++++++++++- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/contracts/pods/EigenPod.sol b/src/contracts/pods/EigenPod.sol index 49ab3b0d06..39bc286a0d 100644 --- a/src/contracts/pods/EigenPod.sol +++ b/src/contracts/pods/EigenPod.sol @@ -91,9 +91,12 @@ contract EigenPod is IEigenPod, Initializable, ReentrancyGuardUpgradeable, Eigen /// @notice This variable tracks any ETH deposited into this contract via the `receive` fallback function uint256 public nonBeaconChainETHBalanceWei; - /// @notice This variable tracks the total amount of partial withdrawals claimed via merkle proofs prior to a switch to ZK proofs for claiming partial withdrawals + /// @notice This variable tracks the total amount of partial withdrawals claimed via merkle proofs prior to a switch to ZK proofs for claiming partial withdrawals uint64 public sumOfPartialWithdrawalsClaimedGwei; + /// @notice Number of validators with proven withdrawal credentials, who do not have proven full withdrawals + uint256 activeValidatorCount; + modifier onlyEigenPodManager() { require(msg.sender == address(eigenPodManager), "EigenPod.onlyEigenPodManager: not eigenPodManager"); _; @@ -479,6 +482,7 @@ contract EigenPod is IEigenPod, Initializable, ReentrancyGuardUpgradeable, Eigen }); // Proofs complete - update this validator's status, record its proven balance, and save in state: + activeValidatorCount++; validatorInfo.status = VALIDATOR_STATUS.ACTIVE; validatorInfo.validatorIndex = validatorIndex; validatorInfo.mostRecentBalanceUpdateTimestamp = oracleTimestamp; @@ -697,9 +701,12 @@ contract EigenPod is IEigenPod, Initializable, ReentrancyGuardUpgradeable, Eigen * Finally, the validator is fully withdrawn. Update their status and place in state: */ - validatorInfo.restakedBalanceGwei = 0; - validatorInfo.status = VALIDATOR_STATUS.WITHDRAWN; + if (validatorInfo.status != VALIDATOR_STATUS.WITHDRAWN) { + activeValidatorCount--; + validatorInfo.status = VALIDATOR_STATUS.WITHDRAWN; + } + validatorInfo.restakedBalanceGwei = 0; _validatorPubkeyHashToInfo[validatorPubkeyHash] = validatorInfo; emit FullWithdrawalRedeemed(validatorIndex, withdrawalTimestamp, recipient, withdrawalAmountGwei); diff --git a/src/test/harnesses/EigenPodHarness.sol b/src/test/harnesses/EigenPodHarness.sol index 3cdd6409c0..c139620f06 100644 --- a/src/test/harnesses/EigenPodHarness.sol +++ b/src/test/harnesses/EigenPodHarness.sol @@ -20,6 +20,14 @@ contract EPInternalFunctions is EigenPod, Test { _GENESIS_TIME ) {} + function getActiveValidatorCount() public view returns (uint256) { + return activeValidatorCount; + } + + function setActiveValidatorCount(uint _count) public { + activeValidatorCount = _count; + } + function verifyWithdrawalCredentials( uint64 oracleTimestamp, bytes32 beaconStateRoot, diff --git a/src/test/unit/EigenPodUnit.t.sol b/src/test/unit/EigenPodUnit.t.sol index 7b907dfc40..f9100c7fe3 100644 --- a/src/test/unit/EigenPodUnit.t.sol +++ b/src/test/unit/EigenPodUnit.t.sol @@ -453,6 +453,8 @@ contract EigenPodUnitTests_VerifyWithdrawalCredentialsTests is EigenPodHarnessSe uint64 effectiveBalanceGwei = validatorFields.getEffectiveBalanceGwei(); assertGt(effectiveBalanceGwei, MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR, "Proof file has an effective balance less than 32 ETH"); + uint activeValidatorCountBefore = eigenPodHarness.getActiveValidatorCount(); + // Verify withdrawal credentials vm.expectEmit(true, true, true, true); emit ValidatorRestaked(validatorIndex); @@ -467,6 +469,8 @@ contract EigenPodUnitTests_VerifyWithdrawalCredentialsTests is EigenPodHarnessSe ); // Checks + uint activeValidatorCountAfter = eigenPodHarness.getActiveValidatorCount(); + assertEq(activeValidatorCountAfter, activeValidatorCountBefore + 1, "active validator count should increase when proving withdrawal credentials"); assertEq(restakedBalanceWei, uint256(MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR) * uint256(1e9), "Returned restaked balance gwei should be max"); _assertWithdrawalCredentialsSet(MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR); } @@ -480,6 +484,8 @@ contract EigenPodUnitTests_VerifyWithdrawalCredentialsTests is EigenPodHarnessSe uint64 effectiveBalanceGwei = validatorFields.getEffectiveBalanceGwei(); assertLt(effectiveBalanceGwei, MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR, "Proof file has an effective balance greater than 32 ETH"); + uint activeValidatorCountBefore = eigenPodHarness.getActiveValidatorCount(); + // Verify withdrawal credentials vm.expectEmit(true, true, true, true); emit ValidatorRestaked(validatorIndex); @@ -494,6 +500,8 @@ contract EigenPodUnitTests_VerifyWithdrawalCredentialsTests is EigenPodHarnessSe ); // Checks + uint activeValidatorCountAfter = eigenPodHarness.getActiveValidatorCount(); + assertEq(activeValidatorCountAfter, activeValidatorCountBefore + 1, "active validator count should increase when proving withdrawal credentials"); assertEq(restakedBalanceWei, uint256(effectiveBalanceGwei) * uint256(1e9), "Returned restaked balance gwei incorrect"); _assertWithdrawalCredentialsSet(effectiveBalanceGwei); } @@ -920,10 +928,19 @@ contract EigenPodUnitTests_WithdrawalTests is EigenPodHarnessSetup, ProofParsing mostRecentBalanceUpdateTimestamp: 0, status: IEigenPod.VALIDATOR_STATUS.ACTIVE }); + + // Since we're withdrawing using an ACTIVE validator, ensure we have + // a validator count to decrement + uint activeValidatorCountBefore = 1 + eigenPodHarness.getActiveValidatorCount(); + eigenPodHarness.setActiveValidatorCount(activeValidatorCountBefore); - // Process full withdrawal + // Process full withdrawal. IEigenPod.VerifiedWithdrawal memory vw = eigenPodHarness.processFullWithdrawal(0, pubkeyHash, 0, podOwner, withdrawalAmount, validatorInfo); + // Validate that our activeValidatorCount decreased + uint activeValidatorCountAfter = eigenPodHarness.getActiveValidatorCount(); + assertEq(activeValidatorCountAfter, activeValidatorCountBefore - 1, "active validator count should decrease when withdrawing active validator"); + // Get expected amounts based on withdrawalAmount uint64 amountETHToQueue; uint64 amountETHToSend; From 3ba2b34d0663dfcad9f81aa1c8e9148154aea852 Mon Sep 17 00:00:00 2001 From: Michael Sun <35479365+8sunyuan@users.noreply.github.com> Date: Wed, 13 Mar 2024 11:57:11 -0400 Subject: [PATCH 06/13] chore: remove maxPods (#463) * chore: remove maxPods * docs: update docs * refactor: set to private --- certora/specs/pods/EigenPodManager.spec | 1 - docs/core/EigenPodManager.md | 15 ---- script/deploy/mainnet/M2Deploy.s.sol | 6 +- .../utils/validateStorage/validateUpgrade.sh | 4 +- src/contracts/interfaces/IEigenPodManager.sol | 6 -- src/contracts/pods/EigenPodManager.sol | 19 ----- src/contracts/pods/EigenPodManagerStorage.sol | 5 +- src/test/DepositWithdraw.t.sol | 1 - src/test/EigenLayerDeployer.t.sol | 1 - src/test/EigenPod.t.sol | 82 ------------------- src/test/events/IEigenPodManagerEvents.sol | 4 - .../integration/IntegrationDeployer.t.sol | 1 - src/test/mocks/EigenPodManagerMock.sol | 3 - src/test/tree/EigenPodManagerUnit.tree | 7 -- src/test/unit/EigenPod-PodManagerUnit.t.sol | 3 - src/test/unit/EigenPodManagerUnit.t.sol | 44 +--------- 16 files changed, 7 insertions(+), 195 deletions(-) diff --git a/certora/specs/pods/EigenPodManager.spec b/certora/specs/pods/EigenPodManager.spec index 8d405c5fb5..37bdc41827 100644 --- a/certora/specs/pods/EigenPodManager.spec +++ b/certora/specs/pods/EigenPodManager.spec @@ -46,7 +46,6 @@ methods { function slasher() external returns (address) envfree; function hasPod(address podOwner) external returns (bool) envfree; function numPods() external returns (uint256) envfree; - function maxPods() external returns (uint256) envfree; function podOwnerShares(address podOwner) external returns (int256) envfree; function beaconChainETHStrategy() external returns (address) envfree; diff --git a/docs/core/EigenPodManager.md b/docs/core/EigenPodManager.md index f770782deb..24dabe1f5f 100644 --- a/docs/core/EigenPodManager.md +++ b/docs/core/EigenPodManager.md @@ -527,24 +527,9 @@ This method loops over up to `maxNumberOfDelayedWithdrawalsToClaim` withdrawals, ### System Configuration -* [`EigenPodManager.setMaxPods`](#eigenpodmanagersetmaxpods) * [`EigenPodManager.updateBeaconChainOracle`](#eigenpodmanagerupdatebeaconchainoracle) * [`DelayedWithdrawalRouter.setWithdrawalDelayBlocks`](#delayedwithdrawalroutersetwithdrawaldelayblocks) -#### `EigenPodManager.setMaxPods` - -```solidity -function setMaxPods(uint256 newMaxPods) external onlyUnpauser -``` - -Allows the unpauser to update the maximum number of `EigenPods` that the `EigenPodManager` can create. - -*Effects*: -* Updates `EigenPodManager.maxPods` - -*Requirements*: -* Caller MUST be the unpauser - #### `EigenPodManager.updateBeaconChainOracle` ```solidity diff --git a/script/deploy/mainnet/M2Deploy.s.sol b/script/deploy/mainnet/M2Deploy.s.sol index d93455e60e..a39eeb5449 100644 --- a/script/deploy/mainnet/M2Deploy.s.sol +++ b/script/deploy/mainnet/M2Deploy.s.sol @@ -62,7 +62,6 @@ contract M2Deploy is Script, Test { uint256 public withdrawalDelayBlocks; bytes32 public delegationManagerDomainSeparator; uint256 public numPods; - uint256 public maxPods; // Pointers to pre-upgrade values for lstDepositor address public lstDepositor; @@ -122,7 +121,6 @@ contract M2Deploy is Script, Test { withdrawalDelayBlocks = m1StrategyManager(address(strategyManager)).withdrawalDelayBlocks(); delegationManagerDomainSeparator = IDelegationManagerV0(address(delegation)).DOMAIN_SEPARATOR(); numPods = eigenPodManager.numPods(); - maxPods = eigenPodManager.maxPods(); delayedWithdrawalRouter = EigenPod(payable(eigenPodBeacon.implementation())).delayedWithdrawalRouter(); // Set chain-specific values @@ -277,7 +275,7 @@ contract M2Deploy is Script, Test { // Call contracts to ensure that all simple view functions return the same values (e.g. the return value of `StrategyManager.delegation()` hasn’t changed) // StrategyManager: delegation, eigenPodManager, slasher, strategyWhitelister, withdrawalDelayBlocks all unchanged // DelegationManager: DOMAIN_SEPARATOR, strategyManager, slasher, eigenPodManager all unchanged - // EigenPodManager: ethPOS, eigenPodBeacon, strategyManager, slasher, beaconChainOracle, numPods, maxPods all unchanged + // EigenPodManager: ethPOS, eigenPodBeacon, strategyManager, slasher, beaconChainOracle, numPods all unchanged // delegationManager is now correct (added immutable) // Call contracts to make sure they are still “initialized” (ensure that trying to call initializer reverts) function _verifyStorageSlots() internal view { @@ -311,7 +309,6 @@ contract M2Deploy is Script, Test { "eigenPodManager.beaconChainOracle incorrect" ); require(eigenPodManager.numPods() == numPods, "eigenPodManager.numPods incorrect"); - require(eigenPodManager.maxPods() == maxPods, "eigenPodManager.maxPods incorrect"); require(EigenPodManagerStorage(address(eigenPodManager)).delegationManager() == delegation, "eigenPodManager.delegationManager incorrect"); } @@ -339,7 +336,6 @@ contract M2Deploy is Script, Test { cheats.expectRevert(bytes("Initializable: contract is already initialized")); EigenPodManager(address(eigenPodManager)).initialize( - 0, IBeaconChainOracle(address(this)), address(this), PauserRegistry(address(this)), diff --git a/script/utils/validateStorage/validateUpgrade.sh b/script/utils/validateStorage/validateUpgrade.sh index 59a708d72d..943f30f6f4 100644 --- a/script/utils/validateStorage/validateUpgrade.sh +++ b/script/utils/validateStorage/validateUpgrade.sh @@ -69,7 +69,7 @@ echo "Comparing storage layouts..." # Add -k operator if present if [ ! -k "$1" ]; then echo "Keeping old storage layout files" - eval "npx ts-node script/upgrade/validateStorage.ts --old onChainLayout.csv --new localLayout.csv --keep" + eval "npx ts-node script/utils/validateStorage/validateStorage.ts --old onChainLayout.csv --new localLayout.csv --keep" else - eval "npx ts-node script/upgrade/validateStorage.ts --old onChainLayout.csv --new localLayout.csv" + eval "npx ts-node script/utils/validateStorage/validateStorage.ts --old onChainLayout.csv --new localLayout.csv" fi \ No newline at end of file diff --git a/src/contracts/interfaces/IEigenPodManager.sol b/src/contracts/interfaces/IEigenPodManager.sol index 020e0d2d97..4860cff408 100644 --- a/src/contracts/interfaces/IEigenPodManager.sol +++ b/src/contracts/interfaces/IEigenPodManager.sol @@ -26,9 +26,6 @@ interface IEigenPodManager is IPausable { /// @notice Emitted to notify a deposit of beacon chain ETH recorded in the strategy manager event BeaconChainETHDeposited(address indexed podOwner, uint256 amount); - /// @notice Emitted when `maxPods` value is updated from `previousValue` to `newValue` - event MaxPodsUpdated(uint256 previousValue, uint256 newValue); - /// @notice Emitted when the balance of an EigenPod is updated event PodSharesUpdated(address indexed podOwner, int256 sharesDelta); @@ -107,9 +104,6 @@ interface IEigenPodManager is IPausable { /// @notice Returns the number of EigenPods that have been created function numPods() external view returns (uint256); - /// @notice Returns the maximum number of EigenPods that can be created - function maxPods() external view returns (uint256); - /** * @notice Mapping from Pod owner owner to the number of shares they have in the virtual beacon chain ETH strategy. * @dev The share amount can become negative. This is necessary to accommodate the fact that a pod owner's virtual beacon chain ETH shares can diff --git a/src/contracts/pods/EigenPodManager.sol b/src/contracts/pods/EigenPodManager.sol index a90177a136..ce42de5445 100644 --- a/src/contracts/pods/EigenPodManager.sol +++ b/src/contracts/pods/EigenPodManager.sol @@ -55,13 +55,11 @@ contract EigenPodManager is } function initialize( - uint256 _maxPods, IBeaconChainOracle _beaconChainOracle, address initialOwner, IPauserRegistry _pauserRegistry, uint256 _initPausedStatus ) external initializer { - _setMaxPods(_maxPods); _updateBeaconChainOracle(_beaconChainOracle); _transferOwnership(initialOwner); _initializePauser(_pauserRegistry, _initPausedStatus); @@ -223,15 +221,6 @@ contract EigenPodManager is ownerToPod[podOwner].withdrawRestakedBeaconChainETH(destination, shares); } - /** - * Sets the maximum number of pods that can be deployed - * @param newMaxPods The new maximum number of pods that can be deployed - * @dev Callable by the unpauser of this contract - */ - function setMaxPods(uint256 newMaxPods) external onlyUnpauser { - _setMaxPods(newMaxPods); - } - /** * @notice Updates the oracle contract that provides the beacon chain state root * @param newBeaconChainOracle is the new oracle contract being pointed to @@ -256,8 +245,6 @@ contract EigenPodManager is // INTERNAL FUNCTIONS function _deployPod() internal returns (IEigenPod) { - // check that the limit of EigenPods has not been hit, and increment the EigenPod count - require(numPods + 1 <= maxPods, "EigenPodManager._deployPod: pod limit reached"); ++numPods; // create the pod IEigenPod pod = IEigenPod( @@ -281,12 +268,6 @@ contract EigenPodManager is emit BeaconOracleUpdated(address(newBeaconChainOracle)); } - /// @notice Internal setter for `maxPods` that also emits an event - function _setMaxPods(uint256 _maxPods) internal { - emit MaxPodsUpdated(maxPods, _maxPods); - maxPods = _maxPods; - } - /** * @notice Calculates the change in a pod owner's delegateable shares as a result of their beacon chain ETH shares changing * from `sharesBefore` to `sharesAfter`. The key concept here is that negative/"deficit" shares are not delegateable. diff --git a/src/contracts/pods/EigenPodManagerStorage.sol b/src/contracts/pods/EigenPodManagerStorage.sol index 76e687fbd4..f637f060ef 100644 --- a/src/contracts/pods/EigenPodManagerStorage.sol +++ b/src/contracts/pods/EigenPodManagerStorage.sol @@ -50,8 +50,9 @@ abstract contract EigenPodManagerStorage is IEigenPodManager { /// @notice The number of EigenPods that have been deployed uint256 public numPods; - /// @notice The maximum number of EigenPods that can be deployed - uint256 public maxPods; + /// @notice Deprecated from old mainnet release. Was initially used to limit growth early on but there is no longer + /// a maximum number of EigenPods that can be deployed. + uint256 private __deprecated_maxPods; // BEGIN STORAGE VARIABLES ADDED AFTER MAINNET DEPLOYMENT -- DO NOT SUGGEST REORDERING TO CONVENTIONAL ORDER /** diff --git a/src/test/DepositWithdraw.t.sol b/src/test/DepositWithdraw.t.sol index accb90382a..dea978d8d6 100644 --- a/src/test/DepositWithdraw.t.sol +++ b/src/test/DepositWithdraw.t.sol @@ -416,7 +416,6 @@ contract DepositWithdrawTests is EigenLayerTestHelper { address(eigenPodManagerImplementation), abi.encodeWithSelector( EigenPodManager.initialize.selector, - type(uint256).max, beaconChainOracleAddress, eigenLayerReputedMultisig, eigenLayerPauserReg, diff --git a/src/test/EigenLayerDeployer.t.sol b/src/test/EigenLayerDeployer.t.sol index ac28592d2b..8b5ada2a8e 100644 --- a/src/test/EigenLayerDeployer.t.sol +++ b/src/test/EigenLayerDeployer.t.sol @@ -303,7 +303,6 @@ contract EigenLayerDeployer is Operators { address(eigenPodManagerImplementation), abi.encodeWithSelector( EigenPodManager.initialize.selector, - type(uint256).max, // maxPods beaconChainOracleAddress, eigenLayerReputedMultisig, eigenLayerPauserReg, diff --git a/src/test/EigenPod.t.sol b/src/test/EigenPod.t.sol index 56cf277cf6..c991fb6963 100644 --- a/src/test/EigenPod.t.sol +++ b/src/test/EigenPod.t.sol @@ -76,9 +76,6 @@ contract EigenPodTests is ProofParsing, EigenPodPausingConstants { /// @notice Emitted to notify a deposit of beacon chain ETH recorded in the strategy manager event BeaconChainETHDeposited(address indexed podOwner, uint256 amount); - /// @notice Emitted when `maxPods` value is updated from `previousValue` to `newValue` - event MaxPodsUpdated(uint256 previousValue, uint256 newValue); - // EIGENPOD EVENTS /// @notice Emitted when an ETH validator stakes via this eigenPod event EigenPodStaked(bytes pubkey); @@ -238,7 +235,6 @@ contract EigenPodTests is ProofParsing, EigenPodPausingConstants { address(eigenPodManagerImplementation), abi.encodeWithSelector( EigenPodManager.initialize.selector, - type(uint256).max, // maxPods beaconChainOracle, initialOwner, pauserReg, @@ -1334,37 +1330,6 @@ contract EigenPodTests is ProofParsing, EigenPodPausingConstants { require(numPodsAfter == numPodsBefore + 1, "numPods did not increment correctly"); } - // verifies that the `maxPods` variable is enforced on the `EigenPod.stake` function - function test_maxPodsEnforcementOnStake( - bytes calldata _pubkey, - bytes calldata _signature, - bytes32 _depositDataRoot - ) public { - // set pod limit to current number of pods - cheats.startPrank(unpauser); - EigenPodManager(address(eigenPodManager)).setMaxPods(EigenPodManager(address(eigenPodManager)).numPods()); - cheats.stopPrank(); - - cheats.startPrank(podOwner); - cheats.expectRevert("EigenPodManager._deployPod: pod limit reached"); - eigenPodManager.stake{value: 32 ether}(_pubkey, _signature, _depositDataRoot); - cheats.stopPrank(); - - // set pod limit to *one more than* current number of pods - cheats.startPrank(unpauser); - EigenPodManager(address(eigenPodManager)).setMaxPods(EigenPodManager(address(eigenPodManager)).numPods() + 1); - cheats.stopPrank(); - - IEigenPod newPod = eigenPodManager.getPod(podOwner); - - cheats.startPrank(podOwner); - // successful call - cheats.expectEmit(true, true, true, true, address(newPod)); - emit EigenPodStaked(_pubkey); - eigenPodManager.stake{value: 32 ether}(_pubkey, _signature, _depositDataRoot); - cheats.stopPrank(); - } - // verifies that the `numPod` variable increments correctly on a succesful call to the `EigenPod.createPod` function function test_incrementNumPodsOnCreatePod() public { uint256 numPodsBefore = EigenPodManager(address(eigenPodManager)).numPods(); @@ -1379,53 +1344,6 @@ contract EigenPodTests is ProofParsing, EigenPodPausingConstants { eigenPodManager.createPod(); } - // verifies that the `maxPods` variable is enforced on the `EigenPod.createPod` function - function test_maxPodsEnforcementOnCreatePod() public { - // set pod limit to current number of pods - cheats.startPrank(unpauser); - uint256 previousValue = EigenPodManager(address(eigenPodManager)).maxPods(); - uint256 newValue = EigenPodManager(address(eigenPodManager)).numPods(); - cheats.expectEmit(true, true, true, true, address(eigenPodManager)); - emit MaxPodsUpdated(previousValue, newValue); - EigenPodManager(address(eigenPodManager)).setMaxPods(newValue); - cheats.stopPrank(); - - cheats.expectRevert("EigenPodManager._deployPod: pod limit reached"); - eigenPodManager.createPod(); - - // set pod limit to *one more than* current number of pods - cheats.startPrank(unpauser); - previousValue = EigenPodManager(address(eigenPodManager)).maxPods(); - newValue = EigenPodManager(address(eigenPodManager)).numPods() + 1; - cheats.expectEmit(true, true, true, true, address(eigenPodManager)); - emit MaxPodsUpdated(previousValue, newValue); - EigenPodManager(address(eigenPodManager)).setMaxPods(newValue); - cheats.stopPrank(); - - // successful call - eigenPodManager.createPod(); - } - - function test_setMaxPods(uint256 newValue) public { - cheats.startPrank(unpauser); - uint256 previousValue = EigenPodManager(address(eigenPodManager)).maxPods(); - cheats.expectEmit(true, true, true, true, address(eigenPodManager)); - emit MaxPodsUpdated(previousValue, newValue); - EigenPodManager(address(eigenPodManager)).setMaxPods(newValue); - cheats.stopPrank(); - - require(EigenPodManager(address(eigenPodManager)).maxPods() == newValue, "maxPods value not set correctly"); - } - - function test_setMaxPods_RevertsWhenNotCalledByUnpauser(address notUnpauser) public fuzzedAddress(notUnpauser) { - cheats.assume(notUnpauser != unpauser); - uint256 newValue = 0; - cheats.startPrank(notUnpauser); - cheats.expectRevert("msg.sender is not permissioned as unpauser"); - EigenPodManager(address(eigenPodManager)).setMaxPods(newValue); - cheats.stopPrank(); - } - function test_validatorPubkeyToInfo() external { bytes memory _pubkey = hex"93a0dd04ccddf3f1b419fdebf99481a2182c17d67cf14d32d6e50fc4bf8effc8db4a04b7c2f3a5975c1b9b74e2841888"; diff --git a/src/test/events/IEigenPodManagerEvents.sol b/src/test/events/IEigenPodManagerEvents.sol index 2f97966848..d974ce2c94 100644 --- a/src/test/events/IEigenPodManagerEvents.sol +++ b/src/test/events/IEigenPodManagerEvents.sol @@ -8,13 +8,9 @@ interface IEigenPodManagerEvents { /// @notice Emitted to notify that the denebForkTimestamp has been set event DenebForkTimestampUpdated(uint64 denebForkTimestamp); - /// @notice Emitted to notify the deployment of an EigenPod event PodDeployed(address indexed eigenPod, address indexed podOwner); - /// @notice Emitted when `maxPods` value is updated from `previousValue` to `newValue` - event MaxPodsUpdated(uint256 previousValue, uint256 newValue); - /// @notice Emitted when the balance of an EigenPod is updated event PodSharesUpdated(address indexed podOwner, int256 sharesDelta); } \ No newline at end of file diff --git a/src/test/integration/IntegrationDeployer.t.sol b/src/test/integration/IntegrationDeployer.t.sol index 0687a7089f..1be9fdf81a 100644 --- a/src/test/integration/IntegrationDeployer.t.sol +++ b/src/test/integration/IntegrationDeployer.t.sol @@ -235,7 +235,6 @@ abstract contract IntegrationDeployer is Test, IUserDeployer { address(eigenPodManagerImplementation), abi.encodeWithSelector( EigenPodManager.initialize.selector, - type(uint).max, // maxPods address(beaconChainOracle), eigenLayerReputedMultisig, // initialOwner pauserRegistry, diff --git a/src/test/mocks/EigenPodManagerMock.sol b/src/test/mocks/EigenPodManagerMock.sol index e3c2f0e17a..96da69030b 100644 --- a/src/test/mocks/EigenPodManagerMock.sol +++ b/src/test/mocks/EigenPodManagerMock.sol @@ -84,9 +84,6 @@ contract EigenPodManagerMock is IEigenPodManager, Test { function numPods() external view returns (uint256) {} - function maxPods() external view returns (uint256) {} - - function denebForkTimestamp() external pure returns (uint64) { return type(uint64).max; } diff --git a/src/test/tree/EigenPodManagerUnit.tree b/src/test/tree/EigenPodManagerUnit.tree index c8807c2be3..b09fdad3f9 100644 --- a/src/test/tree/EigenPodManagerUnit.tree +++ b/src/test/tree/EigenPodManagerUnit.tree @@ -6,8 +6,6 @@ ├── when createPod called │ ├── given the user has already created a pod │ │ └── it should revert -│ ├── given that the max number of pods has been deployed -│ │ └── it should revert │ └── given the user has not created a pod │ └── it should deploy a pod ├── when stake is called @@ -15,11 +13,6 @@ │ │ └── it should deploy a pod │ └── given the user has already created a pod │ └── it should call stake on the eigenPod -├── when setMaxPods is called -│ ├── given the user is not the pauser -│ │ └── it should revert -│ └── given the user is the pauser -│ └── it should set the max pods ├── when updateBeaconChainOracle is called │ ├── given the user is not the owner │ │ └── it should revert diff --git a/src/test/unit/EigenPod-PodManagerUnit.t.sol b/src/test/unit/EigenPod-PodManagerUnit.t.sol index 7aae852b6d..b0507257b0 100644 --- a/src/test/unit/EigenPod-PodManagerUnit.t.sol +++ b/src/test/unit/EigenPod-PodManagerUnit.t.sol @@ -85,7 +85,6 @@ contract EigenPod_PodManager_UnitTests is EigenLayerUnitTestSetup { address(eigenPodManagerWrapper), abi.encodeWithSelector( EigenPodManager.initialize.selector, - type(uint256).max /*maxPods*/, beaconChainOracle, initialOwner, pauserRegistry, @@ -228,9 +227,7 @@ contract EigenPod_PodManager_UnitTests_EigenPod is EigenPod_PodManager_UnitTests function test_stake_podAlreadyDeployed(bytes memory signature, bytes32 depositDataRoot) public { uint256 stakeAmount = 32e18; - uint256 maxPods = eigenPodManager.maxPods(); uint256 numPods = eigenPodManager.numPods(); - emit log_named_uint("maxPods", maxPods); emit log_named_uint("numPods", numPods); cheats.startPrank(podOwner); diff --git a/src/test/unit/EigenPodManagerUnit.t.sol b/src/test/unit/EigenPodManagerUnit.t.sol index 9e0e3fc3f2..f88697273c 100644 --- a/src/test/unit/EigenPodManagerUnit.t.sol +++ b/src/test/unit/EigenPodManagerUnit.t.sol @@ -53,7 +53,6 @@ contract EigenPodManagerUnitTests is EigenLayerUnitTestSetup { address(eigenLayerProxyAdmin), abi.encodeWithSelector( EigenPodManager.initialize.selector, - type(uint256).max /*maxPods*/, IBeaconChainOracle(address(0)) /*beaconChainOracle*/, initialOwner, pauserRegistry, @@ -111,7 +110,6 @@ contract EigenPodManagerUnitTests_Initialization_Setters is EigenPodManagerUnitT function test_initialization() public { // Check max pods, beacon chain, owner, and pauser - assertEq(eigenPodManager.maxPods(), type(uint256).max, "Initialization: max pods incorrect"); assertEq(address(eigenPodManager.beaconChainOracle()), address(IBeaconChainOracle(address(0))), "Initialization: beacon chain oracle incorrect"); assertEq(eigenPodManager.owner(), initialOwner, "Initialization: owner incorrect"); assertEq(address(eigenPodManager.pauserRegistry()), address(pauserRegistry), "Initialization: pauser registry incorrect"); @@ -127,36 +125,17 @@ contract EigenPodManagerUnitTests_Initialization_Setters is EigenPodManagerUnitT function test_initialize_revert_alreadyInitialized() public { cheats.expectRevert("Initializable: contract is already initialized"); - eigenPodManager.initialize(type(uint256).max /*maxPods*/, + eigenPodManager.initialize( IBeaconChainOracle(address(0)) /*beaconChainOracle*/, initialOwner, pauserRegistry, 0 /*initialPausedStatus*/); } - function testFuzz_setMaxPods_revert_notUnpauser(address notUnpauser) public filterFuzzedAddressInputs(notUnpauser) { - cheats.assume(notUnpauser != unpauser); - cheats.prank(notUnpauser); - cheats.expectRevert("msg.sender is not permissioned as unpauser"); - eigenPodManager.setMaxPods(0); - } - /******************************************************************************* Setters *******************************************************************************/ - function test_setMaxPods() public { - // Set max pods - uint256 newMaxPods = 0; - cheats.expectEmit(true, true, true, true); - emit MaxPodsUpdated(eigenPodManager.maxPods(), newMaxPods); - cheats.prank(unpauser); - eigenPodManager.setMaxPods(newMaxPods); - - // Check storage update - assertEq(eigenPodManager.maxPods(), newMaxPods, "Max pods not updated"); - } - function testFuzz_updateBeaconChainOracle_revert_notOwner(address notOwner) public filterFuzzedAddressInputs(notOwner) { cheats.assume(notOwner != initialOwner); cheats.prank(notOwner); @@ -220,27 +199,6 @@ contract EigenPodManagerUnitTests_CreationTests is EigenPodManagerUnitTests, IEi cheats.expectRevert("EigenPodManager.createPod: Sender already has a pod"); eigenPodManager.createPod(); } - - function test_createPod_revert_maxPodsUint256() public { - // Write numPods into storage. Num pods is at slot 153 - bytes32 slot = bytes32(uint256(153)); - bytes32 value = bytes32(eigenPodManager.maxPods()); - cheats.store(address(eigenPodManager), slot, value); - - // Expect revert on pod creation - cheats.expectRevert(); // Arithmetic overflow/underflow - eigenPodManager.createPod(); - } - - function test_createPod_revert_maxPodsNontUint256() public { - // Set max pods to a small value - 0 - cheats.prank(unpauser); - eigenPodManager.setMaxPods(0); - - // Expect revert on pod creation - cheats.expectRevert("EigenPodManager._deployPod: pod limit reached"); - eigenPodManager.createPod(); - } } contract EigenPodManagerUnitTests_StakeTests is EigenPodManagerUnitTests { From 20acb92bd6d964a03b759d357428784c496ce174 Mon Sep 17 00:00:00 2001 From: 8sunyuan Date: Mon, 11 Mar 2024 21:14:02 -0400 Subject: [PATCH 07/13] script: parser script helpers --- .env.example | 1 + ...M2_deploy_from_scratch.holesky.config.json | 52 +++ .../holesky/M2_Deploy_From_Scratch.s.sol | 27 ++ script/utils/ExistingDeploymentParser.sol | 438 +++++++++++++++++- 4 files changed, 501 insertions(+), 17 deletions(-) create mode 100644 script/configs/holesky/M2_deploy_from_scratch.holesky.config.json create mode 100644 script/deploy/holesky/M2_Deploy_From_Scratch.s.sol diff --git a/.env.example b/.env.example index 8985dacc60..948f166c8b 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,5 @@ RPC_MAINNET="https://eth.llamarpc.com" # RPC_MAINNET="https://mainnet.infura.io/v3/API-KEY" RPC_GOERLI="https://ethereum-goerli.publicnode.com" +RPC_HOLESKY="" ETHERSCAN_API_KEY="API-KEY" diff --git a/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json b/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json new file mode 100644 index 0000000000..4f8f8772a6 --- /dev/null +++ b/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json @@ -0,0 +1,52 @@ +{ + "chainInfo": { + "chainId": 17000 + }, + "multisig_addresses": { + "pauserMultisig": "0x53410249ec7d3a3F9F1ba3912D50D6A3Df6d10A7", + "communityMultisig": "0xCb8d2f9e55Bc7B1FA9d089f9aC80C583D2BDD5F7", + "operationsMultisig": "0xfaEF7338b7490b9E272d80A1a39f4657cAf2b97d", + "executorMultisig": "0x28Ade60640fdBDb2609D8d8734D1b5cBeFc0C348", + "timelock": "0xcF19CE0561052a7A7Ff21156730285997B350A7D" + }, + "strategies": [ + { + "token_address": "0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034", + "token_name": "Liquid staked Ether 2.0", + "token_symbol": "stETH" + }, + { + "token_address": "0x7322c24752f79c05FFD1E2a6FCB97020C1C264F1", + "token_name": "Rocket Pool ETH", + "token_symbol": "rETH" + } + ], + "strategyManager": { + "init_strategy_whitelister": "", + "init_paused_status": 0 + }, + "delegationManager": { + "init_paused_status": 0, + "init_minWithdrawalDelayBlocks": 50400 + }, + "avsDirectory": { + "init_paused_status": 0 + }, + "slasher": { + "init_paused_status": 0 + }, + "eigenPod": { + "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": 32000000000000000000, + "GENESIS_TIME": 1695902400 + }, + "eigenPodManager": { + "init_paused_status": 0, + "beaconOracleContract": "0x4C116BB629bff7A8373c2378bBd919f8349B8f25" + }, + "delayedWithdrawalRouter": { + "init_paused_status": 0, + "init_withdrawalDelayBlocks": 50400 + }, + "ethPOSDepositAddress": "0x4242424242424242424242424242424242424242", + "beaconOracleAddress": "0x4C116BB629bff7A8373c2378bBd919f8349B8f25" +} \ No newline at end of file diff --git a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol new file mode 100644 index 0000000000..05392888ea --- /dev/null +++ b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity =0.8.12; + +import "../../utils/ExistingDeploymentParser.sol"; + +contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { + function run() external { + _parseInitialDeploymentParams("script/configs/holesky/M2_deploy_from_scratch.holesky.config.json"); + + // // START RECORDING TRANSACTIONS FOR DEPLOYMENT + // vm.startBroadcast(); + // _deployFromScratch(); + + // // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + // vm.stopBroadcast(); + + // Sanity Checks + _verifyContractPointers(); + _verifyImplementations(); + _verifyContractsInitialized({isInitialDeployment: true}); + _verifyInitializationParams(); + + logContractAddresses(); + } + + function _deployFromScratch() internal {} +} diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol index 8d2544b265..3ad9bb75de 100644 --- a/script/utils/ExistingDeploymentParser.sol +++ b/script/utils/ExistingDeploymentParser.sol @@ -11,6 +11,7 @@ import "../../src/contracts/core/DelegationManager.sol"; import "../../src/contracts/core/AVSDirectory.sol"; import "../../src/contracts/strategies/StrategyBase.sol"; +import "../../src/contracts/strategies/StrategyBaseTVLLimits.sol"; import "../../src/contracts/pods/EigenPod.sol"; import "../../src/contracts/pods/EigenPodManager.sol"; @@ -24,7 +25,6 @@ import "forge-std/Script.sol"; import "forge-std/Test.sol"; contract ExistingDeploymentParser is Script, Test { - // EigenLayer Contracts ProxyAdmin public eigenLayerProxyAdmin; PauserRegistry public eigenLayerPauserReg; @@ -32,14 +32,15 @@ contract ExistingDeploymentParser is Script, Test { Slasher public slasherImplementation; AVSDirectory public avsDirectory; AVSDirectory public avsDirectoryImplementation; - DelegationManager public delegation; - DelegationManager public delegationImplementation; + DelegationManager public delegationManager; + DelegationManager public delegationManagerImplementation; StrategyManager public strategyManager; StrategyManager public strategyManagerImplementation; EigenPodManager public eigenPodManager; EigenPodManager public eigenPodManagerImplementation; DelayedWithdrawalRouter public delayedWithdrawalRouter; DelayedWithdrawalRouter public delayedWithdrawalRouterImplementation; + IBeaconChainOracle beaconOracle; UpgradeableBeacon public eigenPodBeacon; EigenPod public eigenPodImplementation; StrategyBase public baseStrategyImplementation; @@ -48,10 +49,42 @@ contract ExistingDeploymentParser is Script, Test { address executorMultisig; address operationsMultisig; + address communityMultisig; + address pauserMultisig; // strategies deployed StrategyBase[] public deployedStrategyArray; + // the ETH2 deposit contract -- if not on mainnet, we deploy a mock as stand-in + IETHPOSDeposit public ethPOSDeposit; + + // // IMMUTABLES TO SET + // uint64 MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR; + // uint64 GOERLI_GENESIS_TIME = 1616508000; + + /// @notice Initialization Params for first initial deployment scripts + // StrategyManager + uint256 STRATEGY_MANAGER_INIT_PAUSED_STATUS; + // SLasher + uint256 SLASHER_INIT_PAUSED_STATUS; + // DelegationManager + uint256 DELEGATION_MANAGER_INIT_PAUSED_STATUS; + uint256 DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS; + // AVSDirectory + uint256 AVS_DIRECTORY_INIT_PAUSED_STATUS; + // EigenPodManager + uint256 EIGENPOD_MANAGER_INIT_PAUSED_STATUS; + uint256 EIGENPOD_MANAGER_MAX_PODS; + // EigenPod + uint64 EIGENPOD_GENESIS_TIME; + uint64 EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR; + address ETHPOSDepositAddress; + uint256 DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS; + + // one week in blocks -- 50400 + uint32 DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS; + + /// @notice use for parsing already deployed EigenLayer contracts function _parseDeployedContracts(string memory existingDeploymentInfoPath) internal { // read and log the chainID uint256 currentChainId = block.chainid; @@ -67,25 +100,51 @@ contract ExistingDeploymentParser is Script, Test { // read all of the deployed addresses executorMultisig = stdJson.readAddress(existingDeploymentData, ".parameters.executorMultisig"); operationsMultisig = stdJson.readAddress(existingDeploymentData, ".parameters.operationsMultisig"); - - eigenLayerProxyAdmin = ProxyAdmin(stdJson.readAddress(existingDeploymentData, ".addresses.eigenLayerProxyAdmin")); - eigenLayerPauserReg = PauserRegistry(stdJson.readAddress(existingDeploymentData, ".addresses.eigenLayerPauserReg")); + communityMultisig = stdJson.readAddress(existingDeploymentData, ".parameters.communityMultisig"); + pauserMultisig = stdJson.readAddress(existingDeploymentData, ".parameters.pauserMultisig"); + + eigenLayerProxyAdmin = ProxyAdmin( + stdJson.readAddress(existingDeploymentData, ".addresses.eigenLayerProxyAdmin") + ); + eigenLayerPauserReg = PauserRegistry( + stdJson.readAddress(existingDeploymentData, ".addresses.eigenLayerPauserReg") + ); slasher = Slasher(stdJson.readAddress(existingDeploymentData, ".addresses.slasher")); - slasherImplementation = Slasher(stdJson.readAddress(existingDeploymentData, ".addresses.slasherImplementation")); - delegation = DelegationManager(stdJson.readAddress(existingDeploymentData, ".addresses.delegation")); - delegationImplementation = DelegationManager(stdJson.readAddress(existingDeploymentData, ".addresses.delegationImplementation")); + slasherImplementation = Slasher( + stdJson.readAddress(existingDeploymentData, ".addresses.slasherImplementation") + ); + delegationManager = DelegationManager(stdJson.readAddress(existingDeploymentData, ".addresses.delegation")); + delegationManagerImplementation = DelegationManager( + stdJson.readAddress(existingDeploymentData, ".addresses.delegationImplementation") + ); avsDirectory = AVSDirectory(stdJson.readAddress(existingDeploymentData, ".addresses.avsDirectory")); - avsDirectoryImplementation = AVSDirectory(stdJson.readAddress(existingDeploymentData, ".addresses.avsDirectoryImplementation")); + avsDirectoryImplementation = AVSDirectory( + stdJson.readAddress(existingDeploymentData, ".addresses.avsDirectoryImplementation") + ); strategyManager = StrategyManager(stdJson.readAddress(existingDeploymentData, ".addresses.strategyManager")); - strategyManagerImplementation = StrategyManager(stdJson.readAddress(existingDeploymentData, ".addresses.strategyManagerImplementation")); + strategyManagerImplementation = StrategyManager( + stdJson.readAddress(existingDeploymentData, ".addresses.strategyManagerImplementation") + ); eigenPodManager = EigenPodManager(stdJson.readAddress(existingDeploymentData, ".addresses.eigenPodManager")); - eigenPodManagerImplementation = EigenPodManager(stdJson.readAddress(existingDeploymentData, ".addresses.eigenPodManagerImplementation")); - delayedWithdrawalRouter = DelayedWithdrawalRouter(stdJson.readAddress(existingDeploymentData, ".addresses.delayedWithdrawalRouter")); - delayedWithdrawalRouterImplementation = - DelayedWithdrawalRouter(stdJson.readAddress(existingDeploymentData, ".addresses.delayedWithdrawalRouterImplementation")); + eigenPodManagerImplementation = EigenPodManager( + stdJson.readAddress(existingDeploymentData, ".addresses.eigenPodManagerImplementation") + ); + delayedWithdrawalRouter = DelayedWithdrawalRouter( + stdJson.readAddress(existingDeploymentData, ".addresses.delayedWithdrawalRouter") + ); + delayedWithdrawalRouterImplementation = DelayedWithdrawalRouter( + stdJson.readAddress(existingDeploymentData, ".addresses.delayedWithdrawalRouterImplementation") + ); + beaconOracle = IBeaconChainOracle( + stdJson.readAddress(existingDeploymentData, ".addresses.beaconOracleAddress") + ); eigenPodBeacon = UpgradeableBeacon(stdJson.readAddress(existingDeploymentData, ".addresses.eigenPodBeacon")); - eigenPodImplementation = EigenPod(payable(stdJson.readAddress(existingDeploymentData, ".addresses.eigenPodImplementation"))); - baseStrategyImplementation = StrategyBase(stdJson.readAddress(existingDeploymentData, ".addresses.baseStrategyImplementation")); + eigenPodImplementation = EigenPod( + payable(stdJson.readAddress(existingDeploymentData, ".addresses.eigenPodImplementation")) + ); + baseStrategyImplementation = StrategyBase( + stdJson.readAddress(existingDeploymentData, ".addresses.baseStrategyImplementation") + ); emptyContract = EmptyContract(stdJson.readAddress(existingDeploymentData, ".addresses.emptyContract")); /* @@ -103,4 +162,349 @@ contract ExistingDeploymentParser is Script, Test { } */ } + + /// @notice use for deploying a new set of EigenLayer contracts + /// Note that this does require multisigs to already be deployed + function _parseInitialDeploymentParams(string memory initialDeploymentParamsPath) internal { + // read and log the chainID + uint256 currentChainId = block.chainid; + emit log_named_uint("You are parsing on ChainID", currentChainId); + + // READ JSON CONFIG DATA + string memory initialDeploymentData = vm.readFile(initialDeploymentParamsPath); + + // check that the chainID matches the one in the config + uint256 configChainId = stdJson.readUint(initialDeploymentData, ".chainInfo.chainId"); + require(configChainId == currentChainId, "You are on the wrong chain for this config"); + + // read beacon oracle + beaconOracle = IBeaconChainOracle(stdJson.readAddress(initialDeploymentData, ".addresses.beaconOracleAddress")); + + // read all of the deployed addresses + executorMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.executorMultisig"); + operationsMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.operationsMultisig"); + communityMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.communityMultisig"); + pauserMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.pauserMultisig"); + + // Read initialize params for upgradeable contracts + STRATEGY_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint( + initialDeploymentData, + ".strategyManager.init_paused_status" + ); + SLASHER_INIT_PAUSED_STATUS = stdJson.readUint(initialDeploymentData, ".slasher.init_paused_status"); + // DelegationManager + DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS = stdJson.readUint( + initialDeploymentData, + ".delegationManager.init_minWithdrawalDelayBlocks" + ); + DELEGATION_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint( + initialDeploymentData, + ".delegationManager.init_paused_status" + ); + // AVSDirectory + AVS_DIRECTORY_INIT_PAUSED_STATUS = stdJson.readUint(initialDeploymentData, ".avsDirectory.init_paused_status"); + // EigenPodManager + EIGENPOD_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint( + initialDeploymentData, + ".eigenPodManager.init_paused_status" + ); + + // EigenPod + EIGENPOD_GENESIS_TIME = uint64(stdJson.readUint(initialDeploymentData, ".eigenPod.GENESIS_TIME")); + EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR = uint64( + stdJson.readUint(initialDeploymentData, ".eigenPod.MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR") + ); + ETHPOSDepositAddress = stdJson.readAddress(initialDeploymentData, ".ethPOSDepositAddress"); + // DelayedWithdrawalRouter + DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS = stdJson.readUint( + initialDeploymentData, + ".delayedWithdrawalRouter.init_paused_status" + ); + + // both set to one week in blocks 50400 + DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS = uint32( + stdJson.readUint(initialDeploymentData, ".delayedWithdrawalRouter.init_withdrawalDelayBlocks") + ); + + logInitialDeploymentParams(); + } + + /// @notice Ensure contracts point at each other correctly via constructors + function _verifyContractPointers() internal view { + // AVSDirectory + require( + avsDirectory.delegation() == delegationManager, + "avsDirectory: delegationManager address not set correctly" + ); + // DelegationManager + require(delegationManager.slasher() == slasher, "delegationManager: slasher address not set correctly"); + require( + delegationManager.strategyManager() == strategyManager, + "delegationManager: strategyManager address not set correctly" + ); + require( + delegationManager.eigenPodManager() == eigenPodManager, + "delegationManager: eigenPodManager address not set correctly" + ); + // StrategyManager + require(strategyManager.slasher() == slasher, "strategyManager: slasher address not set correctly"); + require( + strategyManager.delegation() == delegationManager, + "strategyManager: delegationManager address not set correctly" + ); + require( + strategyManager.eigenPodManager() == eigenPodManager, + "strategyManager: eigenPodManager address not set correctly" + ); + // EPM + require( + address(eigenPodManager.ethPOS()) == ETHPOSDepositAddress, + "eigenPodManager: ethPOSDeposit contract address not set correctly" + ); + require( + eigenPodManager.eigenPodBeacon() == eigenPodBeacon, + "eigenPodManager: eigenPodBeacon contract address not set correctly" + ); + require( + eigenPodManager.strategyManager() == strategyManager, + "eigenPodManager: strategyManager contract address not set correctly" + ); + require(eigenPodManager.slasher() == slasher, "eigenPodManager: slasher contract address not set correctly"); + require( + eigenPodManager.delegationManager() == delegationManager, + "eigenPodManager: delegationManager contract address not set correctly" + ); + // DelayedWithdrawalRouter + require( + delayedWithdrawalRouter.eigenPodManager() == eigenPodManager, + "delayedWithdrawalRouterContract: eigenPodManager address not set correctly" + ); + } + + /// @notice verify implementations for Transparent Upgradeable Proxies + function _verifyImplementations() internal view { + require( + eigenLayerProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(avsDirectory)))) == + address(avsDirectoryImplementation), + "avsDirectory: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + TransparentUpgradeableProxy(payable(address(delegationManager))) + ) == address(delegationManagerImplementation), + "delegationManager: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + TransparentUpgradeableProxy(payable(address(strategyManager))) + ) == address(strategyManagerImplementation), + "strategyManager: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(slasher)))) == + address(slasherImplementation), + "slasher: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + TransparentUpgradeableProxy(payable(address(eigenPodManager))) + ) == address(eigenPodManagerImplementation), + "eigenPodManager: implementation set incorrectly" + ); + require( + eigenLayerProxyAdmin.getProxyImplementation( + TransparentUpgradeableProxy(payable(address(delayedWithdrawalRouter))) + ) == address(delayedWithdrawalRouterImplementation), + "delayedWithdrawalRouter: implementation set incorrectly" + ); + + for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { + require( + eigenLayerProxyAdmin.getProxyImplementation( + TransparentUpgradeableProxy(payable(address(deployedStrategyArray[i]))) + ) == address(baseStrategyImplementation), + "strategy: implementation set incorrectly" + ); + } + + require( + eigenPodBeacon.implementation() == address(eigenPodImplementation), + "eigenPodBeacon: implementation set incorrectly" + ); + } + + /** + * @notice Verify initialization of Transparent Upgradeable Proxies. Also check + * initialization params if this is the first deployment. + * @param isInitialDeployment True if this is the first deployment of contracts from scratch + */ + function _verifyContractsInitialized(bool isInitialDeployment) internal { + // AVSDirectory + vm.expectRevert(bytes("Initializable: contract is already initialized")); + avsDirectory.initialize(address(0), eigenLayerPauserReg, AVS_DIRECTORY_INIT_PAUSED_STATUS); + // DelegationManager + vm.expectRevert(bytes("Initializable: contract is already initialized")); + IStrategy[] memory initializeStrategiesToSetDelayBlocks = new IStrategy[](0); + uint256[] memory initializeWithdrawalDelayBlocks = new uint256[](0); + delegationManager.initialize( + address(0), + eigenLayerPauserReg, + 0, + 0, // minWithdrawalDelayBLocks + initializeStrategiesToSetDelayBlocks, + initializeWithdrawalDelayBlocks + ); + // StrategyManager + vm.expectRevert(bytes("Initializable: contract is already initialized")); + strategyManager.initialize(address(0), address(0), eigenLayerPauserReg, STRATEGY_MANAGER_INIT_PAUSED_STATUS); + // EigenPodManager + vm.expectRevert(bytes("Initializable: contract is already initialized")); + eigenPodManager.initialize( + EIGENPOD_MANAGER_MAX_PODS, + beaconOracle, + address(0), + eigenLayerPauserReg, + EIGENPOD_MANAGER_INIT_PAUSED_STATUS + ); + // DelayedWithdrawalRouter + vm.expectRevert(bytes("Initializable: contract is already initialized")); + delayedWithdrawalRouter.initialize( + address(0), + eigenLayerPauserReg, + DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS, + DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS + ); + // Strategies + for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { + vm.expectRevert(bytes("Initializable: contract is already initialized")); + StrategyBaseTVLLimits(address(deployedStrategyArray[i])).initialize( + 0, + 0, + IERC20(address(0)), + eigenLayerPauserReg + ); + } + } + + /// @notice Verify params based on config constants that are updated from calling `_parseInitialDeploymentParams` + function _verifyInitializationParams() internal { + // AVSDirectory + require( + avsDirectory.pauserRegistry() == eigenLayerPauserReg, + "avsdirectory: pauser registry not set correctly" + ); + require(avsDirectory.owner() == executorMultisig, "avsdirectory: owner not set correctly"); + require( + avsDirectory.paused() == AVS_DIRECTORY_INIT_PAUSED_STATUS, + "avsdirectory: init paused status set incorrectly" + ); + // DelegationManager + require( + delegationManager.pauserRegistry() == eigenLayerPauserReg, + "delegationManager: pauser registry not set correctly" + ); + require(delegationManager.owner() == executorMultisig, "delegationManager: owner not set correctly"); + require( + delegationManager.paused() == DELEGATION_MANAGER_INIT_PAUSED_STATUS, + "delegationManager: init paused status set incorrectly" + ); + require( + delegationManager.minWithdrawalDelayBlocks() == DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS, + "delegationManager: minWithdrawalDelayBlocks not set correctly" + ); + // StrategyManager + require( + strategyManager.pauserRegistry() == eigenLayerPauserReg, + "strategyManager: pauser registry not set correctly" + ); + require(strategyManager.owner() == executorMultisig, "strategyManager: owner not set correctly"); + require( + strategyManager.paused() == STRATEGY_MANAGER_INIT_PAUSED_STATUS, + "strategyManager: init paused status set incorrectly" + ); + // EigenPodManager + require( + eigenPodManager.pauserRegistry() == eigenLayerPauserReg, + "eigenPodManager: pauser registry not set correctly" + ); + require(eigenPodManager.owner() == executorMultisig, "eigenPodManager: owner not set correctly"); + require( + eigenPodManager.paused() == EIGENPOD_MANAGER_INIT_PAUSED_STATUS, + "eigenPodManager: init paused status set incorrectly" + ); + // EigenPodBeacon + require(eigenPodBeacon.owner() == executorMultisig, "eigenPodBeacon: owner not set correctly"); + // DelayedWithdrawalRouter + require( + delayedWithdrawalRouter.pauserRegistry() == eigenLayerPauserReg, + "delayedWithdrawalRouter: pauser registry not set correctly" + ); + require( + delayedWithdrawalRouter.owner() == executorMultisig, + "delayedWithdrawalRouter: owner not set correctly" + ); + require( + delayedWithdrawalRouter.paused() == DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS, + "delayedWithdrawalRouter: init paused status set incorrectly" + ); + require( + delayedWithdrawalRouter.withdrawalDelayBlocks() == DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS, + "delayedWithdrawalRouter: withdrawalDelayBlocks not set correctly" + ); + // Strategies + for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { + require( + deployedStrategyArray[i].pauserRegistry() == eigenLayerPauserReg, + "StrategyBaseTVLLimits: pauser registry not set correctly" + ); + require( + deployedStrategyArray[i].paused() == 0, + "StrategyBaseTVLLimits: init paused status set incorrectly" + ); + } + + // Pausing Permissions + require(eigenLayerPauserReg.isPauser(operationsMultisig), "pauserRegistry: operationsMultisig is not pauser"); + require(eigenLayerPauserReg.isPauser(executorMultisig), "pauserRegistry: executorMultisig is not pauser"); + require(eigenLayerPauserReg.isPauser(pauserMultisig), "pauserRegistry: pauserMultisig is not pauser"); + require(eigenLayerPauserReg.unpauser() == executorMultisig, "pauserRegistry: unpauser not set correctly"); + } + + function logInitialDeploymentParams() public { + emit log_string("==== Parsed Initilize Params for Initial Deployment ===="); + + emit log_named_address("executorMultisig", executorMultisig); + emit log_named_address("operationsMultisig", operationsMultisig); + emit log_named_address("communityMultisig", communityMultisig); + emit log_named_address("pauserMultisig", pauserMultisig); + + emit log_named_uint("STRATEGY_MANAGER_INIT_PAUSED_STATUS", STRATEGY_MANAGER_INIT_PAUSED_STATUS); + emit log_named_uint("SLASHER_INIT_PAUSED_STATUS", SLASHER_INIT_PAUSED_STATUS); + emit log_named_uint( + "DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS", + DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS + ); + emit log_named_uint("DELEGATION_MANAGER_INIT_PAUSED_STATUS", DELEGATION_MANAGER_INIT_PAUSED_STATUS); + emit log_named_uint("AVS_DIRECTORY_INIT_PAUSED_STATUS", AVS_DIRECTORY_INIT_PAUSED_STATUS); + emit log_named_uint("EIGENPOD_MANAGER_INIT_PAUSED_STATUS", EIGENPOD_MANAGER_INIT_PAUSED_STATUS); + emit log_named_uint("EIGENPOD_MANAGER_MAX_PODS", EIGENPOD_MANAGER_MAX_PODS); + emit log_named_uint("EIGENPOD_GENESIS_TIME", EIGENPOD_GENESIS_TIME); + emit log_named_uint( + "EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR", + EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR + ); + emit log_named_address("ETHPOSDepositAddress", ETHPOSDepositAddress); + emit log_named_uint( + "DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS", + DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS + ); + emit log_named_uint( + "DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS", + DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS + ); + } + + function logContractAddresses() public { + emit log_string("==== Contract Addresses from Deployment/Upgrade ===="); + } } From 2a91496cb065eec87c58f96c02b7d795724dead5 Mon Sep 17 00:00:00 2001 From: 8sunyuan Date: Tue, 12 Mar 2024 12:14:05 -0400 Subject: [PATCH 08/13] feat: holesky deploy scripts --- ...M2_deploy_from_scratch.holesky.config.json | 32 +-- .../holesky/M2_Deploy_From_Scratch.s.sol | 194 +++++++++++++++++- script/utils/ExistingDeploymentParser.sol | 132 +++++++++++- 3 files changed, 333 insertions(+), 25 deletions(-) diff --git a/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json b/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json index 4f8f8772a6..8fef056a6a 100644 --- a/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json +++ b/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json @@ -9,18 +9,24 @@ "executorMultisig": "0x28Ade60640fdBDb2609D8d8734D1b5cBeFc0C348", "timelock": "0xcF19CE0561052a7A7Ff21156730285997B350A7D" }, - "strategies": [ - { - "token_address": "0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034", - "token_name": "Liquid staked Ether 2.0", - "token_symbol": "stETH" - }, - { - "token_address": "0x7322c24752f79c05FFD1E2a6FCB97020C1C264F1", - "token_name": "Rocket Pool ETH", - "token_symbol": "rETH" - } - ], + "numStrategies": 2, + "strategies": { + "numStrategies": 2, + "MAX_PER_DEPOSIT": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "MAX_TOTAL_DEPOSITS": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "strategiesToDeploy": [ + { + "token_address": "0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034", + "token_name": "Liquid staked Ether 2.0", + "token_symbol": "stETH" + }, + { + "token_address": "0x7322c24752f79c05FFD1E2a6FCB97020C1C264F1", + "token_name": "Rocket Pool ETH", + "token_symbol": "rETH" + } + ] + }, "strategyManager": { "init_strategy_whitelister": "", "init_paused_status": 0 @@ -41,7 +47,7 @@ }, "eigenPodManager": { "init_paused_status": 0, - "beaconOracleContract": "0x4C116BB629bff7A8373c2378bBd919f8349B8f25" + "deneb_fork_timestamp": "1707323664" }, "delayedWithdrawalRouter": { "init_paused_status": 0, diff --git a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol index 05392888ea..4878f2bd95 100644 --- a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol +++ b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol @@ -3,16 +3,25 @@ pragma solidity =0.8.12; import "../../utils/ExistingDeploymentParser.sol"; +/** + * @notice Script used for the first deployment of EigenLayer core contracts to Holesky + * forge script script/deploy/holesky/M2_Deploy_From_Scratch.s.sol --rpc-url http://127.0.0.1:8545 --private-key $PRIVATE_KEY --broadcast -vvvv + * forge script script/deploy/holesky/M2_Deploy_From_Scratch.s.sol --rpc-url $RPC_HOLESKY --private-key $PRIVATE_KEY --broadcast -vvvv + * + */ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { function run() external { _parseInitialDeploymentParams("script/configs/holesky/M2_deploy_from_scratch.holesky.config.json"); - // // START RECORDING TRANSACTIONS FOR DEPLOYMENT - // vm.startBroadcast(); - // _deployFromScratch(); + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); - // // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT - // vm.stopBroadcast(); + emit log_named_address("Deployer Address", msg.sender); + + _deployFromScratch(); + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); // Sanity Checks _verifyContractPointers(); @@ -20,8 +29,179 @@ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { _verifyContractsInitialized({isInitialDeployment: true}); _verifyInitializationParams(); - logContractAddresses(); + logAndOutputContractAddresses("script/output/holesky/M2_deploy_from_scratch.holesky.config.json"); } - function _deployFromScratch() internal {} + /** + * @notice Deploy EigenLayer contracts from scratch for Holesky + */ + function _deployFromScratch() internal { + // Deploy ProxyAdmin, later set admins for all proxies to be executorMultisig + eigenLayerProxyAdmin = new ProxyAdmin(); + + // Set multisigs as pausers, executorMultisig as unpauser + address[] memory pausers = new address[](3); + pausers[0] = executorMultisig; + pausers[1] = operationsMultisig; + pausers[2] = pauserMultisig; + address unpauser = executorMultisig; + eigenLayerPauserReg = new PauserRegistry(pausers, unpauser); + + /** + * 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(); + avsDirectory = AVSDirectory( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + delegationManager = DelegationManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + strategyManager = StrategyManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + slasher = Slasher( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + eigenPodManager = EigenPodManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + delayedWithdrawalRouter = DelayedWithdrawalRouter( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + + // Deploy EigenPod Contracts + eigenPodImplementation = new EigenPod( + IETHPOSDeposit(ETHPOSDepositAddress), + delayedWithdrawalRouter, + eigenPodManager, + EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR, + EIGENPOD_GENESIS_TIME + ); + + eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); + avsDirectoryImplementation = new AVSDirectory(delegationManager); + delegationManagerImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); + strategyManagerImplementation = new StrategyManager(delegationManager, eigenPodManager, slasher); + slasherImplementation = new Slasher(strategyManager, delegationManager); + eigenPodManagerImplementation = new EigenPodManager( + IETHPOSDeposit(ETHPOSDepositAddress), + eigenPodBeacon, + strategyManager, + slasher, + delegationManager + ); + delayedWithdrawalRouterImplementation = new DelayedWithdrawalRouter(eigenPodManager); + + // Third, upgrade the proxy contracts to point to the implementations + IStrategy[] memory initializeStrategiesToSetDelayBlocks = new IStrategy[](0); + uint256[] memory initializeWithdrawalDelayBlocks = new uint256[](0); + // AVSDirectory + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(avsDirectory))), + address(avsDirectoryImplementation), + abi.encodeWithSelector( + AVSDirectory.initialize.selector, + executorMultisig, // initialOwner + eigenLayerPauserReg, + AVS_DIRECTORY_INIT_PAUSED_STATUS + ) + ); + // DelegationManager + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(delegationManager))), + address(delegationManagerImplementation), + abi.encodeWithSelector( + DelegationManager.initialize.selector, + executorMultisig, // initialOwner + eigenLayerPauserReg, + DELEGATION_MANAGER_INIT_PAUSED_STATUS, + DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS, + initializeStrategiesToSetDelayBlocks, + initializeWithdrawalDelayBlocks + ) + ); + // StrategyManager + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(strategyManager))), + address(strategyManagerImplementation), + abi.encodeWithSelector( + StrategyManager.initialize.selector, + executorMultisig, //initialOwner + executorMultisig, //initial whitelister + eigenLayerPauserReg, + STRATEGY_MANAGER_INIT_PAUSED_STATUS + ) + ); + // Slasher + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(slasher))), + address(slasherImplementation), + abi.encodeWithSelector( + Slasher.initialize.selector, + executorMultisig, + eigenLayerPauserReg, + SLASHER_INIT_PAUSED_STATUS + ) + ); + // EigenPodManager + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(eigenPodManager))), + address(eigenPodManagerImplementation), + abi.encodeWithSelector( + EigenPodManager.initialize.selector, + type(uint).max, // maxPods + beaconOracle, + msg.sender, // initialOwner is msg.sender for now to set forktimestamp later + eigenLayerPauserReg, + EIGENPOD_MANAGER_INIT_PAUSED_STATUS + ) + ); + // Delayed Withdrawal Router + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(delayedWithdrawalRouter))), + address(delayedWithdrawalRouterImplementation), + abi.encodeWithSelector( + DelayedWithdrawalRouter.initialize.selector, + executorMultisig, // initialOwner + eigenLayerPauserReg, + DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS, + DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS + ) + ); + + // Deploy Strategies + baseStrategyImplementation = new StrategyBaseTVLLimits(strategyManager); + uint256 numStrategiesToDeploy = strategiesToDeploy.length; + for (uint256 i = 0; i < numStrategiesToDeploy; i++) { + StrategyUnderlyingTokenConfig memory strategyConfig = strategiesToDeploy[i]; + + // Deploy and upgrade strategy + StrategyBaseTVLLimits strategy = StrategyBaseTVLLimits( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(strategy))), + address(baseStrategyImplementation), + abi.encodeWithSelector( + StrategyBaseTVLLimits.initialize.selector, + STRATEGY_MAX_PER_DEPOSIT, + STRATEGY_MAX_TOTAL_DEPOSITS, + IERC20(strategyConfig.tokenAddress), + eigenLayerPauserReg + ) + ); + + deployedStrategyArray.push(strategy); + } + + // Fork timestamp config + eigenPodManager.setDenebForkTimestamp(EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP); + + // Transfer ownership + eigenLayerProxyAdmin.transferOwnership(executorMultisig); + eigenPodManager.transferOwnership(executorMultisig); + eigenPodBeacon.transferOwnership(executorMultisig); + } } diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol index 3ad9bb75de..e25d11d1bf 100644 --- a/script/utils/ExistingDeploymentParser.sol +++ b/script/utils/ExistingDeploymentParser.sol @@ -24,6 +24,12 @@ import "../../src/test/mocks/EmptyContract.sol"; import "forge-std/Script.sol"; import "forge-std/Test.sol"; +struct StrategyUnderlyingTokenConfig { + address tokenAddress; + string tokenName; + string tokenSymbol; +} + contract ExistingDeploymentParser is Script, Test { // EigenLayer Contracts ProxyAdmin public eigenLayerProxyAdmin; @@ -54,9 +60,12 @@ contract ExistingDeploymentParser is Script, Test { // strategies deployed StrategyBase[] public deployedStrategyArray; + // Strategies to Deploy + uint256 numStrategiesToDeploy; + StrategyUnderlyingTokenConfig[] public strategiesToDeploy; // the ETH2 deposit contract -- if not on mainnet, we deploy a mock as stand-in - IETHPOSDeposit public ethPOSDeposit; + // IETHPOSDeposit public ethPOSDeposit; // // IMMUTABLES TO SET // uint64 MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR; @@ -75,6 +84,7 @@ contract ExistingDeploymentParser is Script, Test { // EigenPodManager uint256 EIGENPOD_MANAGER_INIT_PAUSED_STATUS; uint256 EIGENPOD_MANAGER_MAX_PODS; + uint64 EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP; // EigenPod uint64 EIGENPOD_GENESIS_TIME; uint64 EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR; @@ -84,6 +94,10 @@ contract ExistingDeploymentParser is Script, Test { // one week in blocks -- 50400 uint32 DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS; + // Strategy Deployment + uint256 STRATEGY_MAX_PER_DEPOSIT; + uint256 STRATEGY_MAX_TOTAL_DEPOSITS; + /// @notice use for parsing already deployed EigenLayer contracts function _parseDeployedContracts(string memory existingDeploymentInfoPath) internal { // read and log the chainID @@ -178,7 +192,7 @@ contract ExistingDeploymentParser is Script, Test { require(configChainId == currentChainId, "You are on the wrong chain for this config"); // read beacon oracle - beaconOracle = IBeaconChainOracle(stdJson.readAddress(initialDeploymentData, ".addresses.beaconOracleAddress")); + beaconOracle = IBeaconChainOracle(stdJson.readAddress(initialDeploymentData, ".beaconOracleAddress")); // read all of the deployed addresses executorMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.executorMultisig"); @@ -186,6 +200,26 @@ contract ExistingDeploymentParser is Script, Test { communityMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.communityMultisig"); pauserMultisig = stdJson.readAddress(initialDeploymentData, ".multisig_addresses.pauserMultisig"); + // Strategies to Deploy, load strategy list + numStrategiesToDeploy = stdJson.readUint(initialDeploymentData, ".strategies.numStrategies"); + STRATEGY_MAX_PER_DEPOSIT = stdJson.readUint(initialDeploymentData, ".strategies.MAX_PER_DEPOSIT"); + STRATEGY_MAX_TOTAL_DEPOSITS = stdJson.readUint(initialDeploymentData, ".strategies.MAX_TOTAL_DEPOSITS"); + for (uint256 i = 0; i < numStrategiesToDeploy; ++i) { + // Form the key for the current element + string memory key = string.concat(".strategies.strategiesToDeploy[", vm.toString(i), "]"); + + // Use parseJson with the key to get the value for the current element + bytes memory tokenInfoBytes = stdJson.parseRaw(initialDeploymentData, key); + + // Decode the token information into the Token struct + StrategyUnderlyingTokenConfig memory tokenInfo = abi.decode( + tokenInfoBytes, + (StrategyUnderlyingTokenConfig) + ); + + strategiesToDeploy.push(tokenInfo); + } + // Read initialize params for upgradeable contracts STRATEGY_MANAGER_INIT_PAUSED_STATUS = stdJson.readUint( initialDeploymentData, @@ -208,6 +242,10 @@ contract ExistingDeploymentParser is Script, Test { initialDeploymentData, ".eigenPodManager.init_paused_status" ); + EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP = uint64(stdJson.readUint( + initialDeploymentData, + ".eigenPodManager.deneb_fork_timestamp" + )); // EigenPod EIGENPOD_GENESIS_TIME = uint64(stdJson.readUint(initialDeploymentData, ".eigenPod.GENESIS_TIME")); @@ -487,7 +525,7 @@ contract ExistingDeploymentParser is Script, Test { emit log_named_uint("DELEGATION_MANAGER_INIT_PAUSED_STATUS", DELEGATION_MANAGER_INIT_PAUSED_STATUS); emit log_named_uint("AVS_DIRECTORY_INIT_PAUSED_STATUS", AVS_DIRECTORY_INIT_PAUSED_STATUS); emit log_named_uint("EIGENPOD_MANAGER_INIT_PAUSED_STATUS", EIGENPOD_MANAGER_INIT_PAUSED_STATUS); - emit log_named_uint("EIGENPOD_MANAGER_MAX_PODS", EIGENPOD_MANAGER_MAX_PODS); + emit log_named_uint("EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP", EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP); emit log_named_uint("EIGENPOD_GENESIS_TIME", EIGENPOD_GENESIS_TIME); emit log_named_uint( "EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR", @@ -502,9 +540,93 @@ contract ExistingDeploymentParser is Script, Test { "DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS", DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS ); + + emit log_string("==== Strategies to Deploy ===="); + for (uint256 i = 0; i < numStrategiesToDeploy; ++i) { + // Decode the token information into the Token struct + StrategyUnderlyingTokenConfig memory tokenInfo = strategiesToDeploy[i]; + + strategiesToDeploy.push(tokenInfo); + emit log_named_address("TOKEN ADDRESS", tokenInfo.tokenAddress); + emit log_named_string("TOKEN NAME", tokenInfo.tokenName); + emit log_named_string("TOKEN SYMBOL", tokenInfo.tokenSymbol); + } } - function logContractAddresses() public { - emit log_string("==== Contract Addresses from Deployment/Upgrade ===="); + /** + * @notice Log contract addresses and write to output json file + */ + function logAndOutputContractAddresses(string memory outputPath) public { + // WRITE JSON DATA + string memory parent_object = "parent object"; + + string memory deployed_strategies = "strategies"; + for (uint256 i = 0; i < numStrategiesToDeploy; ++i) { + vm.serializeAddress(deployed_strategies, strategiesToDeploy[i].tokenSymbol, address(deployedStrategyArray[i])); + } + string memory deployed_strategies_output = numStrategiesToDeploy == 0 + ? "" + : vm.serializeAddress( + deployed_strategies, + strategiesToDeploy[numStrategiesToDeploy - 1].tokenSymbol, + address(deployedStrategyArray[numStrategiesToDeploy - 1]) + ); + + 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, "avsDirectory", address(avsDirectory)); + vm.serializeAddress(deployed_addresses, "avsDirectoryImplementation", address(avsDirectoryImplementation)); + vm.serializeAddress(deployed_addresses, "delegationManager", address(delegationManager)); + vm.serializeAddress(deployed_addresses, "delegationManagerImplementation", address(delegationManagerImplementation)); + vm.serializeAddress(deployed_addresses, "strategyManager", address(strategyManager)); + vm.serializeAddress( + deployed_addresses, + "strategyManagerImplementation", + address(strategyManagerImplementation) + ); + vm.serializeAddress(deployed_addresses, "eigenPodManager", address(eigenPodManager)); + vm.serializeAddress( + deployed_addresses, + "eigenPodManagerImplementation", + address(eigenPodManagerImplementation) + ); + vm.serializeAddress(deployed_addresses, "delayedWithdrawalRouter", address(delayedWithdrawalRouter)); + vm.serializeAddress( + deployed_addresses, + "delayedWithdrawalRouterImplementation", + address(delayedWithdrawalRouterImplementation) + ); + vm.serializeAddress(deployed_addresses, "beaconOracle", address(beaconOracle)); + 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); + vm.serializeAddress(parameters, "operationsMultisig", operationsMultisig); + vm.serializeAddress(parameters, "communityMultisig", communityMultisig); + vm.serializeAddress(parameters, "pauserMultisig", pauserMultisig); + 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", block.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); + + vm.writeJson(finalJson, outputPath); + } } From b8d08818e173b2a7ba745f0c9679d5975fc59e25 Mon Sep 17 00:00:00 2001 From: 8sunyuan Date: Tue, 12 Mar 2024 14:35:05 -0400 Subject: [PATCH 09/13] fix: config --- .../holesky/M2_deploy_from_scratch.holesky.config.json | 4 ++-- script/utils/ExistingDeploymentParser.sol | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json b/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json index 8fef056a6a..d143bf043c 100644 --- a/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json +++ b/script/configs/holesky/M2_deploy_from_scratch.holesky.config.json @@ -28,7 +28,7 @@ ] }, "strategyManager": { - "init_strategy_whitelister": "", + "init_strategy_whitelister": "0xfaEF7338b7490b9E272d80A1a39f4657cAf2b97d", "init_paused_status": 0 }, "delegationManager": { @@ -47,7 +47,7 @@ }, "eigenPodManager": { "init_paused_status": 0, - "deneb_fork_timestamp": "1707323664" + "deneb_fork_timestamp": "1707305664" }, "delayedWithdrawalRouter": { "init_paused_status": 0, diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol index e25d11d1bf..bc86b86bf3 100644 --- a/script/utils/ExistingDeploymentParser.sol +++ b/script/utils/ExistingDeploymentParser.sol @@ -460,6 +460,10 @@ contract ExistingDeploymentParser is Script, Test { strategyManager.paused() == STRATEGY_MANAGER_INIT_PAUSED_STATUS, "strategyManager: init paused status set incorrectly" ); + require( + strategyManager.strategyWhitelister() == operationsMultisig, + "strategyManager: strategyWhitelister not set correctly" + ); // EigenPodManager require( eigenPodManager.pauserRegistry() == eigenLayerPauserReg, From 13706a0ddeac6dc8434bc44389de695836dcd8ca Mon Sep 17 00:00:00 2001 From: 8sunyuan Date: Tue, 12 Mar 2024 16:12:32 -0400 Subject: [PATCH 10/13] fix: ops multisig whitelister --- script/deploy/holesky/M2_Deploy_From_Scratch.s.sol | 2 +- script/utils/ExistingDeploymentParser.sol | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol index 4878f2bd95..29369cffd6 100644 --- a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol +++ b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol @@ -129,7 +129,7 @@ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { abi.encodeWithSelector( StrategyManager.initialize.selector, executorMultisig, //initialOwner - executorMultisig, //initial whitelister + STRATEGY_MANAGER_WHITELISTER, //initial whitelister eigenLayerPauserReg, STRATEGY_MANAGER_INIT_PAUSED_STATUS ) diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol index bc86b86bf3..87b7264922 100644 --- a/script/utils/ExistingDeploymentParser.sol +++ b/script/utils/ExistingDeploymentParser.sol @@ -74,6 +74,7 @@ contract ExistingDeploymentParser is Script, Test { /// @notice Initialization Params for first initial deployment scripts // StrategyManager uint256 STRATEGY_MANAGER_INIT_PAUSED_STATUS; + uint256 STRATEGY_MANAGER_WHITELISTER; // SLasher uint256 SLASHER_INIT_PAUSED_STATUS; // DelegationManager @@ -225,6 +226,8 @@ contract ExistingDeploymentParser is Script, Test { initialDeploymentData, ".strategyManager.init_paused_status" ); + STRATEGY_MANAGER_WHITELISTER = stdJson.readUint(initialDeploymentData, ".strategyManager.init_strategy_whitelister"); + // Slasher SLASHER_INIT_PAUSED_STATUS = stdJson.readUint(initialDeploymentData, ".slasher.init_paused_status"); // DelegationManager DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS = stdJson.readUint( @@ -521,6 +524,7 @@ contract ExistingDeploymentParser is Script, Test { emit log_named_address("pauserMultisig", pauserMultisig); emit log_named_uint("STRATEGY_MANAGER_INIT_PAUSED_STATUS", STRATEGY_MANAGER_INIT_PAUSED_STATUS); + emit log_named_uint("STRATEGY_MANAGER_WHITELISTER", STRATEGY_MANAGER_WHITELISTER); emit log_named_uint("SLASHER_INIT_PAUSED_STATUS", SLASHER_INIT_PAUSED_STATUS); emit log_named_uint( "DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS", From 5a024563499e996f593680183e5024e7b1d68f7d Mon Sep 17 00:00:00 2001 From: 8sunyuan Date: Wed, 13 Mar 2024 12:25:54 -0400 Subject: [PATCH 11/13] refactor: maxpods removal --- script/deploy/holesky/M2_Deploy_From_Scratch.s.sol | 1 - script/utils/ExistingDeploymentParser.sol | 4 +--- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol index 29369cffd6..6d844c37f4 100644 --- a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol +++ b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol @@ -151,7 +151,6 @@ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { address(eigenPodManagerImplementation), abi.encodeWithSelector( EigenPodManager.initialize.selector, - type(uint).max, // maxPods beaconOracle, msg.sender, // initialOwner is msg.sender for now to set forktimestamp later eigenLayerPauserReg, diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol index 87b7264922..232360de84 100644 --- a/script/utils/ExistingDeploymentParser.sol +++ b/script/utils/ExistingDeploymentParser.sol @@ -84,7 +84,6 @@ contract ExistingDeploymentParser is Script, Test { uint256 AVS_DIRECTORY_INIT_PAUSED_STATUS; // EigenPodManager uint256 EIGENPOD_MANAGER_INIT_PAUSED_STATUS; - uint256 EIGENPOD_MANAGER_MAX_PODS; uint64 EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP; // EigenPod uint64 EIGENPOD_GENESIS_TIME; @@ -401,7 +400,6 @@ contract ExistingDeploymentParser is Script, Test { // EigenPodManager vm.expectRevert(bytes("Initializable: contract is already initialized")); eigenPodManager.initialize( - EIGENPOD_MANAGER_MAX_PODS, beaconOracle, address(0), eigenLayerPauserReg, @@ -428,7 +426,7 @@ contract ExistingDeploymentParser is Script, Test { } /// @notice Verify params based on config constants that are updated from calling `_parseInitialDeploymentParams` - function _verifyInitializationParams() internal { + function _verifyInitializationParams() internal view { // AVSDirectory require( avsDirectory.pauserRegistry() == eigenLayerPauserReg, From af354270a6acdc83efa8ad2f986d7d08e5e799b8 Mon Sep 17 00:00:00 2001 From: 8sunyuan Date: Wed, 13 Mar 2024 13:50:33 -0400 Subject: [PATCH 12/13] feat: preprod deployment --- .../M2_deploy_preprod.holesky.config.json | 58 ++++ script/deploy/holesky/M2_Deploy_Preprod.s.sol | 295 ++++++++++++++++++ script/utils/ExistingDeploymentParser.sol | 12 +- 3 files changed, 359 insertions(+), 6 deletions(-) create mode 100644 script/configs/holesky/M2_deploy_preprod.holesky.config.json create mode 100644 script/deploy/holesky/M2_Deploy_Preprod.s.sol diff --git a/script/configs/holesky/M2_deploy_preprod.holesky.config.json b/script/configs/holesky/M2_deploy_preprod.holesky.config.json new file mode 100644 index 0000000000..469ef613ec --- /dev/null +++ b/script/configs/holesky/M2_deploy_preprod.holesky.config.json @@ -0,0 +1,58 @@ +{ + "chainInfo": { + "chainId": 17000 + }, + "multisig_addresses": { + "pauserMultisig": "0x0000000000000000000000000000000000000000", + "communityMultisig": "0x0000000000000000000000000000000000000000", + "operationsMultisig": "0x0000000000000000000000000000000000000000", + "executorMultisig": "0x0000000000000000000000000000000000000000", + "timelock": "0x0000000000000000000000000000000000000000" + }, + "numStrategies": 2, + "strategies": { + "numStrategies": 2, + "MAX_PER_DEPOSIT": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "MAX_TOTAL_DEPOSITS": 115792089237316195423570985008687907853269984665640564039457584007913129639935, + "strategiesToDeploy": [ + { + "token_address": "0x3F1c547b21f65e10480dE3ad8E19fAAC46C95034", + "token_name": "Liquid staked Ether 2.0", + "token_symbol": "stETH" + }, + { + "token_address": "0x7322c24752f79c05FFD1E2a6FCB97020C1C264F1", + "token_name": "Rocket Pool ETH", + "token_symbol": "rETH" + } + ] + }, + "strategyManager": { + "init_strategy_whitelister": "0x0000000000000000000000000000000000000000", + "init_paused_status": 0 + }, + "delegationManager": { + "init_paused_status": 0, + "init_minWithdrawalDelayBlocks": 50400 + }, + "avsDirectory": { + "init_paused_status": 0 + }, + "slasher": { + "init_paused_status": 0 + }, + "eigenPod": { + "MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": 32000000000000000000, + "GENESIS_TIME": 1695902400 + }, + "eigenPodManager": { + "init_paused_status": 0, + "deneb_fork_timestamp": "1707305664" + }, + "delayedWithdrawalRouter": { + "init_paused_status": 0, + "init_withdrawalDelayBlocks": 50400 + }, + "ethPOSDepositAddress": "0x4242424242424242424242424242424242424242", + "beaconOracleAddress": "0x4C116BB629bff7A8373c2378bBd919f8349B8f25" +} \ No newline at end of file diff --git a/script/deploy/holesky/M2_Deploy_Preprod.s.sol b/script/deploy/holesky/M2_Deploy_Preprod.s.sol new file mode 100644 index 0000000000..b156cbc8c3 --- /dev/null +++ b/script/deploy/holesky/M2_Deploy_Preprod.s.sol @@ -0,0 +1,295 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity =0.8.12; + +import "../../utils/ExistingDeploymentParser.sol"; + +/** + * @notice Script used for the first deployment of EigenLayer core contracts to Holesky + * forge script script/deploy/holesky/M2_Deploy_Preprod.s.sol --rpc-url http://127.0.0.1:8545 --private-key $PRIVATE_KEY --broadcast -vvvv + * forge script script/deploy/holesky/M2_Deploy_Preprod.s.sol --rpc-url $RPC_HOLESKY --private-key $PRIVATE_KEY --broadcast -vvvv + * + * Script for dev environment, exact same as M2_Deploy_From_Scratch.s.sol but with an EOAowner + * instead of multisig addresses for permissions. + * Unused config fields: + * - init_strategy_whitelister + * - multisig_addresses(operations, pauser, executor, community) + */ +contract M2_Deploy_Holesky_Preprod is ExistingDeploymentParser { + /// @dev EOAowner is the deployer and owner of the contracts + address EOAowner; + + function run() external { + _parseInitialDeploymentParams("script/configs/holesky/M2_deploy_preprod.holesky.config.json"); + + EOAowner = msg.sender; + + // START RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.startBroadcast(); + + emit log_named_address("Deployer and EOAowner Address", EOAowner); + + _deployFromScratch(); + + // STOP RECORDING TRANSACTIONS FOR DEPLOYMENT + vm.stopBroadcast(); + + // Sanity Checks + _verifyContractPointers(); + _verifyImplementations(); + _verifyContractsInitialized({isInitialDeployment: true}); + _verifyInitializationParams(); // override to check contract.owner() is EOAowner instead + + logAndOutputContractAddresses("script/output/holesky/M2_deploy_preprod.holesky.config.json"); + } + + /** + * @notice Deploy EigenLayer contracts from scratch for Holesky + */ + function _deployFromScratch() internal { + // Deploy ProxyAdmin, later set admins for all proxies to be EOAowner + eigenLayerProxyAdmin = new ProxyAdmin(); + + // Set EOAowners as pausers and unpauser + address[] memory pausers = new address[](1); + pausers[0] = EOAowner; + address unpauser = EOAowner; + eigenLayerPauserReg = new PauserRegistry(pausers, unpauser); + + /** + * 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(); + avsDirectory = AVSDirectory( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + delegationManager = DelegationManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + strategyManager = StrategyManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + slasher = Slasher( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + eigenPodManager = EigenPodManager( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + delayedWithdrawalRouter = DelayedWithdrawalRouter( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + + // Deploy EigenPod Contracts + eigenPodImplementation = new EigenPod( + IETHPOSDeposit(ETHPOSDepositAddress), + delayedWithdrawalRouter, + eigenPodManager, + EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR, + EIGENPOD_GENESIS_TIME + ); + + eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); + avsDirectoryImplementation = new AVSDirectory(delegationManager); + delegationManagerImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); + strategyManagerImplementation = new StrategyManager(delegationManager, eigenPodManager, slasher); + slasherImplementation = new Slasher(strategyManager, delegationManager); + eigenPodManagerImplementation = new EigenPodManager( + IETHPOSDeposit(ETHPOSDepositAddress), + eigenPodBeacon, + strategyManager, + slasher, + delegationManager + ); + delayedWithdrawalRouterImplementation = new DelayedWithdrawalRouter(eigenPodManager); + + // Third, upgrade the proxy contracts to point to the implementations + IStrategy[] memory initializeStrategiesToSetDelayBlocks = new IStrategy[](0); + uint256[] memory initializeWithdrawalDelayBlocks = new uint256[](0); + // AVSDirectory + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(avsDirectory))), + address(avsDirectoryImplementation), + abi.encodeWithSelector( + AVSDirectory.initialize.selector, + EOAowner, // initialOwner + eigenLayerPauserReg, + AVS_DIRECTORY_INIT_PAUSED_STATUS + ) + ); + // DelegationManager + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(delegationManager))), + address(delegationManagerImplementation), + abi.encodeWithSelector( + DelegationManager.initialize.selector, + EOAowner, // initialOwner + eigenLayerPauserReg, + DELEGATION_MANAGER_INIT_PAUSED_STATUS, + DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS, + initializeStrategiesToSetDelayBlocks, + initializeWithdrawalDelayBlocks + ) + ); + // StrategyManager + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(strategyManager))), + address(strategyManagerImplementation), + abi.encodeWithSelector( + StrategyManager.initialize.selector, + EOAowner, //initialOwner + EOAowner, //initial whitelister + eigenLayerPauserReg, + STRATEGY_MANAGER_INIT_PAUSED_STATUS + ) + ); + // Slasher + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(slasher))), + address(slasherImplementation), + abi.encodeWithSelector( + Slasher.initialize.selector, + EOAowner, + eigenLayerPauserReg, + SLASHER_INIT_PAUSED_STATUS + ) + ); + // EigenPodManager + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(eigenPodManager))), + address(eigenPodManagerImplementation), + abi.encodeWithSelector( + EigenPodManager.initialize.selector, + beaconOracle, + EOAowner, + eigenLayerPauserReg, + EIGENPOD_MANAGER_INIT_PAUSED_STATUS + ) + ); + // Delayed Withdrawal Router + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(delayedWithdrawalRouter))), + address(delayedWithdrawalRouterImplementation), + abi.encodeWithSelector( + DelayedWithdrawalRouter.initialize.selector, + EOAowner, // initialOwner + eigenLayerPauserReg, + DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS, + DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS + ) + ); + + // Deploy Strategies + baseStrategyImplementation = new StrategyBaseTVLLimits(strategyManager); + uint256 numStrategiesToDeploy = strategiesToDeploy.length; + for (uint256 i = 0; i < numStrategiesToDeploy; i++) { + StrategyUnderlyingTokenConfig memory strategyConfig = strategiesToDeploy[i]; + + // Deploy and upgrade strategy + StrategyBaseTVLLimits strategy = StrategyBaseTVLLimits( + address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) + ); + eigenLayerProxyAdmin.upgradeAndCall( + TransparentUpgradeableProxy(payable(address(strategy))), + address(baseStrategyImplementation), + abi.encodeWithSelector( + StrategyBaseTVLLimits.initialize.selector, + STRATEGY_MAX_PER_DEPOSIT, + STRATEGY_MAX_TOTAL_DEPOSITS, + IERC20(strategyConfig.tokenAddress), + eigenLayerPauserReg + ) + ); + + deployedStrategyArray.push(strategy); + } + + // Fork timestamp config + eigenPodManager.setDenebForkTimestamp(EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP); + + // Transfer ownership + eigenLayerProxyAdmin.transferOwnership(EOAowner); + eigenPodBeacon.transferOwnership(EOAowner); + } + + function _verifyInitializationParams() internal view override { + // AVSDirectory + require( + avsDirectory.pauserRegistry() == eigenLayerPauserReg, + "avsdirectory: pauser registry not set correctly" + ); + require(avsDirectory.owner() == EOAowner, "avsdirectory: owner not set correctly"); + require( + avsDirectory.paused() == AVS_DIRECTORY_INIT_PAUSED_STATUS, + "avsdirectory: init paused status set incorrectly" + ); + // DelegationManager + require( + delegationManager.pauserRegistry() == eigenLayerPauserReg, + "delegationManager: pauser registry not set correctly" + ); + require(delegationManager.owner() == EOAowner, "delegationManager: owner not set correctly"); + require( + delegationManager.paused() == DELEGATION_MANAGER_INIT_PAUSED_STATUS, + "delegationManager: init paused status set incorrectly" + ); + require( + delegationManager.minWithdrawalDelayBlocks() == DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS, + "delegationManager: minWithdrawalDelayBlocks not set correctly" + ); + // StrategyManager + require( + strategyManager.pauserRegistry() == eigenLayerPauserReg, + "strategyManager: pauser registry not set correctly" + ); + require(strategyManager.owner() == EOAowner, "strategyManager: owner not set correctly"); + require( + strategyManager.paused() == STRATEGY_MANAGER_INIT_PAUSED_STATUS, + "strategyManager: init paused status set incorrectly" + ); + require( + strategyManager.strategyWhitelister() == EOAowner, + "strategyManager: strategyWhitelister not set correctly" + ); + // EigenPodManager + require( + eigenPodManager.pauserRegistry() == eigenLayerPauserReg, + "eigenPodManager: pauser registry not set correctly" + ); + require(eigenPodManager.owner() == EOAowner, "eigenPodManager: owner not set correctly"); + require( + eigenPodManager.paused() == EIGENPOD_MANAGER_INIT_PAUSED_STATUS, + "eigenPodManager: init paused status set incorrectly" + ); + // EigenPodBeacon + require(eigenPodBeacon.owner() == EOAowner, "eigenPodBeacon: owner not set correctly"); + // DelayedWithdrawalRouter + require( + delayedWithdrawalRouter.pauserRegistry() == eigenLayerPauserReg, + "delayedWithdrawalRouter: pauser registry not set correctly" + ); + require(delayedWithdrawalRouter.owner() == EOAowner, "delayedWithdrawalRouter: owner not set correctly"); + require( + delayedWithdrawalRouter.paused() == DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS, + "delayedWithdrawalRouter: init paused status set incorrectly" + ); + require( + delayedWithdrawalRouter.withdrawalDelayBlocks() == DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS, + "delayedWithdrawalRouter: withdrawalDelayBlocks not set correctly" + ); + // Strategies + for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { + require( + deployedStrategyArray[i].pauserRegistry() == eigenLayerPauserReg, + "StrategyBaseTVLLimits: pauser registry not set correctly" + ); + require( + deployedStrategyArray[i].paused() == 0, + "StrategyBaseTVLLimits: init paused status set incorrectly" + ); + } + + // Pausing Permissions + require(eigenLayerPauserReg.isPauser(EOAowner), "pauserRegistry: EOAowner is not pauser"); + require(eigenLayerPauserReg.unpauser() == EOAowner, "pauserRegistry: unpauser not set correctly"); + } +} diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol index 232360de84..c89e149838 100644 --- a/script/utils/ExistingDeploymentParser.sol +++ b/script/utils/ExistingDeploymentParser.sol @@ -99,7 +99,7 @@ contract ExistingDeploymentParser is Script, Test { uint256 STRATEGY_MAX_TOTAL_DEPOSITS; /// @notice use for parsing already deployed EigenLayer contracts - function _parseDeployedContracts(string memory existingDeploymentInfoPath) internal { + function _parseDeployedContracts(string memory existingDeploymentInfoPath) internal virtual { // read and log the chainID uint256 currentChainId = block.chainid; emit log_named_uint("You are parsing on ChainID", currentChainId); @@ -179,7 +179,7 @@ contract ExistingDeploymentParser is Script, Test { /// @notice use for deploying a new set of EigenLayer contracts /// Note that this does require multisigs to already be deployed - function _parseInitialDeploymentParams(string memory initialDeploymentParamsPath) internal { + function _parseInitialDeploymentParams(string memory initialDeploymentParamsPath) internal virtual { // read and log the chainID uint256 currentChainId = block.chainid; emit log_named_uint("You are parsing on ChainID", currentChainId); @@ -270,7 +270,7 @@ contract ExistingDeploymentParser is Script, Test { } /// @notice Ensure contracts point at each other correctly via constructors - function _verifyContractPointers() internal view { + function _verifyContractPointers() internal virtual view { // AVSDirectory require( avsDirectory.delegation() == delegationManager, @@ -322,7 +322,7 @@ contract ExistingDeploymentParser is Script, Test { } /// @notice verify implementations for Transparent Upgradeable Proxies - function _verifyImplementations() internal view { + function _verifyImplementations() internal virtual view { require( eigenLayerProxyAdmin.getProxyImplementation(TransparentUpgradeableProxy(payable(address(avsDirectory)))) == address(avsDirectoryImplementation), @@ -378,7 +378,7 @@ contract ExistingDeploymentParser is Script, Test { * initialization params if this is the first deployment. * @param isInitialDeployment True if this is the first deployment of contracts from scratch */ - function _verifyContractsInitialized(bool isInitialDeployment) internal { + function _verifyContractsInitialized(bool isInitialDeployment) internal virtual{ // AVSDirectory vm.expectRevert(bytes("Initializable: contract is already initialized")); avsDirectory.initialize(address(0), eigenLayerPauserReg, AVS_DIRECTORY_INIT_PAUSED_STATUS); @@ -426,7 +426,7 @@ contract ExistingDeploymentParser is Script, Test { } /// @notice Verify params based on config constants that are updated from calling `_parseInitialDeploymentParams` - function _verifyInitializationParams() internal view { + function _verifyInitializationParams() internal virtual view { // AVSDirectory require( avsDirectory.pauserRegistry() == eigenLayerPauserReg, From fa80340e78d1913896bfedcd715439a09960c86a Mon Sep 17 00:00:00 2001 From: 8sunyuan Date: Wed, 13 Mar 2024 15:30:07 -0400 Subject: [PATCH 13/13] refactor: reuse other script --- .../holesky/M2_Deploy_From_Scratch.s.sol | 2 +- script/deploy/holesky/M2_Deploy_Preprod.s.sol | 263 +----------------- script/utils/ExistingDeploymentParser.sol | 6 +- 3 files changed, 13 insertions(+), 258 deletions(-) diff --git a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol index 6d844c37f4..0105406fc8 100644 --- a/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol +++ b/script/deploy/holesky/M2_Deploy_From_Scratch.s.sol @@ -10,7 +10,7 @@ import "../../utils/ExistingDeploymentParser.sol"; * */ contract M2_Deploy_Holesky_From_Scratch is ExistingDeploymentParser { - function run() external { + function run() external virtual { _parseInitialDeploymentParams("script/configs/holesky/M2_deploy_from_scratch.holesky.config.json"); // START RECORDING TRANSACTIONS FOR DEPLOYMENT diff --git a/script/deploy/holesky/M2_Deploy_Preprod.s.sol b/script/deploy/holesky/M2_Deploy_Preprod.s.sol index b156cbc8c3..be27f3809a 100644 --- a/script/deploy/holesky/M2_Deploy_Preprod.s.sol +++ b/script/deploy/holesky/M2_Deploy_Preprod.s.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity =0.8.12; -import "../../utils/ExistingDeploymentParser.sol"; +import "./M2_Deploy_From_Scratch.s.sol"; /** * @notice Script used for the first deployment of EigenLayer core contracts to Holesky @@ -14,14 +14,20 @@ import "../../utils/ExistingDeploymentParser.sol"; * - init_strategy_whitelister * - multisig_addresses(operations, pauser, executor, community) */ -contract M2_Deploy_Holesky_Preprod is ExistingDeploymentParser { +contract M2_Deploy_Holesky_Preprod is M2_Deploy_Holesky_From_Scratch { /// @dev EOAowner is the deployer and owner of the contracts address EOAowner; - function run() external { + function run() external virtual override { _parseInitialDeploymentParams("script/configs/holesky/M2_deploy_preprod.holesky.config.json"); + // Overwrite multisig to be EOAowner EOAowner = msg.sender; + executorMultisig = EOAowner; + operationsMultisig = EOAowner; + pauserMultisig = EOAowner; + communityMultisig = EOAowner; + STRATEGY_MANAGER_WHITELISTER = EOAowner; // START RECORDING TRANSACTIONS FOR DEPLOYMENT vm.startBroadcast(); @@ -41,255 +47,4 @@ contract M2_Deploy_Holesky_Preprod is ExistingDeploymentParser { logAndOutputContractAddresses("script/output/holesky/M2_deploy_preprod.holesky.config.json"); } - - /** - * @notice Deploy EigenLayer contracts from scratch for Holesky - */ - function _deployFromScratch() internal { - // Deploy ProxyAdmin, later set admins for all proxies to be EOAowner - eigenLayerProxyAdmin = new ProxyAdmin(); - - // Set EOAowners as pausers and unpauser - address[] memory pausers = new address[](1); - pausers[0] = EOAowner; - address unpauser = EOAowner; - eigenLayerPauserReg = new PauserRegistry(pausers, unpauser); - - /** - * 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(); - avsDirectory = AVSDirectory( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - delegationManager = DelegationManager( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - strategyManager = StrategyManager( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - slasher = Slasher( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - eigenPodManager = EigenPodManager( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - delayedWithdrawalRouter = DelayedWithdrawalRouter( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - - // Deploy EigenPod Contracts - eigenPodImplementation = new EigenPod( - IETHPOSDeposit(ETHPOSDepositAddress), - delayedWithdrawalRouter, - eigenPodManager, - EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR, - EIGENPOD_GENESIS_TIME - ); - - eigenPodBeacon = new UpgradeableBeacon(address(eigenPodImplementation)); - avsDirectoryImplementation = new AVSDirectory(delegationManager); - delegationManagerImplementation = new DelegationManager(strategyManager, slasher, eigenPodManager); - strategyManagerImplementation = new StrategyManager(delegationManager, eigenPodManager, slasher); - slasherImplementation = new Slasher(strategyManager, delegationManager); - eigenPodManagerImplementation = new EigenPodManager( - IETHPOSDeposit(ETHPOSDepositAddress), - eigenPodBeacon, - strategyManager, - slasher, - delegationManager - ); - delayedWithdrawalRouterImplementation = new DelayedWithdrawalRouter(eigenPodManager); - - // Third, upgrade the proxy contracts to point to the implementations - IStrategy[] memory initializeStrategiesToSetDelayBlocks = new IStrategy[](0); - uint256[] memory initializeWithdrawalDelayBlocks = new uint256[](0); - // AVSDirectory - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(avsDirectory))), - address(avsDirectoryImplementation), - abi.encodeWithSelector( - AVSDirectory.initialize.selector, - EOAowner, // initialOwner - eigenLayerPauserReg, - AVS_DIRECTORY_INIT_PAUSED_STATUS - ) - ); - // DelegationManager - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(delegationManager))), - address(delegationManagerImplementation), - abi.encodeWithSelector( - DelegationManager.initialize.selector, - EOAowner, // initialOwner - eigenLayerPauserReg, - DELEGATION_MANAGER_INIT_PAUSED_STATUS, - DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS, - initializeStrategiesToSetDelayBlocks, - initializeWithdrawalDelayBlocks - ) - ); - // StrategyManager - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(strategyManager))), - address(strategyManagerImplementation), - abi.encodeWithSelector( - StrategyManager.initialize.selector, - EOAowner, //initialOwner - EOAowner, //initial whitelister - eigenLayerPauserReg, - STRATEGY_MANAGER_INIT_PAUSED_STATUS - ) - ); - // Slasher - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(slasher))), - address(slasherImplementation), - abi.encodeWithSelector( - Slasher.initialize.selector, - EOAowner, - eigenLayerPauserReg, - SLASHER_INIT_PAUSED_STATUS - ) - ); - // EigenPodManager - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(eigenPodManager))), - address(eigenPodManagerImplementation), - abi.encodeWithSelector( - EigenPodManager.initialize.selector, - beaconOracle, - EOAowner, - eigenLayerPauserReg, - EIGENPOD_MANAGER_INIT_PAUSED_STATUS - ) - ); - // Delayed Withdrawal Router - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(delayedWithdrawalRouter))), - address(delayedWithdrawalRouterImplementation), - abi.encodeWithSelector( - DelayedWithdrawalRouter.initialize.selector, - EOAowner, // initialOwner - eigenLayerPauserReg, - DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS, - DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS - ) - ); - - // Deploy Strategies - baseStrategyImplementation = new StrategyBaseTVLLimits(strategyManager); - uint256 numStrategiesToDeploy = strategiesToDeploy.length; - for (uint256 i = 0; i < numStrategiesToDeploy; i++) { - StrategyUnderlyingTokenConfig memory strategyConfig = strategiesToDeploy[i]; - - // Deploy and upgrade strategy - StrategyBaseTVLLimits strategy = StrategyBaseTVLLimits( - address(new TransparentUpgradeableProxy(address(emptyContract), address(eigenLayerProxyAdmin), "")) - ); - eigenLayerProxyAdmin.upgradeAndCall( - TransparentUpgradeableProxy(payable(address(strategy))), - address(baseStrategyImplementation), - abi.encodeWithSelector( - StrategyBaseTVLLimits.initialize.selector, - STRATEGY_MAX_PER_DEPOSIT, - STRATEGY_MAX_TOTAL_DEPOSITS, - IERC20(strategyConfig.tokenAddress), - eigenLayerPauserReg - ) - ); - - deployedStrategyArray.push(strategy); - } - - // Fork timestamp config - eigenPodManager.setDenebForkTimestamp(EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP); - - // Transfer ownership - eigenLayerProxyAdmin.transferOwnership(EOAowner); - eigenPodBeacon.transferOwnership(EOAowner); - } - - function _verifyInitializationParams() internal view override { - // AVSDirectory - require( - avsDirectory.pauserRegistry() == eigenLayerPauserReg, - "avsdirectory: pauser registry not set correctly" - ); - require(avsDirectory.owner() == EOAowner, "avsdirectory: owner not set correctly"); - require( - avsDirectory.paused() == AVS_DIRECTORY_INIT_PAUSED_STATUS, - "avsdirectory: init paused status set incorrectly" - ); - // DelegationManager - require( - delegationManager.pauserRegistry() == eigenLayerPauserReg, - "delegationManager: pauser registry not set correctly" - ); - require(delegationManager.owner() == EOAowner, "delegationManager: owner not set correctly"); - require( - delegationManager.paused() == DELEGATION_MANAGER_INIT_PAUSED_STATUS, - "delegationManager: init paused status set incorrectly" - ); - require( - delegationManager.minWithdrawalDelayBlocks() == DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS, - "delegationManager: minWithdrawalDelayBlocks not set correctly" - ); - // StrategyManager - require( - strategyManager.pauserRegistry() == eigenLayerPauserReg, - "strategyManager: pauser registry not set correctly" - ); - require(strategyManager.owner() == EOAowner, "strategyManager: owner not set correctly"); - require( - strategyManager.paused() == STRATEGY_MANAGER_INIT_PAUSED_STATUS, - "strategyManager: init paused status set incorrectly" - ); - require( - strategyManager.strategyWhitelister() == EOAowner, - "strategyManager: strategyWhitelister not set correctly" - ); - // EigenPodManager - require( - eigenPodManager.pauserRegistry() == eigenLayerPauserReg, - "eigenPodManager: pauser registry not set correctly" - ); - require(eigenPodManager.owner() == EOAowner, "eigenPodManager: owner not set correctly"); - require( - eigenPodManager.paused() == EIGENPOD_MANAGER_INIT_PAUSED_STATUS, - "eigenPodManager: init paused status set incorrectly" - ); - // EigenPodBeacon - require(eigenPodBeacon.owner() == EOAowner, "eigenPodBeacon: owner not set correctly"); - // DelayedWithdrawalRouter - require( - delayedWithdrawalRouter.pauserRegistry() == eigenLayerPauserReg, - "delayedWithdrawalRouter: pauser registry not set correctly" - ); - require(delayedWithdrawalRouter.owner() == EOAowner, "delayedWithdrawalRouter: owner not set correctly"); - require( - delayedWithdrawalRouter.paused() == DELAYED_WITHDRAWAL_ROUTER_INIT_PAUSED_STATUS, - "delayedWithdrawalRouter: init paused status set incorrectly" - ); - require( - delayedWithdrawalRouter.withdrawalDelayBlocks() == DELAYED_WITHDRAWAL_ROUTER_INIT_WITHDRAWAL_DELAY_BLOCKS, - "delayedWithdrawalRouter: withdrawalDelayBlocks not set correctly" - ); - // Strategies - for (uint256 i = 0; i < deployedStrategyArray.length; ++i) { - require( - deployedStrategyArray[i].pauserRegistry() == eigenLayerPauserReg, - "StrategyBaseTVLLimits: pauser registry not set correctly" - ); - require( - deployedStrategyArray[i].paused() == 0, - "StrategyBaseTVLLimits: init paused status set incorrectly" - ); - } - - // Pausing Permissions - require(eigenLayerPauserReg.isPauser(EOAowner), "pauserRegistry: EOAowner is not pauser"); - require(eigenLayerPauserReg.unpauser() == EOAowner, "pauserRegistry: unpauser not set correctly"); - } } diff --git a/script/utils/ExistingDeploymentParser.sol b/script/utils/ExistingDeploymentParser.sol index c89e149838..0338687189 100644 --- a/script/utils/ExistingDeploymentParser.sol +++ b/script/utils/ExistingDeploymentParser.sol @@ -74,7 +74,7 @@ contract ExistingDeploymentParser is Script, Test { /// @notice Initialization Params for first initial deployment scripts // StrategyManager uint256 STRATEGY_MANAGER_INIT_PAUSED_STATUS; - uint256 STRATEGY_MANAGER_WHITELISTER; + address STRATEGY_MANAGER_WHITELISTER; // SLasher uint256 SLASHER_INIT_PAUSED_STATUS; // DelegationManager @@ -225,7 +225,7 @@ contract ExistingDeploymentParser is Script, Test { initialDeploymentData, ".strategyManager.init_paused_status" ); - STRATEGY_MANAGER_WHITELISTER = stdJson.readUint(initialDeploymentData, ".strategyManager.init_strategy_whitelister"); + STRATEGY_MANAGER_WHITELISTER = stdJson.readAddress(initialDeploymentData, ".strategyManager.init_strategy_whitelister"); // Slasher SLASHER_INIT_PAUSED_STATUS = stdJson.readUint(initialDeploymentData, ".slasher.init_paused_status"); // DelegationManager @@ -522,7 +522,7 @@ contract ExistingDeploymentParser is Script, Test { emit log_named_address("pauserMultisig", pauserMultisig); emit log_named_uint("STRATEGY_MANAGER_INIT_PAUSED_STATUS", STRATEGY_MANAGER_INIT_PAUSED_STATUS); - emit log_named_uint("STRATEGY_MANAGER_WHITELISTER", STRATEGY_MANAGER_WHITELISTER); + emit log_named_address("STRATEGY_MANAGER_WHITELISTER", STRATEGY_MANAGER_WHITELISTER); emit log_named_uint("SLASHER_INIT_PAUSED_STATUS", SLASHER_INIT_PAUSED_STATUS); emit log_named_uint( "DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS",