Skip to content

Commit cddb4a8

Browse files
committed
feat(zkstack): Deploy 2 ctms and deploy chain for each of them (#4458)
## What ❔ **Support for deploying and managing multiple CTM (Contract Template Manager) contracts, and allowing selection between them when creating chains.** ### Flow of execution #### 1. Create a new ecosystem ```bash zkstack ecosystem create ``` This command creates a **new ecosystem**. You’ll specify the link to the code repository (by default, this points to the **Era** codebase). Contracts will be used as a submodule within this repository. After creating the ecosystem, initialize it: ```bash zkstack ecosystem init ``` This command deploys a **new ecosystem** and **one default Era chain**. --- #### 2. Initialize another CTM Once everything is deployed, you can deploy an additional CTM: ```bash zkstack ctm init-new-ctm --zksync-os --contracts-src-path <path> --default-configs-src-path <path> ``` **Parameters:** * `--contracts-src-path` — Path to the **Era contracts** (you must clone and manage this repository manually). Use a branch or tag matching the desired **zkSync OS** or **Era** version. * `--default-configs-src-path` — Path to **default configs** (in Era this is typically `etc/env/file_based`). Only one file is required: `genesis.yaml` (in the old format). The data from these paths will be used during CTM deployment. --- #### 3. Register the CTM Once deployed, register the CTM within the ecosystem: ```bash zkstack ecosystem register-ctm --zksync-os ``` > ⚠️ **Important:** > `register-ctm` is an **ecosystem-level** subcommand — it must be called from within the ecosystem context. After registration, any chain can be created using this CTM. --- #### 4. Create a new chain using the selected CTM ```bash zkstack chain create --zksync-os ``` From this point on, all subsequent commands and scripts will use **zkSync OS contracts** by default. Then initialize the chain: ```bash zkstack chain init ``` This finalizes the chain initialization. --- #### 5. Development mode If you use the `--dev` flag during ecosystem initialization: ```bash zkstack ecosystem init --dev ``` All available CTMs and chains will be automatically initialized. --- #### 6. Optional shortcut Immediately after creating the ecosystem, you can predefine CTM contracts: ```bash zkstack ctm set-ctm-contracts --zksync-os ``` This sets the contracts path for the CTM so you don’t need to specify `--contracts-src-path` later during CTM initialization. --- ## Why ❔ This change enables ecosystems to: * Manage **multiple CTM contract versions** (e.g., Era and zkSync OS) side-by-side. * Flexibly choose which CTM to use when deploying new chains. * Simplify migration testing and allow **parallel evolution** of contract versions. * Support **gradual transition** to zkSync OS while maintaining Era compatibility. It also decouples contract source management from code releases, letting developers point to any desired version manually. --- ## Is this a breaking change? * [ ] Yes * [x] No --- ## Operational changes * New commands added: * `zkstack ctm init-new-ctm` * `zkstack ecosystem register-ctm` * `zkstack ctm set-ctm-contracts` * `ecosystem init --dev` now initializes all allowed CTMs and chains automatically. * Ecosystem can now host multiple CTMs (e.g., Era and zkSync OS). * Paths to contract sources and default configs must be managed manually when deploying additional CTMs. --- ## Checklist * [ ] PR title accurately reflects the body and purpose of the change. * [ ] Tests have been added or updated. * [ ] Documentation comments have been added or updated. * [ ] Code formatted with `zkstack dev fmt` and linted with `zkstack dev lint`. --------- Signed-off-by: Danil <[email protected]>
1 parent 265d16c commit cddb4a8

File tree

77 files changed

+1750
-1274
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+1750
-1274
lines changed

.github/workflows/ci-prover-e2e.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,9 @@ jobs:
4747
--base-token-price-denominator 1 \
4848
--set-as-default true \
4949
--ignore-prerequisites \
50-
--evm-emulator false \
51-
--update-submodules=true
50+
--evm-emulator false
5251
53-
ci_run zkstack ecosystem init --dev --update-submodules=true --verbose
52+
ci_run zkstack ecosystem init --dev --verbose
5453
5554
ci_run zkstack prover init --dev --verbose
5655
WEB3_HTTP_URL=$(yq -e '.api.web3_json_rpc.http_url' < ./chains/proving_chain/configs/general.yaml)

core/tests/highlevel-test-tools/src/create-chain.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,6 @@ export async function createChainAndStartServer(chainType: ChainType, testSuiteN
179179
[
180180
'chain',
181181
'create',
182-
'--update-submodules',
183-
'false',
184182
'--chain-name',
185183
chainConfig.chainName,
186184
'--chain-id',
@@ -228,8 +226,6 @@ export async function createChainAndStartServer(chainType: ChainType, testSuiteN
228226
chainConfig.chainName,
229227
'--validium-type',
230228
'no-da',
231-
'--update-submodules',
232-
'false',
233229
'--verbose'
234230
],
235231
chainConfig.chainName,

docs/src/guides/launch.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ To completely reset the dev environment:
7171
--base-token-price-denominator 1 \
7272
--set-as-default false \
7373
--evm-emulator false \
74-
--ignore-prerequisites --update-submodules false
74+
--ignore-prerequisites
7575
```
7676

7777
- Initialise `gateway` chain:

infrastructure/scripts/interop.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ zkstack chain create \
3232
--base-token-price-denominator 1 \
3333
--set-as-default false \
3434
--evm-emulator false \
35-
--ignore-prerequisites --update-submodules false
35+
--ignore-prerequisites
3636

3737
zkstack chain init \
3838
--deploy-paymaster \
@@ -53,7 +53,7 @@ zkstack chain create \
5353
--base-token-price-denominator 1 \
5454
--set-as-default false \
5555
--evm-emulator false \
56-
--ignore-prerequisites --update-submodules false
56+
--ignore-prerequisites
5757

5858
zkstack chain init \
5959
--deploy-paymaster \

zkstack_cli/crates/common/src/contracts.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std::path::Path;
22

33
use xshell::{cmd, Shell};
4+
use zksync_system_constants::L2_NATIVE_TOKEN_VAULT_ADDRESS;
5+
use zksync_types::{ethabi::encode, web3::keccak256, Address, H256, U256};
46

57
use crate::cmd::Cmd;
68

@@ -27,3 +29,33 @@ pub fn build_system_contracts(shell: Shell, link_to_contracts: &Path) -> anyhow:
2729
let _dir_guard = shell.push_dir(link_to_contracts.join("system-contracts"));
2830
Ok(Cmd::new(cmd!(shell, "yarn build:foundry")).run()?)
2931
}
32+
33+
pub fn install_yarn_dependencies(shell: &Shell, link_to_code: &Path) -> anyhow::Result<()> {
34+
let _dir_guard = shell.push_dir(link_to_code);
35+
Ok(Cmd::new(cmd!(shell, "yarn install")).run()?)
36+
}
37+
38+
pub fn build_da_contracts(shell: &Shell, link_to_contracts: &Path) -> anyhow::Result<()> {
39+
let _dir_guard = shell.push_dir(link_to_contracts);
40+
Ok(Cmd::new(cmd!(shell, "yarn da build:foundry")).run()?)
41+
}
42+
43+
pub fn rebuild_all_contracts(shell: &Shell, link_to_contracts: &Path) -> anyhow::Result<()> {
44+
install_yarn_dependencies(shell, link_to_contracts)?;
45+
build_l1_contracts(shell.clone(), link_to_contracts)?;
46+
build_l1_da_contracts(shell.clone(), link_to_contracts)?;
47+
build_l2_contracts(shell.clone(), link_to_contracts)?;
48+
build_system_contracts(shell.clone(), link_to_contracts)?;
49+
build_da_contracts(shell, link_to_contracts)?;
50+
Ok(())
51+
}
52+
53+
pub fn encode_ntv_asset_id(l1_chain_id: U256, addr: Address) -> H256 {
54+
let encoded_data = encode(&[
55+
ethers::abi::Token::Uint(l1_chain_id),
56+
ethers::abi::Token::Address(L2_NATIVE_TOKEN_VAULT_ADDRESS),
57+
ethers::abi::Token::Address(addr),
58+
]);
59+
60+
H256(keccak256(&encoded_data))
61+
}

zkstack_cli/crates/config/src/chain.rs

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use anyhow::Context;
77
use serde::{Deserialize, Serialize, Serializer};
88
use xshell::Shell;
99
use zkstack_cli_common::files::find_file;
10-
use zkstack_cli_types::{BaseToken, L1BatchCommitmentMode, L1Network, ProverMode, WalletCreation};
10+
use zkstack_cli_types::{
11+
BaseToken, L1BatchCommitmentMode, L1Network, ProverMode, VMOption, WalletCreation,
12+
};
1113
use zksync_basic_types::L2ChainId;
1214

1315
use crate::{
@@ -51,7 +53,9 @@ pub struct ChainConfigInternal {
5153
#[serde(default)] // for backward compatibility
5254
pub tight_ports: bool,
5355
#[serde(default)] // for backward compatibility
54-
pub zksync_os: bool,
56+
pub vm_option: VMOption,
57+
#[serde(skip_serializing_if = "Option::is_none")]
58+
pub contracts_source_path: Option<PathBuf>,
5559
}
5660

5761
/// Chain configuration file. This file is created in the chain
@@ -73,10 +77,11 @@ pub struct ChainConfig {
7377
pub legacy_bridge: Option<bool>,
7478
pub evm_emulator: bool,
7579
pub tight_ports: bool,
76-
pub zksync_os: bool,
80+
pub vm_option: VMOption,
7781
shell: OnceCell<Shell>,
7882
self_path: PathBuf,
7983
link_to_code: PathBuf,
84+
contracts_source_path: Option<PathBuf>,
8085
}
8186

8287
#[derive(Debug, Clone)]
@@ -116,7 +121,8 @@ impl ChainConfig {
116121
legacy_bridge: Option<bool>,
117122
evm_emulator: bool,
118123
tight_ports: bool,
119-
zksync_os: bool,
124+
vm_option: VMOption,
125+
contracts_source_path: Option<PathBuf>,
120126
) -> Self {
121127
Self {
122128
id,
@@ -137,7 +143,8 @@ impl ChainConfig {
137143
legacy_bridge,
138144
evm_emulator,
139145
tight_ports,
140-
zksync_os,
146+
vm_option,
147+
contracts_source_path,
141148
}
142149
}
143150

@@ -239,7 +246,8 @@ impl ChainConfig {
239246
legacy_bridge: self.legacy_bridge,
240247
evm_emulator: self.evm_emulator,
241248
tight_ports: self.tight_ports,
242-
zksync_os: self.zksync_os,
249+
vm_option: self.vm_option,
250+
contracts_source_path: self.contracts_source_path.clone(),
243251
}
244252
}
245253
pub(crate) fn from_internal(
@@ -273,7 +281,8 @@ impl ChainConfig {
273281
tight_ports: chain_internal.tight_ports,
274282
self_path: shell.current_dir(),
275283
shell: shell.into(),
276-
zksync_os: chain_internal.zksync_os,
284+
vm_option: chain_internal.vm_option,
285+
contracts_source_path: chain_internal.contracts_source_path.clone(),
277286
})
278287
}
279288
}
@@ -316,7 +325,11 @@ impl ZkStackConfigTrait for ChainConfig {
316325
}
317326

318327
fn contracts_path(&self) -> PathBuf {
319-
self.link_to_code().join(CONTRACTS_PATH)
328+
if let Some(contracts_path) = &self.contracts_source_path {
329+
contracts_path.clone()
330+
} else {
331+
self.link_to_code().join(CONTRACTS_PATH)
332+
}
320333
}
321334

322335
fn path_to_foundry_scripts(&self) -> PathBuf {

0 commit comments

Comments
 (0)