Skip to content

Commit c3448b3

Browse files
authored
feat: deploy from scratch scripts (#1661)
**Motivation:** We want deploy from scratch scripts for preprod-hoodi. **Modifications:** - Reorganize the deploy from scratch scripts into: 1. Multichain Deployer; 2. Destination Chain Genesis: 3. Protocol Genesis - Create a `v1.6.0-protocol-from-scratch` script - Add a `MultisigDeployerLib` to dedupe all the Multisig calls we were making - Add a `Scripts.md` file that describes the available scripts **Result:** Clear deploy from scratch
1 parent 4c7842c commit c3448b3

34 files changed

+2166
-891
lines changed

.github/workflows/validate-deployment-scripts.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
strategy:
1919
fail-fast: true
2020
matrix:
21-
env: [mainnet, testnet-sepolia, testnet-hoodi, testnet-base-sepolia, base]
21+
env: [mainnet, testnet-sepolia, testnet-hoodi, testnet-base-sepolia, base, preprod-hoodi]
2222

2323
steps:
2424
- uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911
@@ -66,7 +66,7 @@ jobs:
6666
- name: Validate Solidity Scripts
6767
run: |
6868
# Find all .sol files under /script/releases
69-
RELEASE_FILES=$(find script/releases -type f -name "*.sol" ! -name "Env.sol" ! -name "CrosschainDeployLib.sol" 2>/dev/null || echo "")
69+
RELEASE_FILES=$(find script/releases -type f -name "*.sol" ! -name "Env.sol" ! -name "CrosschainDeployLib.sol" ! -name "MultisigDeployLib.sol" 2>/dev/null || echo "")
7070
7171
# Combine file lists
7272
FILES="$RELEASE_FILES"
@@ -91,6 +91,8 @@ jobs:
9191
RPC_URL="${{ secrets.RPC_MAINNET }}"
9292
elif [ "${{ matrix.env }}" = "base" ]; then
9393
RPC_URL="${{ secrets.RPC_BASE }}"
94+
elif [ "${{ matrix.env }}" = "preprod-hoodi" ]; then
95+
RPC_URL="${{ secrets.RPC_HOODI }}"
9496
fi
9597
9698
# Run zeus test on each file with the specified environment and RPC URL

script/releases/Env.sol

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,10 @@ library Env {
9292
return _envAddress("executorMultisig");
9393
}
9494

95+
function beigenExecutorMultisig() internal view returns (address) {
96+
return _envAddress("beigenExecutorMultisig");
97+
}
98+
9599
function opsMultisig() internal view returns (address) {
96100
return _envAddress("operationsMultisig");
97101
}
@@ -120,6 +124,10 @@ library Env {
120124
return _envAddress("proxyAdmin");
121125
}
122126

127+
function beigenProxyAdmin() internal view returns (address) {
128+
return _envAddress("beigenProxyAdmin");
129+
}
130+
123131
function ethPOS() internal view returns (IETHPOSDeposit) {
124132
return IETHPOSDeposit(_envAddress("ethPOS"));
125133
}
@@ -128,6 +136,10 @@ library Env {
128136
return TimelockController(payable(_envAddress("timelockController")));
129137
}
130138

139+
function beigenTimelockController() internal view returns (TimelockController) {
140+
return TimelockController(payable(_envAddress("beigenTimelockController")));
141+
}
142+
131143
function multiSendCallOnly() internal view returns (address) {
132144
return _envAddress("MultiSendCallOnly");
133145
}
@@ -412,14 +424,14 @@ library Env {
412424

413425
function beigen(
414426
DeployedProxy
415-
) internal view returns (IBackingEigen) {
416-
return IBackingEigen(_deployedProxy(type(BackingEigen).name));
427+
) internal view returns (BackingEigen) {
428+
return BackingEigen(_deployedProxy(type(BackingEigen).name));
417429
}
418430

419431
function beigen(
420432
DeployedImpl
421-
) internal view returns (IBackingEigen) {
422-
return IBackingEigen(_deployedImpl(type(BackingEigen).name));
433+
) internal view returns (BackingEigen) {
434+
return BackingEigen(_deployedImpl(type(BackingEigen).name));
423435
}
424436

425437
/**
Lines changed: 47 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,10 @@
11
// SPDX-License-Identifier: BUSL-1.1
22
pragma solidity ^0.8.12;
33

4-
import {EOADeployer} from "zeus-templates/templates/EOADeployer.sol";
5-
import "forge-std/console.sol";
6-
import "../../releases/Env.sol";
7-
8-
/// @notice Deploy the multichain deployer multisig
9-
/// @dev This script is used to deploy the multichain deployer multisig on the destination chain
10-
/// @dev This script should ONLY be used for mainnet environments. Testnet environments should follow our notion guide
11-
/// TODO: Add a testnet version of this script
12-
/// @dev The SAFE version is 1.4.1
13-
contract DeployMultichainDeployer is EOADeployer {
14-
using Env for *;
15-
16-
/// @dev The expected address of the multichain deployer on the destination chain
17-
address public constant MULTICHAIN_DEPLOYER_EXPECTED_ADDRESS = 0xa3053EF25F1F7d9D55a7655372B8a31D0f40eCA9;
18-
19-
/// @dev Salt for deploying the multichain deployer multisig
20-
uint256 public constant SALT = 0;
21-
22-
/// @dev Initial threshold for the multichain deployer multisig
23-
uint256 public constant INITIAL_THRESHOLD = 1;
24-
25-
/// @dev Initial owner of the multichain deployer multisig
26-
address public constant INITIAL_OWNER = 0x792e42f05E87Fb9D8b8F9FdFC598B1de20507964;
4+
/// @notice A library for deploying Safe multisigs
5+
/// @dev Double check the constant addresses are correct on each chain prior to deployment
6+
library MultisigDeployLib {
7+
using MultisigDeployLib for *;
278

289
/// @dev Safe proxy factory, this should be the same for all chains
2910
/// @dev See https://github.com/safe-global/safe-smart-account/blob/main/CHANGELOG.md#version-141 for more details
@@ -35,76 +16,65 @@ contract DeployMultichainDeployer is EOADeployer {
3516
/// @dev L2 Singletons still need to be passed into the L1 deployment
3617
/// @dev `SAFE_TO_L2_SETUP` does a no-op if the chain is mainnet
3718
/// @dev See: https://github.com/safe-global/safe-smart-account/blob/0095f1aa113255d97b476e625760514cc7d10982/contracts/libraries/SafeToL2Setup.sol#L59-L69
19+
/// @dev Even mainnet testnet chains (eg. sepolia, hoodi) should use the SAFE_L2_SINGLETON
3820
address public constant SAFE_L2_SINGLETON = 0x29fcB43b46531BcA003ddC8FCB67FFE91900C762;
3921
address public constant SAFE_TO_L2_SETUP = 0xBD89A1CE4DDe368FFAB0eC35506eEcE0b1fFdc54;
22+
bytes public constant SETUP_TO_L2_DATA = abi.encodeWithSignature("setupToL2(address)", SAFE_L2_SINGLETON);
4023

41-
function _runAsEOA() internal override {
42-
vm.startBroadcast();
43-
44-
address multichainDeployerMultisig = ISafeProxyFactory(SAFE_PROXY_FACTORY).createProxyWithNonce({
45-
_singleton: SAFE_SINGLETON,
46-
initializer: getInitializationData(),
47-
saltNonce: SALT
48-
});
49-
50-
vm.stopBroadcast();
51-
52-
// Update config
53-
zUpdate("multichainDeployerMultisig", multichainDeployerMultisig);
54-
}
55-
56-
function testScript() public virtual {
57-
// If the multichain deployer multisig is already deployed, we need to add the contracts to the env
58-
if (_isDeployerMultisigDeployed()) {
59-
_addContractsToEnv();
60-
} else {
61-
// Otherwise, we need to deploy the multichain deployer multisig
62-
super.runAsEOA();
63-
}
64-
65-
// Check that the multichain deployer multisig is deployed at the expected address
66-
assertEq(Env.multichainDeployerMultisig(), MULTICHAIN_DEPLOYER_EXPECTED_ADDRESS);
67-
68-
// Check the threshold is 1
69-
assertEq(IMultisig(address(Env.multichainDeployerMultisig())).getThreshold(), 1);
70-
71-
// Check owners
72-
address[] memory owners = IMultisig(address(Env.multichainDeployerMultisig())).getOwners();
73-
assertEq(owners.length, 1, "Expected 1 owner");
74-
assertEq(owners[0], INITIAL_OWNER, "Expected initial owner");
75-
76-
// Check the version is 1.4.1
77-
assertEq(IMultisig(address(Env.multichainDeployerMultisig())).VERSION(), "1.4.1");
24+
/**
25+
* @notice Deploys a Safe multisig
26+
* @param initialOwners The initial owners of the multisig
27+
* @param initialThreshold The initial threshold of the multisig
28+
* @param salt The salt to use for the deployment
29+
* @return The address of the deployed multisig
30+
*/
31+
function deployMultisig(
32+
address[] memory initialOwners,
33+
uint256 initialThreshold,
34+
uint256 salt
35+
) internal returns (address) {
36+
return deployMultisigWithPaymentReceiver(initialOwners, initialThreshold, salt, address(0));
7837
}
7938

80-
function getInitializationData() internal pure returns (bytes memory) {
81-
// Setup initial owners
82-
address[] memory initialOwners = new address[](1);
83-
initialOwners[0] = INITIAL_OWNER;
84-
85-
// Setup the multisig
86-
return abi.encodeWithSelector(
39+
/// @notice Used to deploy a multisig with a payment receiver. This is used by multichain deployer on testnet chains.
40+
function deployMultisigWithPaymentReceiver(
41+
address[] memory initialOwners,
42+
uint256 initialThreshold,
43+
uint256 salt,
44+
address paymentReceiver
45+
) internal returns (address) {
46+
bytes memory initializerData = abi.encodeWithSelector(
8747
IMultisig.setup.selector,
8848
initialOwners, /* signers */
89-
INITIAL_THRESHOLD, /* threshold */
49+
initialThreshold, /* threshold */
9050
SAFE_TO_L2_SETUP, /* to (used in setupModules) */
91-
abi.encodeWithSignature("setupToL2(address)", SAFE_L2_SINGLETON), /* data (used in setupModules) */
51+
SETUP_TO_L2_DATA, /* data (used in setupModules) */
9252
SAFE_FALLBACK_HANDLER, /* fallbackHandler */
9353
address(0), /* paymentToken */
9454
0, /* payment */
95-
payable(address(0)) /* paymentReceiver */
55+
payable(paymentReceiver) /* paymentReceiver */
9656
);
57+
58+
address deployedMultisig =
59+
ISafeProxyFactory(SAFE_PROXY_FACTORY).createProxyWithNonce(SAFE_SINGLETON, initializerData, salt);
60+
require(deployedMultisig != address(0), "something wrong in multisig deployment, zero address returned");
61+
return deployedMultisig;
62+
}
63+
64+
function getThreshold(
65+
address multisig
66+
) internal view returns (uint256) {
67+
return IMultisig(multisig).getThreshold();
9768
}
9869

99-
function _isDeployerMultisigDeployed() internal view returns (bool) {
100-
return MULTICHAIN_DEPLOYER_EXPECTED_ADDRESS.code.length > 0;
70+
function getOwners(
71+
address multisig
72+
) internal view returns (address[] memory) {
73+
return IMultisig(multisig).getOwners();
10174
}
10275

103-
/// @dev Add contracts to the env
104-
/// @dev This function should only be called if the multichain deployer multisig is already deployed
105-
function _addContractsToEnv() internal {
106-
require(MULTICHAIN_DEPLOYER_EXPECTED_ADDRESS.code.length > 0, "Multichain deployer multisig not deployed");
107-
zUpdate("multichainDeployerMultisig", MULTICHAIN_DEPLOYER_EXPECTED_ADDRESS);
76+
function isOwner(address multisig, address owner) internal view returns (bool) {
77+
return IMultisig(multisig).isOwner(owner);
10878
}
10979
}
11080

script/releases/Scripts.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# EigenLayer Release Scripts
2+
3+
This document describes the various release scripts available in the `script/releases/` directory.
4+
5+
## Multichain Multisig Deployer Scripts
6+
7+
### 1. multichain-deployer-mainnet
8+
Deploys a multichain deployer multisig to mainnet environments (e.g., Base, Ethereum Mainnet).
9+
- Initializes the multisig to be 3/7
10+
- 6 of the 7 signers come from the ops multisig
11+
12+
### 2. multichain-deployer-testnet-preprod
13+
Deploys a multichain deployer multisig to testnet and preprod environments.
14+
- Configured as a 1/n multisig
15+
- Has 0xDA as the signer
16+
17+
## Destination Chain Initialization Scripts
18+
19+
### 3. v1.6.0-destination-genesis-mainnet
20+
Deploys foundational contracts for a destination chain
21+
- Proxy Admin
22+
- Ops Multisig
23+
- Pauser Multisig
24+
25+
### 4. v1.6.0-destination-governance-mainnet
26+
Deploys governance infrastructure for a destination chain
27+
- Timelock Controller (with 1 day delay)
28+
- Protocol Council Multisig
29+
- Community Multisig
30+
- Executor Multisig
31+
- The protocol council and community multisigs are initialized to be the mainnet ops multisig signers with 3/n quorum
32+
33+
### 5. v1.6.0-destination-governance-testnet
34+
Same as the mainnet governance deployment above, but with testnet-specific configurations:
35+
- Timelock delay set to 1 second
36+
- The owner of the multisig is the 0xDA address
37+
- Threshold is 1
38+
39+
## Protocol Deployment Scripts
40+
41+
### 6. v1.6.0-protocol-from-scratch
42+
Deploys the entire EigenLayer protocol from scratch to v1.6.0, including:
43+
- All contracts up to slashing
44+
- Governance infrastructure
45+
- Token contracts
46+
*Note: This should not be used on destination chains, only the below should be used.* This script is useful to initiate a net new *full core protocol deployment* on a testnet chain.
47+
48+
### 7. v1.7.0-v1.8.0-multichain-hourglass-combined
49+
Upgrades the protocol to support:
50+
- Multichain functionality
51+
- Hourglass features

0 commit comments

Comments
 (0)