Skip to content

Commit

Permalink
feat: m2 mainnet upgrade script (#480)
Browse files Browse the repository at this point in the history
* feat: m2-mainnet upgrade script

* chore: remove test output

* feat: add upgrade queue test (#481)

this commit also imports various tx-queuing-related utils

* feat: fix encoding & complete M2 upgrade queuing test

* chore: adjustments to ordering, use parsed address

* fix: correct genesis time

* fix: max restake gwei config

---------

Co-authored-by: ChaoticWalrus <[email protected]>
  • Loading branch information
8sunyuan and ChaoticWalrus authored Mar 22, 2024
1 parent b87095b commit 4b15d68
Show file tree
Hide file tree
Showing 8 changed files with 582 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"init_paused_status": 0
},
"eigenPod": {
"MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": 32000000000000000000,
"MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": 32000000000,
"GENESIS_TIME": 1695902400
},
"eigenPodManager": {
Expand Down
46 changes: 46 additions & 0 deletions script/configs/mainnet/M2_mainnet_upgrade.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"chainInfo": {
"chainId": 1
},
"multisig_addresses": {
"communityMultisig": "0xFEA47018D632A77bA579846c840d5706705Dc598",
"executorMultisig": "0x369e6F597e22EaB55fFb173C6d9cD234BD699111",
"operationsMultisig": "0xBE1685C81aA44FF9FB319dD389addd9374383e90",
"pauserMultisig": "0x5050389572f2d220ad927CcbeA0D406831012390",
"timelock": "0xA6Db1A8C5a981d1536266D2a393c5F8dDb210EAF"
},
"strategies": {
"numStrategies": 0,
"MAX_PER_DEPOSIT": 115792089237316195423570985008687907853269984665640564039457584007913129639935,
"MAX_TOTAL_DEPOSITS": 115792089237316195423570985008687907853269984665640564039457584007913129639935,
"strategiesToDeploy": []
},
"strategyManager": {
"init_strategy_whitelister": "0xBE1685C81aA44FF9FB319dD389addd9374383e90",
"init_paused_status": 1
},
"delegationManager": {
"init_paused_status": 0,
"init_minWithdrawalDelayBlocks": 50400
},
"avsDirectory": {
"init_paused_status": 0
},
"slasher": {
"init_paused_status": 115792089237316195423570985008687907853269984665640564039457584007913129639935
},
"eigenPod": {
"MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR": 32000000000,
"GENESIS_TIME": 1606824023
},
"eigenPodManager": {
"init_paused_status": 0,
"deneb_fork_timestamp": "1710338135"
},
"delayedWithdrawalRouter": {
"init_paused_status": 0,
"init_withdrawalDelayBlocks": 50400
},
"ethPOSDepositAddress": "0x00000000219ab540356cBB839Cbe05303d7705Fa",
"beaconOracleAddress": "0x343907185b71aDF0eBa9567538314396aa985442"
}
306 changes: 306 additions & 0 deletions script/deploy/mainnet/M2_Mainnet_Upgrade.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,306 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.12;

import "../../utils/ExistingDeploymentParser.sol";
import "../../utils/TimelockEncoding.sol";
import "../../utils/Multisend.sol";

/**
* @notice Script used for the first deployment of EigenLayer core contracts to Holesky
* anvil --fork-url $RPC_MAINNET
* forge script script/deploy/mainnet/M2_Mainnet_Upgrade.s.sol:M2_Mainnet_Upgrade --rpc-url http://127.0.0.1:8545 --private-key $PRIVATE_KEY --broadcast -vvvv
*
* forge script script/deploy/mainnet/M2_Mainnet_Upgrade.s.sol:M2_Mainnet_Upgrade --rpc-url $RPC_MAINNET --private-key $PRIVATE_KEY --broadcast -vvvv
*
*/
contract M2_Mainnet_Upgrade is ExistingDeploymentParser {
function run() external virtual {
_parseDeployedContracts("script/output/mainnet/M1_deployment_mainnet_2023_6_9.json");
_parseInitialDeploymentParams("script/configs/mainnet/M2_mainnet_upgrade.config.json");

// START RECORDING TRANSACTIONS FOR DEPLOYMENT
vm.startBroadcast();

emit log_named_address("Deployer Address", msg.sender);

_deployImplementationContracts();

// STOP RECORDING TRANSACTIONS FOR DEPLOYMENT
vm.stopBroadcast();

// Simulate upgrade of contracts to new implementations
_simulateUpgrade();

// Sanity Checks
_verifyContractPointers();
_verifyImplementations();
_verifyContractsInitialized({isInitialDeployment: true});
_verifyInitializationParams();

logAndOutputContractAddresses("script/output/mainnet/M2_mainnet_upgrade.output.json");
}

/**
* @notice Deploy EigenLayer contracts from scratch for Holesky
*/
function _deployImplementationContracts() internal {
// 1. Deploy New TUPS
avsDirectoryImplementation = new AVSDirectory(delegationManager);
avsDirectory = AVSDirectory(
address(
new TransparentUpgradeableProxy(
address(avsDirectoryImplementation),
address(eigenLayerProxyAdmin),
abi.encodeWithSelector(
AVSDirectory.initialize.selector,
executorMultisig, // initialOwner
eigenLayerPauserReg,
AVS_DIRECTORY_INIT_PAUSED_STATUS
)
)
)
);

// 2. Deploy Implementations
eigenPodImplementation = new EigenPod(
IETHPOSDeposit(ETHPOSDepositAddress),
delayedWithdrawalRouter,
eigenPodManager,
EIGENPOD_MAX_RESTAKED_BALANCE_GWEI_PER_VALIDATOR,
EIGENPOD_GENESIS_TIME
);
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);
}

function _simulateUpgrade() internal {

vm.startPrank(executorMultisig);

// First, upgrade the proxy contracts to point to the implementations
// AVSDirectory
// eigenLayerProxyAdmin.upgrade(
// TransparentUpgradeableProxy(payable(address(avsDirectory))),
// address(avsDirectoryImplementation)
// );
// DelegationManager
eigenLayerProxyAdmin.upgrade(
TransparentUpgradeableProxy(payable(address(delegationManager))),
address(delegationManagerImplementation)
);
// StrategyManager
eigenLayerProxyAdmin.upgrade(
TransparentUpgradeableProxy(payable(address(strategyManager))),
address(strategyManagerImplementation)
);
// Slasher
eigenLayerProxyAdmin.upgrade(
TransparentUpgradeableProxy(payable(address(slasher))),
address(slasherImplementation)
);
// EigenPodManager
eigenLayerProxyAdmin.upgrade(
TransparentUpgradeableProxy(payable(address(eigenPodManager))),
address(eigenPodManagerImplementation)
);
// Delayed Withdrawal Router
eigenLayerProxyAdmin.upgrade(
TransparentUpgradeableProxy(payable(address(delayedWithdrawalRouter))),
address(delayedWithdrawalRouterImplementation)
);

// Second, configure additional settings and paused statuses
delegationManager.setMinWithdrawalDelayBlocks(DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS);
delegationManager.unpause(0);
eigenPodManager.unpause(0);

eigenPodManager.setDenebForkTimestamp(EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP);
eigenPodManager.updateBeaconChainOracle(beaconOracle);
eigenPodBeacon.upgradeTo(address(eigenPodImplementation));

vm.stopPrank();
}
}

// forge t --mt test_queueUpgrade --fork-url $RPC_MAINNET -vvvv
contract Queue_M2_Upgrade is M2_Mainnet_Upgrade, TimelockEncoding {
Vm cheats = Vm(HEVM_ADDRESS);

// Thurs Apr 04 2024 12:00:00 GMT-0700 (Pacific Daylight Time)
uint256 timelockEta = 1712214000;

function test_queueUpgrade() external {
_parseDeployedContracts("script/output/mainnet/M1_deployment_mainnet_2023_6_9.json");
_parseInitialDeploymentParams("script/configs/mainnet/M2_mainnet_upgrade.config.json");

// TODO: fill in correct addresses
// simulate deploying contracts
_deployImplementationContracts();

Tx[] memory txs = new Tx[](11);
// upgrade the DelegationManager, Slasher, StrategyManager, DelayedWithdrawalRouter, EigenPodManager, & EigenPod contracts
txs[0] = Tx(
address(eigenLayerProxyAdmin),
0,
abi.encodeWithSelector(
ProxyAdmin.upgrade.selector,
TransparentUpgradeableProxy(payable(address(delegationManager))),
delegationManagerImplementation
)
);

txs[1] = Tx(
address(eigenLayerProxyAdmin),
0,
abi.encodeWithSelector(
ProxyAdmin.upgrade.selector,
TransparentUpgradeableProxy(payable(address(slasher))),
slasherImplementation
)
);

txs[2] = Tx(
address(eigenLayerProxyAdmin),
0,
abi.encodeWithSelector(
ProxyAdmin.upgrade.selector,
TransparentUpgradeableProxy(payable(address(strategyManager))),
strategyManagerImplementation
)
);

txs[3] = Tx(
address(eigenLayerProxyAdmin),
0,
abi.encodeWithSelector(
ProxyAdmin.upgrade.selector,
TransparentUpgradeableProxy(payable(address(delayedWithdrawalRouter))),
delayedWithdrawalRouterImplementation
)
);

txs[4] = Tx(
address(eigenLayerProxyAdmin),
0,
abi.encodeWithSelector(
ProxyAdmin.upgrade.selector,
TransparentUpgradeableProxy(payable(address(eigenPodManager))),
eigenPodManagerImplementation
)
);

txs[5] = Tx(
address(eigenPodBeacon),
0,
abi.encodeWithSelector(
UpgradeableBeacon.upgradeTo.selector,
eigenPodImplementation
)
);

// set the min withdrawal delay blocks on the DelegationManager
txs[6] = Tx(
address(delegationManager),
0, // value
abi.encodeWithSelector(DelegationManager.setMinWithdrawalDelayBlocks.selector, DELEGATION_MANAGER_MIN_WITHDRAWAL_DELAY_BLOCKS)
);

// set beacon chain oracle on EigenPodManager
txs[7] = Tx(
address(eigenPodManager),
0, // value
abi.encodeWithSelector(EigenPodManager.updateBeaconChainOracle.selector, beaconOracle)
);

// set Deneb fork timestamp on EigenPodManager
txs[8] = Tx(
address(eigenPodManager),
0, // value
abi.encodeWithSelector(EigenPodManager.setDenebForkTimestamp.selector, EIGENPOD_MANAGER_DENEB_FORK_TIMESTAMP)
);

// unpause everything on DelegationManager
txs[9] = Tx(
address(delegationManager),
0, // value
abi.encodeWithSelector(Pausable.unpause.selector, 0)
);

// unpause everything on EigenPodManager
txs[10] = Tx(
address(eigenPodManager),
0, // value
abi.encodeWithSelector(Pausable.unpause.selector, 0)
);

bytes memory calldata_to_multisend_contract = abi.encodeWithSelector(MultiSendCallOnly.multiSend.selector, encodeMultisendTxs(txs));
emit log_named_bytes("calldata_to_multisend_contract", calldata_to_multisend_contract);

bytes memory final_calldata_to_executor_multisig = encodeForExecutor({
// call to executor will be from the timelock
from: timelock,
// performing many operations at the same time
to: multiSendCallOnly,
// value to send in tx
value: 0,
// calldata for the operation
data: calldata_to_multisend_contract,
// operation type (for performing many operations at the same time)
operation: ISafe.Operation.DelegateCall
});

(bytes memory calldata_to_timelock_queuing_action, bytes memory calldata_to_timelock_executing_action) = encodeForTimelock({
// address to be called from the timelock
to: executorMultisig,
// value to send in tx
value: 0,
// calldata for the operation
data: final_calldata_to_executor_multisig,
// time at which the tx will become executable
timelockEta: timelockEta

});

bytes32 expectedTxHash = getTxHash({
target: executorMultisig,
_value: 0,
_data: final_calldata_to_executor_multisig,
eta: timelockEta
});
emit log_named_bytes32("expectedTxHash", expectedTxHash);

cheats.prank(operationsMultisig);
(bool success, ) = timelock.call(calldata_to_timelock_queuing_action);
require(success, "call to timelock queuing action failed");

require(ITimelock(timelock).queuedTransactions(expectedTxHash), "expectedTxHash not queued");

// test performing the upgrade
cheats.warp(timelockEta);
cheats.prank(operationsMultisig);
(success, ) = timelock.call(calldata_to_timelock_executing_action);
require(success, "call to timelock executing action failed");

// Check correctness after upgrade
_verifyContractPointers();
_verifyImplementations();
_verifyContractsInitialized({isInitialDeployment: true});
_verifyInitializationParams();
}

function getTxHash(address target, uint256 _value, bytes memory _data, uint256 eta) public pure returns (bytes32) {
// empty bytes
bytes memory signature;
bytes32 txHash = keccak256(abi.encode(target, _value, signature, _data, eta));
return txHash;
}
}
3 changes: 3 additions & 0 deletions script/output/mainnet/M1_deployment_mainnet_2023_6_9.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{
"addresses": {
"avsDirectory": "0x0000000000000000000000000000000000000000",
"avsDirectoryImplementation": "0x0000000000000000000000000000000000000000",
"baseStrategyImplementation": "0xdfdA04f980bE6A64E3607c95Ca26012Ab9aA46d3",
"beaconOracleAddress": "0x0000000000000000000000000000000000000000",
"delayedWithdrawalRouter": "0x7Fe7E9CC0F274d2435AD5d56D5fa73E47F6A23D8",
"delayedWithdrawalRouterImplementation": "0x44Bcb0E01CD0C5060D4Bb1A07b42580EF983E2AF",
"delegation": "0x39053D51B77DC0d36036Fc1fCc8Cb819df8Ef37A",
Expand Down
Loading

0 comments on commit 4b15d68

Please sign in to comment.