-
Notifications
You must be signed in to change notification settings - Fork 357
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: m2 mainnet upgrade script (#480)
* 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
1 parent
b87095b
commit 4b15d68
Showing
8 changed files
with
582 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.