diff --git a/zkstack_cli/crates/config/src/chain.rs b/zkstack_cli/crates/config/src/chain.rs index d01b32fd7d58..f4c57d67c2e1 100644 --- a/zkstack_cli/crates/config/src/chain.rs +++ b/zkstack_cli/crates/config/src/chain.rs @@ -19,7 +19,7 @@ use crate::{ FileConfigWithDefaultName, ReadConfig, ReadConfigWithBasePath, SaveConfig, SaveConfigWithBasePath, ZkStackConfig, }, - utils::find_file, + utils::{find_file, get_preexisting_ecosystem_contracts_path}, ContractsConfig, EcosystemConfig, GeneralConfig, GenesisConfig, SecretsConfig, WalletsConfig, }; @@ -151,6 +151,10 @@ impl ChainConfig { config.save_with_base_path(shell, path) } + pub fn get_preexisting_ecosystem_contracts_path(&self) -> PathBuf { + get_preexisting_ecosystem_contracts_path(&self.link_to_code, self.l1_network) + } + fn get_internal(&self) -> ChainConfigInternal { ChainConfigInternal { id: self.id, diff --git a/zkstack_cli/crates/config/src/consts.rs b/zkstack_cli/crates/config/src/consts.rs index c3efb4ac3e96..1332d59037f4 100644 --- a/zkstack_cli/crates/config/src/consts.rs +++ b/zkstack_cli/crates/config/src/consts.rs @@ -36,8 +36,8 @@ pub(crate) const LOCAL_APPS_PATH: &str = "apps/"; pub(crate) const LOCAL_CHAINS_PATH: &str = "chains/"; pub(crate) const LOCAL_CONFIGS_PATH: &str = "configs/"; pub(crate) const LOCAL_GENERATED_PATH: &str = ".generated/"; -pub(crate) const LOCAL_DB_PATH: &str = "db/"; -pub(crate) const LOCAL_ARTIFACTS_PATH: &str = "artifacts/"; +pub const LOCAL_DB_PATH: &str = "db/"; +pub const LOCAL_ARTIFACTS_PATH: &str = "artifacts/"; /// Name of apps config file pub const APPS_CONFIG_FILE: &str = "apps.yaml"; diff --git a/zkstack_cli/crates/config/src/ecosystem.rs b/zkstack_cli/crates/config/src/ecosystem.rs index fc3a2c5b71f9..15836d748002 100644 --- a/zkstack_cli/crates/config/src/ecosystem.rs +++ b/zkstack_cli/crates/config/src/ecosystem.rs @@ -12,9 +12,9 @@ use zksync_basic_types::L2ChainId; use crate::{ consts::{ - CONFIGS_PATH, CONFIG_NAME, CONTRACTS_FILE, ECOSYSTEM_PATH, ERA_CHAIN_ID, - ERC20_CONFIGS_FILE, ERC20_DEPLOYMENT_FILE, INITIAL_DEPLOYMENT_FILE, L1_CONTRACTS_FOUNDRY, - LOCAL_ARTIFACTS_PATH, LOCAL_DB_PATH, WALLETS_FILE, + CONFIGS_PATH, CONFIG_NAME, CONTRACTS_FILE, ERA_CHAIN_ID, ERC20_CONFIGS_FILE, + ERC20_DEPLOYMENT_FILE, INITIAL_DEPLOYMENT_FILE, L1_CONTRACTS_FOUNDRY, LOCAL_ARTIFACTS_PATH, + LOCAL_DB_PATH, WALLETS_FILE, }, create_localhost_wallets, forge_interface::deploy_ecosystem::{ @@ -22,7 +22,7 @@ use crate::{ output::{ERC20Tokens, Erc20Token}, }, traits::{FileConfigWithDefaultName, ReadConfig, SaveConfig, ZkStackConfig}, - utils::find_file, + utils::{find_file, get_preexisting_ecosystem_contracts_path}, ChainConfig, ChainConfigInternal, ContractsConfig, WalletsConfig, }; @@ -123,7 +123,6 @@ impl EcosystemConfig { // with chain and we will find the ecosystem config somewhere in parent directories let chain_config = ChainConfigInternal::read(shell, CONFIG_NAME) .map_err(|err| EcosystemConfigFromFileError::InvalidConfig { source: err })?; - logger::info(format!("You are in a directory with chain config, default chain for execution has changed to {}", &chain_config.name)); let current_dir = shell.current_dir(); let Some(parent) = current_dir.parent() else { @@ -131,8 +130,15 @@ impl EcosystemConfig { }; // Try to find ecosystem somewhere in parent directories shell.change_dir(parent); - let mut ecosystem_config = EcosystemConfig::from_file(shell)?; + let mut ecosystem_config = match EcosystemConfig::from_file(shell) { + Ok(ecosystem) => ecosystem, + Err(err) => { + shell.change_dir(¤t_dir); + return Err(err); + } + }; // change the default chain for using it in later executions + logger::info(format!("You are in a directory with chain config, default chain for execution has changed to {}", &chain_config.name)); ecosystem_config.default_chain = chain_config.name; ecosystem_config } @@ -197,7 +203,7 @@ impl EcosystemConfig { } pub fn get_wallets(&self) -> anyhow::Result { - let path = self.config.join(WALLETS_FILE); + let path = self.get_wallets_path(); if self.get_shell().path_exists(&path) { return WalletsConfig::read(self.get_shell(), &path); } @@ -211,7 +217,7 @@ impl EcosystemConfig { } pub fn get_contracts_config(&self) -> anyhow::Result { - ContractsConfig::read(self.get_shell(), self.config.join(CONTRACTS_FILE)) + ContractsConfig::read(self.get_shell(), self.get_contracts_path()) } pub fn path_to_foundry(&self) -> PathBuf { @@ -242,8 +248,8 @@ impl EcosystemConfig { } /// Path to the predefined ecosystem configs - pub fn get_preexisting_configs_path(&self) -> PathBuf { - self.link_to_code.join(ECOSYSTEM_PATH) + pub fn get_preexisting_ecosystem_contracts_path(&self) -> PathBuf { + get_preexisting_ecosystem_contracts_path(&self.link_to_code, self.l1_network) } pub fn get_chain_rocks_db_path(&self, chain_name: &str) -> PathBuf { @@ -272,6 +278,14 @@ impl EcosystemConfig { wallet_creation: self.wallet_creation, } } + + pub fn get_contracts_path(&self) -> PathBuf { + self.config.join(CONTRACTS_FILE) + } + + pub fn get_wallets_path(&self) -> PathBuf { + self.config.join(WALLETS_FILE) + } } /// Result of checking if the ecosystem exists. diff --git a/zkstack_cli/crates/config/src/lib.rs b/zkstack_cli/crates/config/src/lib.rs index f3001fd55f8d..4937618ae1ed 100644 --- a/zkstack_cli/crates/config/src/lib.rs +++ b/zkstack_cli/crates/config/src/lib.rs @@ -14,7 +14,6 @@ pub use zksync_protobuf_config::{encode_yaml_repr, read_yaml_repr}; mod apps; mod chain; -mod consts; mod contracts; mod ecosystem; mod file_config; @@ -28,6 +27,7 @@ mod wallets; pub mod consensus_config; pub mod consensus_secrets; +pub mod consts; pub mod docker_compose; pub mod explorer; pub mod explorer_compose; diff --git a/zkstack_cli/crates/config/src/utils.rs b/zkstack_cli/crates/config/src/utils.rs index 63cf2cf601f5..e24c1570e2c9 100644 --- a/zkstack_cli/crates/config/src/utils.rs +++ b/zkstack_cli/crates/config/src/utils.rs @@ -1,7 +1,10 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; +use types::L1Network; use xshell::Shell; +use crate::ECOSYSTEM_PATH; + // Find file in all parents repository and return necessary path or an empty error if nothing has been found pub fn find_file(shell: &Shell, path_buf: PathBuf, file_name: &str) -> Result { let _dir = shell.push_dir(path_buf); @@ -15,3 +18,12 @@ pub fn find_file(shell: &Shell, path_buf: PathBuf, file_name: &str) -> Result PathBuf { + link_to_code + .join(ECOSYSTEM_PATH) + .join(format!("{}.yaml", l1_network.to_string().to_lowercase())) +} diff --git a/zkstack_cli/crates/zkstack/completion/_zkstack.zsh b/zkstack_cli/crates/zkstack/completion/_zkstack.zsh index fa24bf741c22..9a45735aa25e 100644 --- a/zkstack_cli/crates/zkstack/completion/_zkstack.zsh +++ b/zkstack_cli/crates/zkstack/completion/_zkstack.zsh @@ -82,6 +82,7 @@ in-file\:"Specify file with wallets"))' \ '--base-token-price-denominator=[Base token denominator]:BASE_TOKEN_PRICE_DENOMINATOR:_default' \ '--set-as-default=[Set as default chain]' \ '--evm-emulator=[Enable EVM emulator]' \ +'--l1-network=[L1 Network]:L1_NETWORK:(localhost sepolia holesky mainnet)' \ '--start-containers=[Start reth and postgres containers after creation]' \ '--chain=[Chain to use]:CHAIN:_default' \ '--legacy-bridge[]' \ @@ -243,6 +244,7 @@ in-file\:"Specify file with wallets"))' \ '--base-token-price-denominator=[Base token denominator]:BASE_TOKEN_PRICE_DENOMINATOR:_default' \ '--set-as-default=[Set as default chain]' \ '--evm-emulator=[Enable EVM emulator]' \ +'--l1-network=[L1 Network]:L1_NETWORK:(localhost sepolia holesky mainnet)' \ '--chain=[Chain to use]:CHAIN:_default' \ '--legacy-bridge[]' \ '-v[Verbose mode]' \ @@ -284,6 +286,8 @@ _arguments "${_arguments_options[@]}" : \ '--server-db-name=[Server database name]:SERVER_DB_NAME:_default' \ '--deploy-paymaster=[]' \ '--l1-rpc-url=[L1 RPC URL]:L1_RPC_URL:_default' \ +'--ecosystem-contracts-path=[Ecosystem contracts path]:ECOSYSTEM_CONTRACTS_PATH:_default' \ +'--wallets-path=[Wallets path]:WALLETS_PATH:_default' \ '--chain=[Chain to use]:CHAIN:_default' \ '--resume[]' \ '-d[]' \ @@ -310,6 +314,7 @@ _arguments "${_arguments_options[@]}" : \ '--server-db-url=[Server database url without database name]:SERVER_DB_URL:_default' \ '--server-db-name=[Server database name]:SERVER_DB_NAME:_default' \ '--l1-rpc-url=[L1 RPC URL]:L1_RPC_URL:_default' \ +'--ecosystem-contracts-path=[Ecosystem contracts path]:ECOSYSTEM_CONTRACTS_PATH:_default' \ '--chain=[Chain to use]:CHAIN:_default' \ '-d[Use default database urls and names]' \ '--dev[Use default database urls and names]' \ diff --git a/zkstack_cli/crates/zkstack/completion/zkstack.fish b/zkstack_cli/crates/zkstack/completion/zkstack.fish index 0ff8584ba2a1..20ea0c60c834 100644 --- a/zkstack_cli/crates/zkstack/completion/zkstack.fish +++ b/zkstack_cli/crates/zkstack/completion/zkstack.fish @@ -71,6 +71,7 @@ complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_se complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from create" -l base-token-price-denominator -d 'Base token denominator' -r complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from create" -l set-as-default -d 'Set as default chain' -r -f -a "{true\t'',false\t''}" complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from create" -l evm-emulator -d 'Enable EVM emulator' -r -f -a "{true\t'',false\t''}" +complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from create" -l l1-network -d 'L1 Network' -r -f -a "{localhost\t'',sepolia\t'',holesky\t'',mainnet\t''}" complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from create" -l start-containers -d 'Start reth and postgres containers after creation' -r -f -a "{true\t'',false\t''}" complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from create" -l chain -d 'Chain to use' -r complete -c zkstack -n "__fish_zkstack_using_subcommand ecosystem; and __fish_seen_subcommand_from create" -l legacy-bridge @@ -159,6 +160,7 @@ complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_s complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from create" -l base-token-price-denominator -d 'Base token denominator' -r complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from create" -l set-as-default -d 'Set as default chain' -r -f -a "{true\t'',false\t''}" complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from create" -l evm-emulator -d 'Enable EVM emulator' -r -f -a "{true\t'',false\t''}" +complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from create" -l l1-network -d 'L1 Network' -r -f -a "{localhost\t'',sepolia\t'',holesky\t'',mainnet\t''}" complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from create" -l chain -d 'Chain to use' -r complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from create" -l legacy-bridge complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from create" -s v -l verbose -d 'Verbose mode' @@ -185,6 +187,8 @@ complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_s complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -l server-db-name -d 'Server database name' -r complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -l deploy-paymaster -r -f -a "{true\t'',false\t''}" complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -l l1-rpc-url -d 'L1 RPC URL' -r +complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -l ecosystem-contracts-path -d 'Ecosystem contracts path' -r +complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -l wallets-path -d 'Wallets path' -r complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -l chain -d 'Chain to use' -r complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -l resume complete -c zkstack -n "__fish_zkstack_using_subcommand chain; and __fish_seen_subcommand_from init" -s d -l dont-drop diff --git a/zkstack_cli/crates/zkstack/completion/zkstack.sh b/zkstack_cli/crates/zkstack/completion/zkstack.sh index 941c964d4c60..5dd12b32ee1b 100644 --- a/zkstack_cli/crates/zkstack/completion/zkstack.sh +++ b/zkstack_cli/crates/zkstack/completion/zkstack.sh @@ -1652,7 +1652,7 @@ _zkstack() { return 0 ;; zkstack__chain__create) - opts="-v -h --chain-name --chain-id --prover-mode --wallet-creation --wallet-path --l1-batch-commit-data-generator-mode --base-token-address --base-token-price-nominator --base-token-price-denominator --set-as-default --legacy-bridge --evm-emulator --verbose --chain --ignore-prerequisites --help" + opts="-v -h --chain-name --chain-id --prover-mode --wallet-creation --wallet-path --l1-batch-commit-data-generator-mode --base-token-address --base-token-price-nominator --base-token-price-denominator --set-as-default --legacy-bridge --evm-emulator --l1-network --verbose --chain --ignore-prerequisites --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -1713,6 +1713,10 @@ _zkstack() { COMPREPLY=($(compgen -W "true false" -- "${cur}")) return 0 ;; + --l1-network) + COMPREPLY=($(compgen -W "localhost sepolia holesky mainnet" -- "${cur}")) + return 0 + ;; --chain) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2551,7 +2555,7 @@ _zkstack() { return 0 ;; zkstack__chain__init) - opts="-a -d -v -h --verify --verifier --verifier-url --verifier-api-key --resume --additional-args --server-db-url --server-db-name --dont-drop --deploy-paymaster --l1-rpc-url --no-port-reallocation --dev --verbose --chain --ignore-prerequisites --help configs help" + opts="-a -d -v -h --verify --verifier --verifier-url --verifier-api-key --resume --additional-args --server-db-url --server-db-name --dont-drop --deploy-paymaster --l1-rpc-url --no-port-reallocation --ecosystem-contracts-path --wallets-path --dev --verbose --chain --ignore-prerequisites --help configs help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2597,6 +2601,14 @@ _zkstack() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --ecosystem-contracts-path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --wallets-path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --chain) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -2609,7 +2621,7 @@ _zkstack() { return 0 ;; zkstack__chain__init__configs) - opts="-d -d -v -h --server-db-url --server-db-name --dev --dont-drop --l1-rpc-url --no-port-reallocation --verbose --chain --ignore-prerequisites --help" + opts="-d -d -v -h --server-db-url --server-db-name --dev --dont-drop --l1-rpc-url --no-port-reallocation --ecosystem-contracts-path --verbose --chain --ignore-prerequisites --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 4 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -2627,6 +2639,10 @@ _zkstack() { COMPREPLY=($(compgen -f "${cur}")) return 0 ;; + --ecosystem-contracts-path) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; --chain) COMPREPLY=($(compgen -f "${cur}")) return 0 @@ -5305,7 +5321,7 @@ _zkstack() { return 0 ;; zkstack__ecosystem__create) - opts="-v -h --ecosystem-name --l1-network --link-to-code --chain-name --chain-id --prover-mode --wallet-creation --wallet-path --l1-batch-commit-data-generator-mode --base-token-address --base-token-price-nominator --base-token-price-denominator --set-as-default --legacy-bridge --evm-emulator --start-containers --verbose --chain --ignore-prerequisites --help" + opts="-v -h --ecosystem-name --l1-network --link-to-code --chain-name --chain-id --prover-mode --wallet-creation --wallet-path --l1-batch-commit-data-generator-mode --base-token-address --base-token-price-nominator --base-token-price-denominator --set-as-default --legacy-bridge --evm-emulator --l1-network --start-containers --verbose --chain --ignore-prerequisites --help" if [[ ${cur} == -* || ${COMP_CWORD} -eq 3 ]] ; then COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) return 0 @@ -5381,6 +5397,10 @@ _zkstack() { COMPREPLY=($(compgen -W "true false" -- "${cur}")) return 0 ;; + --l1-network) + COMPREPLY=($(compgen -W "localhost sepolia holesky mainnet" -- "${cur}")) + return 0 + ;; --start-containers) COMPREPLY=($(compgen -W "true false" -- "${cur}")) return 0 diff --git a/zkstack_cli/crates/zkstack/src/accept_ownership.rs b/zkstack_cli/crates/zkstack/src/accept_ownership.rs index 474e76e599a8..d3c6d7699fda 100644 --- a/zkstack_cli/crates/zkstack/src/accept_ownership.rs +++ b/zkstack_cli/crates/zkstack/src/accept_ownership.rs @@ -1,3 +1,5 @@ +use std::path::Path; + use common::{ forge::{Forge, ForgeScript, ForgeScriptArgs}, spinner::Spinner, @@ -26,7 +28,7 @@ lazy_static! { pub async fn accept_admin( shell: &Shell, - ecosystem_config: &EcosystemConfig, + foundry_contracts_path: &Path, admin: Address, governor: &Wallet, target_address: Address, @@ -42,8 +44,7 @@ pub async fn accept_admin( let calldata = ACCEPT_ADMIN .encode("chainAdminAcceptAdmin", (admin, target_address)) .unwrap(); - let foundry_contracts_path = ecosystem_config.path_to_foundry(); - let forge = Forge::new(&foundry_contracts_path) + let forge = Forge::new(foundry_contracts_path) .script( &ACCEPT_GOVERNANCE_SCRIPT_PARAMS.script(), forge_args.clone(), diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/accept_chain_ownership.rs b/zkstack_cli/crates/zkstack/src/commands/chain/accept_chain_ownership.rs index 2ecb80b1fed6..b98d81581272 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/accept_chain_ownership.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/accept_chain_ownership.rs @@ -1,23 +1,19 @@ use anyhow::Context; use common::{forge::ForgeScriptArgs, logger, spinner::Spinner}; -use config::zkstack_config::ZkStackConfig; +use config::ChainConfig; use xshell::Shell; use crate::{ accept_ownership::accept_admin, messages::{ - MSG_ACCEPTING_ADMIN_SPINNER, MSG_CHAIN_NOT_INITIALIZED, MSG_CHAIN_OWNERSHIP_TRANSFERRED, + MSG_ACCEPTING_ADMIN_SPINNER, MSG_CHAIN_OWNERSHIP_TRANSFERRED, MSG_L1_SECRETS_MUST_BE_PRESENTED, }, }; -pub async fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { - let ecosystem_config = ZkStackConfig::ecosystem(shell)?; - let chain_config = ecosystem_config - .load_current_chain() - .context(MSG_CHAIN_NOT_INITIALIZED)?; - let contracts = chain_config.get_contracts_config()?; - let secrets = chain_config.get_secrets_config()?; +pub async fn run(args: ForgeScriptArgs, shell: &Shell, chain: ChainConfig) -> anyhow::Result<()> { + let contracts = chain.get_contracts_config()?; + let secrets = chain.get_secrets_config()?; let l1_rpc_url = secrets .l1 .context(MSG_L1_SECRETS_MUST_BE_PRESENTED)? @@ -28,9 +24,9 @@ pub async fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { let spinner = Spinner::new(MSG_ACCEPTING_ADMIN_SPINNER); accept_admin( shell, - &ecosystem_config, + &chain.path_to_foundry(), contracts.l1.chain_admin_addr, - &chain_config.get_wallets_config()?.governor, + &chain.get_wallets_config()?.governor, contracts.l1.diamond_proxy_addr, &args, l1_rpc_url.clone(), diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/args/create.rs b/zkstack_cli/crates/zkstack/src/commands/chain/args/create.rs index ec37f9ba0304..c6f2f8b28362 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/args/create.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/args/create.rs @@ -8,7 +8,8 @@ use serde::{Deserialize, Serialize}; use slugify_rs::slugify; use strum::{Display, EnumIter, IntoEnumIterator}; use types::{BaseToken, L1BatchCommitmentMode, L1Network, ProverMode, WalletCreation}; -use zksync_basic_types::H160; +use xshell::Shell; +use zksync_basic_types::{L2ChainId, H160}; use crate::{ defaults::L2_CHAIN_ID, @@ -20,12 +21,13 @@ use crate::{ MSG_CHAIN_ID_PROMPT, MSG_CHAIN_ID_VALIDATOR_ERR, MSG_CHAIN_NAME_PROMPT, MSG_EVM_EMULATOR_HELP, MSG_EVM_EMULATOR_PROMPT, MSG_L1_BATCH_COMMIT_DATA_GENERATOR_MODE_PROMPT, MSG_L1_COMMIT_DATA_GENERATOR_MODE_HELP, - MSG_NUMBER_VALIDATOR_GREATHER_THAN_ZERO_ERR, MSG_NUMBER_VALIDATOR_NOT_ZERO_ERR, - MSG_PROVER_MODE_HELP, MSG_PROVER_VERSION_PROMPT, MSG_SET_AS_DEFAULT_HELP, - MSG_SET_AS_DEFAULT_PROMPT, MSG_WALLET_CREATION_HELP, MSG_WALLET_CREATION_PROMPT, - MSG_WALLET_CREATION_VALIDATOR_ERR, MSG_WALLET_PATH_HELP, MSG_WALLET_PATH_INVALID_ERR, - MSG_WALLET_PATH_PROMPT, + MSG_L1_NETWORK_HELP, MSG_L1_NETWORK_PROMPT, MSG_NUMBER_VALIDATOR_GREATHER_THAN_ZERO_ERR, + MSG_NUMBER_VALIDATOR_NOT_ZERO_ERR, MSG_PROVER_MODE_HELP, MSG_PROVER_VERSION_PROMPT, + MSG_SET_AS_DEFAULT_HELP, MSG_SET_AS_DEFAULT_PROMPT, MSG_WALLET_CREATION_HELP, + MSG_WALLET_CREATION_PROMPT, MSG_WALLET_CREATION_VALIDATOR_ERR, MSG_WALLET_PATH_HELP, + MSG_WALLET_PATH_INVALID_ERR, MSG_WALLET_PATH_PROMPT, }, + utils::link_to_code::get_link_to_code, }; // We need to duplicate it for using enum inside the arguments @@ -70,21 +72,30 @@ pub struct ChainCreateArgs { pub(crate) legacy_bridge: bool, #[arg(long, help = MSG_EVM_EMULATOR_HELP, default_missing_value = "true", num_args = 0..=1)] evm_emulator: Option, + #[clap(long, help = MSG_L1_NETWORK_HELP, value_enum)] + pub l1_network: Option, } impl ChainCreateArgs { + #[allow(clippy::too_many_arguments)] pub fn fill_values_with_prompt( self, + shell: &Shell, number_of_chains: u32, - l1_network: &L1Network, + internal_id: u32, + l1_network: Option, possible_erc20: Vec, - link_to_code: String, + link_to_code: Option, + chains_path: Option, + era_chain_id: L2ChainId, ) -> anyhow::Result { let mut chain_name = self .chain_name .unwrap_or_else(|| Prompt::new(MSG_CHAIN_NAME_PROMPT).ask()); chain_name = slugify!(&chain_name, separator = "_"); + let chain_path = chains_path.unwrap_or_default().join(&chain_name); + let chain_id = self .chain_id .map(|v| match v { @@ -97,8 +108,14 @@ impl ChainCreateArgs { .ask() }); + let l1_network = l1_network.unwrap_or_else(|| { + self.l1_network.unwrap_or_else(|| { + PromptSelect::new(MSG_L1_NETWORK_PROMPT, L1Network::iter()).ask() + }) + }); + let wallet_creation = if let Some(wallet) = self.wallet_creation { - if wallet == WalletCreation::Localhost && *l1_network != L1Network::Localhost { + if wallet == WalletCreation::Localhost && l1_network != L1Network::Localhost { bail!(MSG_WALLET_CREATION_VALIDATOR_ERR); } else { wallet @@ -108,7 +125,7 @@ impl ChainCreateArgs { MSG_WALLET_CREATION_PROMPT, WalletCreation::iter().filter(|wallet| { // Disable localhost wallets for external networks - if *l1_network == L1Network::Localhost { + if l1_network == L1Network::Localhost { true } else { *wallet != WalletCreation::Localhost @@ -215,6 +232,8 @@ impl ChainCreateArgs { } }; + let link_to_code = link_to_code.unwrap_or_else(|| get_link_to_code(shell)); + let evm_emulator = self.evm_emulator.unwrap_or_else(|| { PromptConfirm::new(MSG_EVM_EMULATOR_PROMPT) .default(false) @@ -222,6 +241,9 @@ impl ChainCreateArgs { }); let set_as_default = self.set_as_default.unwrap_or_else(|| { + if number_of_chains == 0 { + return true; + } PromptConfirm::new(MSG_SET_AS_DEFAULT_PROMPT) .default(true) .ask() @@ -239,6 +261,10 @@ impl ChainCreateArgs { legacy_bridge: self.legacy_bridge, evm_emulator, link_to_code, + chain_path, + era_chain_id, + internal_id, + l1_network, }) } } @@ -256,6 +282,10 @@ pub struct ChainCreateArgsFinal { pub legacy_bridge: bool, pub evm_emulator: bool, pub link_to_code: String, + pub chain_path: PathBuf, + pub era_chain_id: L2ChainId, + pub internal_id: u32, + pub l1_network: L1Network, } #[derive(Debug, Clone, EnumIter, Display, PartialEq, Eq)] diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/args/init/configs.rs b/zkstack_cli/crates/zkstack/src/commands/chain/args/init/configs.rs index b34809643cf5..67f06effedd5 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/args/init/configs.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/args/init/configs.rs @@ -1,17 +1,23 @@ +use std::path::PathBuf; + use clap::Parser; use common::Prompt; -use config::ChainConfig; +use config::{ChainConfig, EcosystemConfig}; use serde::{Deserialize, Serialize}; use types::L1Network; use url::Url; use crate::{ - commands::chain::args::{ - genesis::{GenesisArgs, GenesisArgsFinal}, - init::InitArgsFinal, + commands::{ + chain::args::{ + genesis::{GenesisArgs, GenesisArgsFinal}, + init::InitArgsFinal, + }, + ecosystem::init::prompt_ecosystem_contracts_path, }, defaults::LOCAL_RPC_URL, messages::{ + msg_ecosystem_no_found_preexisting_contract, MSG_ECOSYSTEM_CONTRACTS_PATH_HELP, MSG_GENESIS_ARGS_HELP, MSG_L1_RPC_URL_HELP, MSG_L1_RPC_URL_INVALID_ERR, MSG_L1_RPC_URL_PROMPT, MSG_NO_PORT_REALLOCATION_HELP, }, @@ -26,6 +32,8 @@ pub struct InitConfigsArgs { pub l1_rpc_url: Option, #[clap(long, help = MSG_NO_PORT_REALLOCATION_HELP)] pub no_port_reallocation: bool, + #[clap(long, help = MSG_ECOSYSTEM_CONTRACTS_PATH_HELP)] + pub ecosystem_contracts_path: Option, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -33,13 +41,18 @@ pub struct InitConfigsArgsFinal { pub genesis_args: GenesisArgsFinal, pub l1_rpc_url: String, pub no_port_reallocation: bool, + pub ecosystem_contracts_path: PathBuf, } impl InitConfigsArgs { - pub fn fill_values_with_prompt(self, config: &ChainConfig) -> InitConfigsArgsFinal { + pub fn fill_values_with_prompt( + self, + ecosystem: Option, + chain: &ChainConfig, + ) -> anyhow::Result { let l1_rpc_url = self.l1_rpc_url.unwrap_or_else(|| { let mut prompt = Prompt::new(MSG_L1_RPC_URL_PROMPT); - if config.l1_network == L1Network::Localhost { + if chain.l1_network == L1Network::Localhost { prompt = prompt.default(LOCAL_RPC_URL); } prompt @@ -51,12 +64,43 @@ impl InitConfigsArgs { .ask() }); - InitConfigsArgsFinal { - genesis_args: self.genesis_args.fill_values_with_prompt(config), + let ecosystem_contracts_path = + get_ecosystem_contracts_path(self.ecosystem_contracts_path, ecosystem, chain)?; + + Ok(InitConfigsArgsFinal { + genesis_args: self.genesis_args.fill_values_with_prompt(chain), l1_rpc_url, no_port_reallocation: self.no_port_reallocation, - } + ecosystem_contracts_path, + }) + } +} + +pub fn get_ecosystem_contracts_path( + ecosystem_contracts_path: Option, + ecosystem: Option, + chain: &ChainConfig, +) -> anyhow::Result { + let ecosystem_preexisting_contracts_path = ecosystem.map_or_else( + || chain.get_preexisting_ecosystem_contracts_path(), + |e| e.get_preexisting_ecosystem_contracts_path(), + ); + + let ecosystem_contracts_path = + ecosystem_contracts_path.map_or_else(prompt_ecosystem_contracts_path, |path| { + if path.is_empty() { + return None; + } + Some(PathBuf::from(path)) + }); + + if ecosystem_contracts_path.is_none() && !ecosystem_preexisting_contracts_path.exists() { + anyhow::bail!(msg_ecosystem_no_found_preexisting_contract( + &chain.l1_network.to_string() + )) } + + Ok(ecosystem_contracts_path.unwrap_or(ecosystem_preexisting_contracts_path)) } impl InitConfigsArgsFinal { @@ -65,6 +109,7 @@ impl InitConfigsArgsFinal { genesis_args: init_args.genesis_args.clone(), l1_rpc_url: init_args.l1_rpc_url.clone(), no_port_reallocation: init_args.no_port_reallocation, + ecosystem_contracts_path: init_args.ecosystem_contracts_path.clone(), } } } diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/args/init/mod.rs b/zkstack_cli/crates/zkstack/src/commands/chain/args/init/mod.rs index a5c7a6890ca1..84e7d71bc8ae 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/args/init/mod.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/args/init/mod.rs @@ -1,6 +1,9 @@ +use std::path::PathBuf; + use clap::Parser; use common::{forge::ForgeScriptArgs, Prompt}; -use config::ChainConfig; +use config::{ChainConfig, EcosystemConfig}; +use configs::get_ecosystem_contracts_path; use serde::{Deserialize, Serialize}; use types::L1Network; use url::Url; @@ -9,9 +12,10 @@ use crate::{ commands::chain::args::genesis::{GenesisArgs, GenesisArgsFinal}, defaults::LOCAL_RPC_URL, messages::{ - MSG_DEPLOY_PAYMASTER_PROMPT, MSG_DEV_ARG_HELP, MSG_L1_RPC_URL_HELP, - MSG_L1_RPC_URL_INVALID_ERR, MSG_L1_RPC_URL_PROMPT, MSG_NO_PORT_REALLOCATION_HELP, - MSG_SERVER_DB_NAME_HELP, MSG_SERVER_DB_URL_HELP, + MSG_DEPLOY_PAYMASTER_PROMPT, MSG_DEV_ARG_HELP, MSG_ECOSYSTEM_CONTRACTS_PATH_HELP, + MSG_L1_RPC_URL_HELP, MSG_L1_RPC_URL_INVALID_ERR, MSG_L1_RPC_URL_PROMPT, + MSG_NO_PORT_REALLOCATION_HELP, MSG_SERVER_DB_NAME_HELP, MSG_SERVER_DB_URL_HELP, + MSG_WALLETS_PATH_HELP, MSG_WALLETS_PATH_PROMPT, }, }; @@ -35,6 +39,10 @@ pub struct InitArgs { pub l1_rpc_url: Option, #[clap(long, help = MSG_NO_PORT_REALLOCATION_HELP)] pub no_port_reallocation: bool, + #[clap(long, help = MSG_ECOSYSTEM_CONTRACTS_PATH_HELP)] + pub ecosystem_contracts_path: Option, + #[clap(long, help = MSG_WALLETS_PATH_HELP)] + pub wallets_path: Option, #[clap(long, help = MSG_DEV_ARG_HELP)] pub dev: bool, } @@ -49,7 +57,11 @@ impl InitArgs { } } - pub fn fill_values_with_prompt(self, config: &ChainConfig) -> InitArgsFinal { + pub fn fill_values_with_prompt( + self, + ecosystem: Option, + chain: &ChainConfig, + ) -> anyhow::Result { let genesis = self.get_genesis_args(); let deploy_paymaster = if self.dev { @@ -67,7 +79,7 @@ impl InitArgs { } else { self.l1_rpc_url.unwrap_or_else(|| { let mut prompt = Prompt::new(MSG_L1_RPC_URL_PROMPT); - if config.l1_network == L1Network::Localhost { + if chain.l1_network == L1Network::Localhost { prompt = prompt.default(LOCAL_RPC_URL); } prompt @@ -80,14 +92,40 @@ impl InitArgs { }) }; - InitArgsFinal { + let ecosystem_contracts_path = if self.dev { + self.ecosystem_contracts_path.map_or_else( + || { + ecosystem.as_ref().map_or_else( + || chain.get_preexisting_ecosystem_contracts_path(), + |e| e.get_contracts_path(), + ) + }, + PathBuf::from, + ) + } else if let Some(ecosystem) = &ecosystem { + ecosystem.get_contracts_path() + } else { + get_ecosystem_contracts_path(self.ecosystem_contracts_path, ecosystem.clone(), chain)? + }; + + let wallets_path = ecosystem.map_or_else( + || { + self.wallets_path + .map_or_else(|| Prompt::new(MSG_WALLETS_PATH_PROMPT).ask(), PathBuf::from) + }, + |e| e.get_wallets_path(), + ); + + Ok(InitArgsFinal { forge_args: self.forge_args, - genesis_args: genesis.fill_values_with_prompt(config), + genesis_args: genesis.fill_values_with_prompt(chain), deploy_paymaster, l1_rpc_url, no_port_reallocation: self.no_port_reallocation, + ecosystem_contracts_path, + wallets_path, dev: self.dev, - } + }) } } @@ -98,5 +136,7 @@ pub struct InitArgsFinal { pub deploy_paymaster: bool, pub l1_rpc_url: String, pub no_port_reallocation: bool, + pub ecosystem_contracts_path: PathBuf, + pub wallets_path: PathBuf, pub dev: bool, } diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/build_transactions.rs b/zkstack_cli/crates/zkstack/src/commands/chain/build_transactions.rs index 5af70ec176e9..f40472e4b8b1 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/build_transactions.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/build_transactions.rs @@ -1,8 +1,8 @@ use anyhow::Context; use common::{git, logger, spinner::Spinner}; use config::{ - copy_configs, traits::SaveConfigWithBasePath, update_from_chain_config, - zkstack_config::ZkStackConfig, + copy_configs, traits::SaveConfigWithBasePath, update_from_chain_config, ChainConfig, + EcosystemConfig, }; use ethers::utils::hex::ToHex; use xshell::Shell; @@ -12,9 +12,9 @@ use crate::{ args::build_transactions::BuildTransactionsArgs, register_chain::register_chain, }, messages::{ - MSG_BUILDING_CHAIN_REGISTRATION_TXNS_SPINNER, MSG_CHAIN_NOT_FOUND_ERR, - MSG_CHAIN_TRANSACTIONS_BUILT, MSG_CHAIN_TXN_MISSING_CONTRACT_CONFIG, - MSG_CHAIN_TXN_OUT_PATH_INVALID_ERR, MSG_PREPARING_CONFIG_SPINNER, MSG_SELECTED_CONFIG, + MSG_BUILDING_CHAIN_REGISTRATION_TXNS_SPINNER, MSG_CHAIN_TRANSACTIONS_BUILT, + MSG_CHAIN_TXN_MISSING_CONTRACT_CONFIG, MSG_CHAIN_TXN_OUT_PATH_INVALID_ERR, + MSG_ECOSYSTEM_CONFIG_INVALID_ERR, MSG_PREPARING_CONFIG_SPINNER, MSG_SELECTED_CONFIG, MSG_WRITING_OUTPUT_FILES_SPINNER, }, }; @@ -27,40 +27,43 @@ const SCRIPT_CONFIG_FILE_SRC: &str = "contracts/l1-contracts/script-config/register-hyperchain.toml"; const SCRIPT_CONFIG_FILE_DST: &str = "register-hyperchain.toml"; -pub(crate) async fn run(args: BuildTransactionsArgs, shell: &Shell) -> anyhow::Result<()> { - let config = ZkStackConfig::ecosystem(shell)?; - let chain_config = config - .load_current_chain() - .context(MSG_CHAIN_NOT_FOUND_ERR)?; +pub(crate) async fn run( + args: BuildTransactionsArgs, + shell: &Shell, + chain: ChainConfig, + ecosystem: Option, +) -> anyhow::Result<()> { + let ecosystem = ecosystem.context(MSG_ECOSYSTEM_CONFIG_INVALID_ERR)?; - let args = args.fill_values_with_prompt(config.default_chain.clone()); + let args = args.fill_values_with_prompt(ecosystem.default_chain.clone()); - git::submodule_update(shell, config.link_to_code.clone())?; + git::submodule_update(shell, ecosystem.link_to_code.clone())?; let spinner = Spinner::new(MSG_PREPARING_CONFIG_SPINNER); - copy_configs(shell, &config.link_to_code, &chain_config.configs)?; + copy_configs(shell, &ecosystem.link_to_code, &chain.configs)?; - logger::note(MSG_SELECTED_CONFIG, logger::object_to_string(&chain_config)); + logger::note(MSG_SELECTED_CONFIG, logger::object_to_string(&chain)); - let mut genesis_config = chain_config.get_genesis_config()?; - update_from_chain_config(&mut genesis_config, &chain_config)?; + let mut genesis_config = chain.get_genesis_config()?; + update_from_chain_config(&mut genesis_config, &chain)?; // Copy ecosystem contracts - let mut contracts_config = config + let mut contracts_config = ecosystem .get_contracts_config() .context(MSG_CHAIN_TXN_MISSING_CONTRACT_CONFIG)?; - contracts_config.l1.base_token_addr = chain_config.base_token.address; + contracts_config.l1.base_token_addr = chain.base_token.address; spinner.finish(); let spinner = Spinner::new(MSG_BUILDING_CHAIN_REGISTRATION_TXNS_SPINNER); - let governor: String = config.get_wallets()?.governor.address.encode_hex_upper(); + let wallets = ecosystem.get_wallets()?; + let governor: String = wallets.governor.address.encode_hex_upper(); register_chain( shell, args.forge_args.clone(), - &config, - &chain_config, + &chain, &mut contracts_config, + &wallets, args.l1_rpc_url.clone(), Some(governor), false, @@ -76,12 +79,12 @@ pub(crate) async fn run(args: BuildTransactionsArgs, shell: &Shell) -> anyhow::R .context(MSG_CHAIN_TXN_OUT_PATH_INVALID_ERR)?; shell.copy_file( - config.link_to_code.join(REGISTER_CHAIN_TXNS_FILE_SRC), + ecosystem.link_to_code.join(REGISTER_CHAIN_TXNS_FILE_SRC), args.out.join(REGISTER_CHAIN_TXNS_FILE_DST), )?; shell.copy_file( - config.link_to_code.join(SCRIPT_CONFIG_FILE_SRC), + ecosystem.link_to_code.join(SCRIPT_CONFIG_FILE_SRC), args.out.join(SCRIPT_CONFIG_FILE_DST), )?; spinner.finish(); diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/common.rs b/zkstack_cli/crates/zkstack/src/commands/chain/common.rs index 0c35b3ee4fe0..c14e140679c5 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/common.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/common.rs @@ -1,5 +1,5 @@ use common::spinner::Spinner; -use config::{ChainConfig, EcosystemConfig}; +use config::{ChainConfig, WalletsConfig}; use types::{BaseToken, L1Network, WalletCreation}; use crate::{ @@ -9,66 +9,70 @@ use crate::{ // Distribute eth to the chain wallets for localhost environment pub async fn distribute_eth( - ecosystem_config: &EcosystemConfig, chain_config: &ChainConfig, l1_rpc_url: String, + wallets: &WalletsConfig, ) -> anyhow::Result<()> { - if chain_config.wallet_creation == WalletCreation::Localhost - && ecosystem_config.l1_network == L1Network::Localhost + if chain_config.wallet_creation != WalletCreation::Localhost + || chain_config.l1_network != L1Network::Localhost { - let spinner = Spinner::new(MSG_DISTRIBUTING_ETH_SPINNER); - let wallets = ecosystem_config.get_wallets()?; - let chain_wallets = chain_config.get_wallets_config()?; - let mut addresses = vec![ - chain_wallets.operator.address, - chain_wallets.blob_operator.address, - chain_wallets.governor.address, - ]; - if let Some(deployer) = chain_wallets.deployer { - addresses.push(deployer.address) - } - if let Some(setter) = chain_wallets.token_multiplier_setter { - addresses.push(setter.address) - } - common::ethereum::distribute_eth( - wallets.operator, - addresses, - l1_rpc_url, - ecosystem_config.l1_network.chain_id(), - AMOUNT_FOR_DISTRIBUTION_TO_WALLETS, - ) - .await?; - spinner.finish(); + return Ok(()); } + + let spinner = Spinner::new(MSG_DISTRIBUTING_ETH_SPINNER); + let chain_wallets = chain_config.get_wallets_config()?; + let mut addresses = vec![ + chain_wallets.operator.address, + chain_wallets.blob_operator.address, + chain_wallets.governor.address, + ]; + if let Some(deployer) = chain_wallets.deployer { + addresses.push(deployer.address); + } + if let Some(setter) = chain_wallets.token_multiplier_setter { + addresses.push(setter.address); + } + common::ethereum::distribute_eth( + wallets.operator.clone(), + addresses, + l1_rpc_url, + chain_config.l1_network.chain_id(), + AMOUNT_FOR_DISTRIBUTION_TO_WALLETS, + ) + .await?; + spinner.finish(); + Ok(()) } pub async fn mint_base_token( - ecosystem_config: &EcosystemConfig, chain_config: &ChainConfig, l1_rpc_url: String, + wallets: &WalletsConfig, ) -> anyhow::Result<()> { - if chain_config.wallet_creation == WalletCreation::Localhost - && ecosystem_config.l1_network == L1Network::Localhost - && chain_config.base_token != BaseToken::eth() + if chain_config.wallet_creation != WalletCreation::Localhost + || chain_config.l1_network != L1Network::Localhost + || chain_config.base_token == BaseToken::eth() { - let spinner = Spinner::new(MSG_MINT_BASE_TOKEN_SPINNER); - let wallets = ecosystem_config.get_wallets()?; - let chain_wallets = chain_config.get_wallets_config()?; - let base_token = &chain_config.base_token; - let addresses = vec![wallets.governor.address, chain_wallets.governor.address]; - let amount = AMOUNT_FOR_DISTRIBUTION_TO_WALLETS * base_token.nominator as u128 - / base_token.denominator as u128; - common::ethereum::mint_token( - wallets.governor, - base_token.address, - addresses, - l1_rpc_url, - ecosystem_config.l1_network.chain_id(), - amount, - ) - .await?; - spinner.finish(); + return Ok(()); } + + let spinner = Spinner::new(MSG_MINT_BASE_TOKEN_SPINNER); + let chain_wallets = chain_config.get_wallets_config()?; + let base_token = &chain_config.base_token; + let addresses = vec![wallets.governor.address, chain_wallets.governor.address]; + let amount = AMOUNT_FOR_DISTRIBUTION_TO_WALLETS * base_token.nominator as u128 + / base_token.denominator as u128; + common::ethereum::mint_token( + wallets.governor.clone(), + base_token.address, + addresses, + l1_rpc_url, + chain_config.l1_network.chain_id(), + amount, + ) + .await?; + spinner.finish(); + Ok(()) } diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/create.rs b/zkstack_cli/crates/zkstack/src/commands/chain/create.rs index c5ff4956c87b..4ef5f8573ed1 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/create.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/create.rs @@ -3,10 +3,10 @@ use std::cell::OnceCell; use anyhow::Context; use common::{logger, spinner::Spinner}; use config::{ - create_local_configs_dir, create_wallets, + create_local_configs_dir, create_wallets, get_default_era_chain_id, traits::{ReadConfigWithBasePath, SaveConfigWithBasePath}, zkstack_config::ZkStackConfig, - ChainConfig, EcosystemConfig, GenesisConfig, + ChainConfig, EcosystemConfig, GenesisConfig, LOCAL_ARTIFACTS_PATH, LOCAL_DB_PATH, }; use xshell::Shell; use zksync_basic_types::L2ChainId; @@ -22,22 +22,49 @@ use crate::{ }; pub fn run(args: ChainCreateArgs, shell: &Shell) -> anyhow::Result<()> { - let mut ecosystem_config = ZkStackConfig::ecosystem(shell)?; + let mut ecosystem_config = ZkStackConfig::ecosystem(shell).ok(); create(args, &mut ecosystem_config, shell) } fn create( args: ChainCreateArgs, - ecosystem_config: &mut EcosystemConfig, + ecosystem: &mut Option, shell: &Shell, ) -> anyhow::Result<()> { - let tokens = ecosystem_config.get_erc20_tokens(); + let possible_erc20 = ecosystem + .as_ref() + .map(|ecosystem| ecosystem.get_erc20_tokens()) + .unwrap_or_default(); + + let number_of_chains = ecosystem + .as_ref() + .map(|ecosystem| ecosystem.list_of_chains().len() as u32) + .unwrap_or(0); + + let internal_id = ecosystem.as_ref().map_or(0, |_| number_of_chains + 1); + + let l1_network = ecosystem.as_ref().map(|ecosystem| ecosystem.l1_network); + + let chains_path = ecosystem.as_ref().map(|ecosystem| ecosystem.chains.clone()); + let era_chain_id = ecosystem + .as_ref() + .map(|ecosystem| ecosystem.era_chain_id) + .unwrap_or(get_default_era_chain_id()); + + let link_to_code = ecosystem + .as_ref() + .map(|ecosystem| ecosystem.link_to_code.clone().display().to_string()); + let args = args .fill_values_with_prompt( - ecosystem_config.list_of_chains().len() as u32, - &ecosystem_config.l1_network, - tokens, - ecosystem_config.link_to_code.clone().display().to_string(), + shell, + number_of_chains, + internal_id, + l1_network, + possible_erc20, + link_to_code, + chains_path, + era_chain_id, ) .context(MSG_ARGS_VALIDATOR_ERR)?; @@ -47,10 +74,14 @@ fn create( let spinner = Spinner::new(MSG_CREATING_CHAIN_CONFIGURATIONS_SPINNER); let name = args.chain_name.clone(); let set_as_default = args.set_as_default; - create_chain_inner(args, ecosystem_config, shell)?; - if set_as_default { - ecosystem_config.default_chain = name; - ecosystem_config.save_with_base_path(shell, ".")?; + + create_chain_inner(args, shell)?; + + if let Some(ecosystem) = ecosystem.as_mut() { + if set_as_default { + ecosystem.default_chain = name; + ecosystem.save_with_base_path(shell, ".")?; + } } spinner.finish(); @@ -59,24 +90,19 @@ fn create( Ok(()) } -pub(crate) fn create_chain_inner( - args: ChainCreateArgsFinal, - ecosystem_config: &EcosystemConfig, - shell: &Shell, -) -> anyhow::Result<()> { +pub(crate) fn create_chain_inner(args: ChainCreateArgsFinal, shell: &Shell) -> anyhow::Result<()> { if args.legacy_bridge { logger::warn("WARNING!!! You are creating a chain with legacy bridge, use it only for testing compatibility") } let default_chain_name = args.chain_name.clone(); - let chain_path = ecosystem_config.chains.join(&default_chain_name); + let chain_path = args.chain_path; let chain_configs_path = create_local_configs_dir(shell, &chain_path)?; let (chain_id, legacy_bridge) = if args.legacy_bridge { // Legacy bridge is distinguished by using the same chain id as ecosystem - (ecosystem_config.era_chain_id, Some(true)) + (args.era_chain_id, Some(true)) } else { (L2ChainId::from(args.chain_id), None) }; - let internal_id = ecosystem_config.list_of_chains().len() as u32; let link_to_code = resolve_link_to_code(shell, chain_path.clone(), args.link_to_code.clone())?; let default_genesis_config = GenesisConfig::read_with_base_path( shell, @@ -86,16 +112,18 @@ pub(crate) fn create_chain_inner( if args.evm_emulator && !has_evm_emulation_support { anyhow::bail!(MSG_EVM_EMULATOR_HASH_MISSING_ERR); } + let rocks_db_path = chain_path.join(LOCAL_DB_PATH); + let artifacts = chain_path.join(LOCAL_ARTIFACTS_PATH); let chain_config = ChainConfig { - id: internal_id, + id: args.internal_id, name: default_chain_name.clone(), chain_id, prover_version: args.prover_version, - l1_network: ecosystem_config.l1_network, - link_to_code: ecosystem_config.link_to_code.clone(), - rocks_db_path: ecosystem_config.get_chain_rocks_db_path(&default_chain_name), - artifacts: ecosystem_config.get_chain_artifacts_path(&default_chain_name), + l1_network: args.l1_network, + link_to_code: link_to_code.clone(), + rocks_db_path, + artifacts, configs: chain_configs_path.clone(), external_node_config_path: None, l1_batch_commit_data_generator_mode: args.l1_batch_commit_data_generator_mode, @@ -109,8 +137,8 @@ pub(crate) fn create_chain_inner( create_wallets( shell, &chain_config.configs, - &ecosystem_config.link_to_code, - internal_id, + &link_to_code, + args.internal_id, args.wallet_creation, args.wallet_path, )?; diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/deploy_l2_contracts.rs b/zkstack_cli/crates/zkstack/src/commands/chain/deploy_l2_contracts.rs index 1aaefacc8e3c..e483511b89ef 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/deploy_l2_contracts.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/deploy_l2_contracts.rs @@ -18,16 +18,13 @@ use config::{ script_params::DEPLOY_L2_CONTRACTS_SCRIPT_PARAMS, }, traits::{ReadConfig, SaveConfig, SaveConfigWithBasePath}, - zkstack_config::ZkStackConfig, - ChainConfig, ContractsConfig, EcosystemConfig, + ChainConfig, ContractsConfig, EcosystemConfig, WalletsConfig, }; use xshell::Shell; +use zksync_basic_types::L2ChainId; use crate::{ - messages::{ - MSG_CHAIN_NOT_INITIALIZED, MSG_DEPLOYING_L2_CONTRACT_SPINNER, - MSG_L1_SECRETS_MUST_BE_PRESENTED, - }, + messages::{MSG_DEPLOYING_L2_CONTRACT_SPINNER, MSG_L1_SECRETS_MUST_BE_PRESENTED}, utils::forge::{check_the_balance, fill_forge_private_key}, }; @@ -44,80 +41,40 @@ pub async fn run( args: ForgeScriptArgs, shell: &Shell, deploy_option: Deploy2ContractsOption, + chain: ChainConfig, + ecosystem: EcosystemConfig, ) -> anyhow::Result<()> { - let ecosystem_config = ZkStackConfig::ecosystem(shell)?; - let chain_config = ecosystem_config - .load_current_chain() - .context(MSG_CHAIN_NOT_INITIALIZED)?; - - let mut contracts = chain_config.get_contracts_config()?; + let mut contracts = chain.get_contracts_config()?; + let era_chain_id = ecosystem.era_chain_id; + let wallets = ecosystem.get_wallets()?; let spinner = Spinner::new(MSG_DEPLOYING_L2_CONTRACT_SPINNER); match deploy_option { Deploy2ContractsOption::All => { - deploy_l2_contracts( - shell, - &chain_config, - &ecosystem_config, - &mut contracts, - args, - ) - .await?; + deploy_l2_contracts(shell, &chain, era_chain_id, &wallets, &mut contracts, args) + .await?; } Deploy2ContractsOption::Upgrader => { - deploy_upgrader( - shell, - &chain_config, - &ecosystem_config, - &mut contracts, - args, - ) - .await?; + deploy_upgrader(shell, &chain, era_chain_id, &wallets, &mut contracts, args).await?; } Deploy2ContractsOption::ConsensusRegistry => { - deploy_consensus_registry( - shell, - &chain_config, - &ecosystem_config, - &mut contracts, - args, - ) - .await?; + deploy_consensus_registry(shell, &chain, era_chain_id, &wallets, &mut contracts, args) + .await?; } Deploy2ContractsOption::Multicall3 => { - deploy_multicall3( - shell, - &chain_config, - &ecosystem_config, - &mut contracts, - args, - ) - .await?; + deploy_multicall3(shell, &chain, era_chain_id, &wallets, &mut contracts, args).await?; } Deploy2ContractsOption::TimestampAsserter => { - deploy_timestamp_asserter( - shell, - &chain_config, - &ecosystem_config, - &mut contracts, - args, - ) - .await?; + deploy_timestamp_asserter(shell, &chain, era_chain_id, &wallets, &mut contracts, args) + .await?; } Deploy2ContractsOption::InitiailizeBridges => { - initialize_bridges( - shell, - &chain_config, - &ecosystem_config, - &mut contracts, - args, - ) - .await? + initialize_bridges(shell, &chain, era_chain_id, &wallets, &mut contracts, args).await? } } - contracts.save_with_base_path(shell, &chain_config.configs)?; + contracts.save_with_base_path(shell, &chain.configs)?; spinner.finish(); Ok(()) @@ -128,13 +85,22 @@ pub async fn run( async fn build_and_deploy( shell: &Shell, chain_config: &ChainConfig, - ecosystem_config: &EcosystemConfig, + era_chain_id: L2ChainId, + wallets: &WalletsConfig, forge_args: ForgeScriptArgs, signature: Option<&str>, mut update_config: impl FnMut(&Shell, &Path) -> anyhow::Result<()>, ) -> anyhow::Result<()> { - build_l2_contracts(shell.clone(), ecosystem_config.link_to_code.clone())?; - call_forge(shell, chain_config, ecosystem_config, forge_args, signature).await?; + build_l2_contracts(shell.clone(), chain_config.link_to_code.clone())?; + call_forge( + shell, + chain_config, + era_chain_id, + wallets, + forge_args, + signature, + ) + .await?; update_config( shell, &DEPLOY_L2_CONTRACTS_SCRIPT_PARAMS.output(&chain_config.link_to_code), @@ -145,7 +111,8 @@ async fn build_and_deploy( pub async fn initialize_bridges( shell: &Shell, chain_config: &ChainConfig, - ecosystem_config: &EcosystemConfig, + era_chain_id: L2ChainId, + wallets: &WalletsConfig, contracts_config: &mut ContractsConfig, forge_args: ForgeScriptArgs, ) -> anyhow::Result<()> { @@ -157,7 +124,8 @@ pub async fn initialize_bridges( build_and_deploy( shell, chain_config, - ecosystem_config, + era_chain_id, + wallets, forge_args, signature, |shell, out| { @@ -170,14 +138,16 @@ pub async fn initialize_bridges( pub async fn deploy_upgrader( shell: &Shell, chain_config: &ChainConfig, - ecosystem_config: &EcosystemConfig, + era_chain_id: L2ChainId, + wallets: &WalletsConfig, contracts_config: &mut ContractsConfig, forge_args: ForgeScriptArgs, ) -> anyhow::Result<()> { build_and_deploy( shell, chain_config, - ecosystem_config, + era_chain_id, + wallets, forge_args, Some("runDefaultUpgrader"), |shell, out| { @@ -190,14 +160,16 @@ pub async fn deploy_upgrader( pub async fn deploy_consensus_registry( shell: &Shell, chain_config: &ChainConfig, - ecosystem_config: &EcosystemConfig, + era_chain_id: L2ChainId, + wallets: &WalletsConfig, contracts_config: &mut ContractsConfig, forge_args: ForgeScriptArgs, ) -> anyhow::Result<()> { build_and_deploy( shell, chain_config, - ecosystem_config, + era_chain_id, + wallets, forge_args, Some("runDeployConsensusRegistry"), |shell, out| { @@ -210,14 +182,16 @@ pub async fn deploy_consensus_registry( pub async fn deploy_multicall3( shell: &Shell, chain_config: &ChainConfig, - ecosystem_config: &EcosystemConfig, + era_chain_id: L2ChainId, + wallets: &WalletsConfig, contracts_config: &mut ContractsConfig, forge_args: ForgeScriptArgs, ) -> anyhow::Result<()> { build_and_deploy( shell, chain_config, - ecosystem_config, + era_chain_id, + wallets, forge_args, Some("runDeployMulticall3"), |shell, out| contracts_config.set_multicall3(&Multicall3Output::read(shell, out)?), @@ -228,14 +202,16 @@ pub async fn deploy_multicall3( pub async fn deploy_timestamp_asserter( shell: &Shell, chain_config: &ChainConfig, - ecosystem_config: &EcosystemConfig, + era_chain_id: L2ChainId, + wallets: &WalletsConfig, contracts_config: &mut ContractsConfig, forge_args: ForgeScriptArgs, ) -> anyhow::Result<()> { build_and_deploy( shell, chain_config, - ecosystem_config, + era_chain_id, + wallets, forge_args, Some("runDeployTimestampAsserter"), |shell, out| { @@ -249,7 +225,8 @@ pub async fn deploy_timestamp_asserter( pub async fn deploy_l2_contracts( shell: &Shell, chain_config: &ChainConfig, - ecosystem_config: &EcosystemConfig, + era_chain_id: L2ChainId, + wallets: &WalletsConfig, contracts_config: &mut ContractsConfig, forge_args: ForgeScriptArgs, ) -> anyhow::Result<()> { @@ -261,7 +238,8 @@ pub async fn deploy_l2_contracts( build_and_deploy( shell, chain_config, - ecosystem_config, + era_chain_id, + wallets, forge_args, signature, |shell, out| { @@ -280,11 +258,12 @@ pub async fn deploy_l2_contracts( async fn call_forge( shell: &Shell, chain_config: &ChainConfig, - ecosystem_config: &EcosystemConfig, + era_chain_id: L2ChainId, + wallets: &WalletsConfig, forge_args: ForgeScriptArgs, signature: Option<&str>, ) -> anyhow::Result<()> { - let input = DeployL2ContractsInput::new(chain_config, ecosystem_config.era_chain_id)?; + let input = DeployL2ContractsInput::new(chain_config, era_chain_id)?; let foundry_contracts_path = chain_config.path_to_foundry(); let secrets = chain_config.get_secrets_config()?; input.save( @@ -312,7 +291,7 @@ async fn call_forge( forge = forge.with_signature(signature); } - forge = fill_forge_private_key(forge, Some(&ecosystem_config.get_wallets()?.governor))?; + forge = fill_forge_private_key(forge, Some(&wallets.governor))?; check_the_balance(&forge).await?; forge.run(shell)?; diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/init/configs.rs b/zkstack_cli/crates/zkstack/src/commands/chain/init/configs.rs index 83873ecffc0c..baa05fdd86fd 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/init/configs.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/init/configs.rs @@ -1,8 +1,9 @@ use anyhow::Context; use common::logger; use config::{ - copy_configs, set_l1_rpc_url, traits::SaveConfigWithBasePath, update_from_chain_config, - zkstack_config::ZkStackConfig, ChainConfig, ContractsConfig, EcosystemConfig, + copy_configs, set_l1_rpc_url, + traits::{ReadConfig, SaveConfigWithBasePath}, + update_from_chain_config, ChainConfig, ContractsConfig, EcosystemConfig, }; use ethers::types::Address; use xshell::Shell; @@ -16,7 +17,7 @@ use crate::{ portal::update_portal_config, }, messages::{ - MSG_CHAIN_CONFIGS_INITIALIZED, MSG_CHAIN_NOT_FOUND_ERR, MSG_CONSENSUS_CONFIG_MISSING_ERR, + MSG_CHAIN_CONFIGS_INITIALIZED, MSG_CONSENSUS_CONFIG_MISSING_ERR, MSG_PORTAL_FAILED_TO_CREATE_CONFIG_ERR, }, utils::{ @@ -25,14 +26,15 @@ use crate::{ }, }; -pub async fn run(args: InitConfigsArgs, shell: &Shell) -> anyhow::Result<()> { - let ecosystem_config = ZkStackConfig::ecosystem(shell)?; - let chain_config = ecosystem_config - .load_current_chain() - .context(MSG_CHAIN_NOT_FOUND_ERR)?; - let args = args.fill_values_with_prompt(&chain_config); +pub async fn run( + args: InitConfigsArgs, + shell: &Shell, + chain: ChainConfig, + ecosystem: Option, +) -> anyhow::Result<()> { + let args = args.fill_values_with_prompt(ecosystem, &chain)?; - init_configs(&args, shell, &ecosystem_config, &chain_config).await?; + init_configs(&args, shell, &chain).await?; logger::outro(MSG_CHAIN_CONFIGS_INITIALIZED); Ok(()) @@ -41,15 +43,14 @@ pub async fn run(args: InitConfigsArgs, shell: &Shell) -> anyhow::Result<()> { pub async fn init_configs( init_args: &InitConfigsArgsFinal, shell: &Shell, - ecosystem_config: &EcosystemConfig, chain_config: &ChainConfig, ) -> anyhow::Result { // Port scanner should run before copying configs to avoid marking initial ports as assigned - let mut ecosystem_ports = EcosystemPortsScanner::scan(shell)?; - copy_configs(shell, &ecosystem_config.link_to_code, &chain_config.configs)?; + let ecosystem_ports = EcosystemPortsScanner::scan(shell); + copy_configs(shell, &chain_config.link_to_code, &chain_config.configs)?; if !init_args.no_port_reallocation { - ecosystem_ports.allocate_ports_in_yaml( + ecosystem_ports?.allocate_ports_in_yaml( shell, &chain_config.path_to_general_config(), chain_config.id, @@ -85,7 +86,7 @@ pub async fn init_configs( genesis_config.save_with_base_path(shell, &chain_config.configs)?; // Initialize contracts config - let mut contracts_config = ecosystem_config.get_contracts_config()?; + let mut contracts_config = ContractsConfig::read(shell, &init_args.ecosystem_contracts_path)?; contracts_config.l1.diamond_proxy_addr = Address::zero(); contracts_config.l1.governance_addr = Address::zero(); contracts_config.l1.chain_admin_addr = Address::zero(); diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/init/mod.rs b/zkstack_cli/crates/zkstack/src/commands/chain/init/mod.rs index 5759e7783f14..51f2d5c615b0 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/init/mod.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/init/mod.rs @@ -2,7 +2,9 @@ use anyhow::Context; use clap::{command, Parser, Subcommand}; use common::{git, logger, spinner::Spinner}; use config::{ - traits::SaveConfigWithBasePath, zkstack_config::ZkStackConfig, ChainConfig, EcosystemConfig, + get_default_era_chain_id, + traits::{ReadConfig, SaveConfigWithBasePath}, + ChainConfig, EcosystemConfig, WalletsConfig, }; use types::BaseToken; use xshell::Shell; @@ -24,9 +26,9 @@ use crate::{ }, messages::{ msg_initializing_chain, MSG_ACCEPTING_ADMIN_SPINNER, MSG_CHAIN_INITIALIZED, - MSG_CHAIN_NOT_FOUND_ERR, MSG_DEPLOYING_PAYMASTER, MSG_GENESIS_DATABASE_ERR, - MSG_REGISTERING_CHAIN_SPINNER, MSG_SELECTED_CONFIG, - MSG_UPDATING_TOKEN_MULTIPLIER_SETTER_SPINNER, MSG_WALLET_TOKEN_MULTIPLIER_SETTER_NOT_FOUND, + MSG_DEPLOYING_PAYMASTER, MSG_GENESIS_DATABASE_ERR, MSG_REGISTERING_CHAIN_SPINNER, + MSG_SELECTED_CONFIG, MSG_UPDATING_TOKEN_MULTIPLIER_SETTER_SPINNER, + MSG_WALLETS_CONFIG_MUST_BE_PRESENT, MSG_WALLET_TOKEN_MULTIPLIER_SETTER_NOT_FOUND, }, }; @@ -48,25 +50,33 @@ pub struct ChainInitCommand { args: InitArgs, } -pub(crate) async fn run(args: ChainInitCommand, shell: &Shell) -> anyhow::Result<()> { +pub(crate) async fn run( + args: ChainInitCommand, + shell: &Shell, + chain: ChainConfig, + ecosystem: Option, +) -> anyhow::Result<()> { match args.command { - Some(ChainInitSubcommands::Configs(args)) => configs::run(args, shell).await, - None => run_init(args.args, shell).await, + Some(ChainInitSubcommands::Configs(args)) => { + configs::run(args, shell, chain, ecosystem).await + } + None => run_init(args.args, shell, chain, ecosystem).await, } } -async fn run_init(args: InitArgs, shell: &Shell) -> anyhow::Result<()> { - let config = ZkStackConfig::ecosystem(shell)?; - let chain_config = config - .load_current_chain() - .context(MSG_CHAIN_NOT_FOUND_ERR)?; - let args = args.fill_values_with_prompt(&chain_config); +async fn run_init( + args: InitArgs, + shell: &Shell, + chain: ChainConfig, + ecosystem: Option, +) -> anyhow::Result<()> { + let args = args.fill_values_with_prompt(ecosystem.clone(), &chain)?; - logger::note(MSG_SELECTED_CONFIG, logger::object_to_string(&chain_config)); + logger::note(MSG_SELECTED_CONFIG, logger::object_to_string(&chain)); logger::info(msg_initializing_chain("")); - git::submodule_update(shell, config.link_to_code.clone())?; + git::submodule_update(shell, chain.link_to_code.clone())?; - init(&args, shell, &config, &chain_config).await?; + init(&args, shell, ecosystem, &chain).await?; logger::success(MSG_CHAIN_INITIALIZED); Ok(()) @@ -75,26 +85,29 @@ async fn run_init(args: InitArgs, shell: &Shell) -> anyhow::Result<()> { pub async fn init( init_args: &InitArgsFinal, shell: &Shell, - ecosystem_config: &EcosystemConfig, + ecosystem: Option, chain_config: &ChainConfig, ) -> anyhow::Result<()> { // Initialize configs - let init_configs_args = InitConfigsArgsFinal::from_chain_init_args(init_args); - let mut contracts_config = - init_configs(&init_configs_args, shell, ecosystem_config, chain_config).await?; + let mut init_configs_args = InitConfigsArgsFinal::from_chain_init_args(init_args); + if ecosystem.is_none() { + init_configs_args.no_port_reallocation = true; + } + let mut contracts_config = init_configs(&init_configs_args, shell, chain_config).await?; + let wallets = WalletsConfig::read(shell, init_args.wallets_path.clone())?; // Fund some wallet addresses with ETH or base token (only for Localhost) - distribute_eth(ecosystem_config, chain_config, init_args.l1_rpc_url.clone()).await?; - mint_base_token(ecosystem_config, chain_config, init_args.l1_rpc_url.clone()).await?; + distribute_eth(chain_config, init_args.l1_rpc_url.clone(), &wallets).await?; + mint_base_token(chain_config, init_args.l1_rpc_url.clone(), &wallets).await?; // Register chain on BridgeHub (run by L1 Governor) let spinner = Spinner::new(MSG_REGISTERING_CHAIN_SPINNER); register_chain( shell, init_args.forge_args.clone(), - ecosystem_config, chain_config, &mut contracts_config, + &wallets, init_args.l1_rpc_url.clone(), None, true, @@ -107,7 +120,7 @@ pub async fn init( let spinner = Spinner::new(MSG_ACCEPTING_ADMIN_SPINNER); accept_admin( shell, - ecosystem_config, + &chain_config.path_to_foundry(), contracts_config.l1.chain_admin_addr, &chain_config.get_wallets_config()?.governor, contracts_config.l1.diamond_proxy_addr, @@ -122,12 +135,12 @@ pub async fn init( let spinner = Spinner::new(MSG_UPDATING_TOKEN_MULTIPLIER_SETTER_SPINNER); set_token_multiplier_setter( shell, - ecosystem_config, + &chain_config.path_to_foundry(), &chain_config.get_wallets_config()?.governor, contracts_config.l1.chain_admin_addr, chain_config .get_wallets_config() - .unwrap() + .context(MSG_WALLETS_CONFIG_MUST_BE_PRESENT)? .token_multiplier_setter .context(MSG_WALLET_TOKEN_MULTIPLIER_SETTER_NOT_FOUND)? .address, @@ -139,10 +152,15 @@ pub async fn init( } // Deploy L2 contracts: L2SharedBridge, L2DefaultUpgrader, ... (run by L1 Governor) + let era_chain_id = ecosystem + .as_ref() + .map(|ecosystem| ecosystem.era_chain_id) + .unwrap_or(get_default_era_chain_id()); deploy_l2_contracts::deploy_l2_contracts( shell, chain_config, - ecosystem_config, + era_chain_id, + &wallets, &mut contracts_config, init_args.forge_args.clone(), ) @@ -154,7 +172,7 @@ pub async fn init( setup_legacy_bridge( shell, chain_config, - ecosystem_config, + &wallets, &contracts_config, init_args.forge_args.clone(), ) diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/mod.rs b/zkstack_cli/crates/zkstack/src/commands/chain/mod.rs index 5d0c39851baf..0260cc630713 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/mod.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/mod.rs @@ -14,7 +14,7 @@ use crate::{ args::create::ChainCreateArgs, deploy_l2_contracts::Deploy2ContractsOption, genesis::GenesisCommand, init::ChainInitCommand, }, - messages::MSG_CHAIN_NOT_FOUND_ERR, + messages::{MSG_CHAIN_NOT_FOUND_ERR, MSG_ECOSYSTEM_CONFIG_INVALID_ERR}, }; mod accept_chain_ownership; @@ -91,38 +91,85 @@ pub(crate) async fn run(shell: &Shell, cmd: ChainCommands) -> anyhow::Result<()> } let chain = ZkStackConfig::current_chain(shell).context(MSG_CHAIN_NOT_FOUND_ERR)?; + let ecosystem = ZkStackConfig::ecosystem(shell).ok(); match cmd { - ChainCommands::Create(args) => create::run(args, shell), - ChainCommands::Init(args) => init::run(*args, shell).await, - ChainCommands::BuildTransactions(args) => build_transactions::run(args, shell).await, + ChainCommands::Init(args) => init::run(*args, shell, chain, ecosystem).await, + ChainCommands::BuildTransactions(args) => { + build_transactions::run(args, shell, chain, ecosystem).await + } ChainCommands::Genesis(args) => genesis::run(args, shell, chain).await, ChainCommands::RegisterChain(args) => register_chain::run(args, shell).await, ChainCommands::DeployL2Contracts(args) => { - deploy_l2_contracts::run(args, shell, Deploy2ContractsOption::All).await + deploy_l2_contracts::run( + args, + shell, + Deploy2ContractsOption::All, + chain, + ecosystem.context(MSG_ECOSYSTEM_CONFIG_INVALID_ERR)?, + ) + .await + } + ChainCommands::AcceptChainOwnership(args) => { + accept_chain_ownership::run(args, shell, chain).await } - ChainCommands::AcceptChainOwnership(args) => accept_chain_ownership::run(args, shell).await, ChainCommands::DeployConsensusRegistry(args) => { - deploy_l2_contracts::run(args, shell, Deploy2ContractsOption::ConsensusRegistry).await + deploy_l2_contracts::run( + args, + shell, + Deploy2ContractsOption::ConsensusRegistry, + chain, + ecosystem.context(MSG_ECOSYSTEM_CONFIG_INVALID_ERR)?, + ) + .await } ChainCommands::DeployMulticall3(args) => { - deploy_l2_contracts::run(args, shell, Deploy2ContractsOption::Multicall3).await + deploy_l2_contracts::run( + args, + shell, + Deploy2ContractsOption::Multicall3, + chain, + ecosystem.context(MSG_ECOSYSTEM_CONFIG_INVALID_ERR)?, + ) + .await } ChainCommands::DeployTimestampAsserter(args) => { - deploy_l2_contracts::run(args, shell, Deploy2ContractsOption::TimestampAsserter).await + deploy_l2_contracts::run( + args, + shell, + Deploy2ContractsOption::TimestampAsserter, + chain, + ecosystem.context(MSG_ECOSYSTEM_CONFIG_INVALID_ERR)?, + ) + .await } ChainCommands::DeployUpgrader(args) => { - deploy_l2_contracts::run(args, shell, Deploy2ContractsOption::Upgrader).await + deploy_l2_contracts::run( + args, + shell, + Deploy2ContractsOption::Upgrader, + chain, + ecosystem.context(MSG_ECOSYSTEM_CONFIG_INVALID_ERR)?, + ) + .await } ChainCommands::InitializeBridges(args) => { - deploy_l2_contracts::run(args, shell, Deploy2ContractsOption::InitiailizeBridges).await + deploy_l2_contracts::run( + args, + shell, + Deploy2ContractsOption::InitiailizeBridges, + chain, + ecosystem.context(MSG_ECOSYSTEM_CONFIG_INVALID_ERR)?, + ) + .await } ChainCommands::DeployPaymaster(args) => deploy_paymaster::run(args, shell, chain).await, ChainCommands::UpdateTokenMultiplierSetter(args) => { - set_token_multiplier_setter::run(args, shell).await + set_token_multiplier_setter::run(args, shell, chain).await } ChainCommands::Server(args) => server::run(shell, args, chain).await, ChainCommands::ContractVerifier(args) => contract_verifier::run(shell, args, chain).await, ChainCommands::Consensus(cmd) => cmd.run(shell).await, + ChainCommands::Create(_) => unreachable!("Chain create is handled before loading chain"), } } diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/register_chain.rs b/zkstack_cli/crates/zkstack/src/commands/chain/register_chain.rs index 08a38fdf9018..a94cd59d2b36 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/register_chain.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/register_chain.rs @@ -11,7 +11,7 @@ use config::{ }, traits::{ReadConfig, SaveConfig, SaveConfigWithBasePath}, zkstack_config::ZkStackConfig, - ChainConfig, ContractsConfig, EcosystemConfig, + ChainConfig, ContractsConfig, WalletsConfig, }; use xshell::Shell; @@ -29,6 +29,7 @@ pub async fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { .load_current_chain() .context(MSG_CHAIN_NOT_INITIALIZED)?; let mut contracts = chain_config.get_contracts_config()?; + let wallets = ecosystem_config.get_wallets()?; let secrets = chain_config.get_secrets_config()?; let l1_rpc_url = secrets .l1 @@ -40,9 +41,9 @@ pub async fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { register_chain( shell, args, - &ecosystem_config, &chain_config, &mut contracts, + &wallets, l1_rpc_url, None, true, @@ -58,19 +59,19 @@ pub async fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { pub async fn register_chain( shell: &Shell, forge_args: ForgeScriptArgs, - config: &EcosystemConfig, chain_config: &ChainConfig, contracts: &mut ContractsConfig, + wallets: &WalletsConfig, l1_rpc_url: String, sender: Option, broadcast: bool, ) -> anyhow::Result<()> { - let deploy_config_path = REGISTER_CHAIN_SCRIPT_PARAMS.input(&config.link_to_code); + let deploy_config_path = REGISTER_CHAIN_SCRIPT_PARAMS.input(&chain_config.link_to_code); let deploy_config = RegisterChainL1Config::new(chain_config, contracts)?; deploy_config.save(shell, deploy_config_path)?; - let mut forge = Forge::new(&config.path_to_foundry()) + let mut forge = Forge::new(&chain_config.path_to_foundry()) .script(®ISTER_CHAIN_SCRIPT_PARAMS.script(), forge_args.clone()) .with_ffi() .with_rpc_url(l1_rpc_url); @@ -82,7 +83,7 @@ pub async fn register_chain( if let Some(address) = sender { forge = forge.with_sender(address); } else { - forge = fill_forge_private_key(forge, Some(&config.get_wallets()?.governor))?; + forge = fill_forge_private_key(forge, Some(&wallets.governor))?; check_the_balance(&forge).await?; } diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/set_token_multiplier_setter.rs b/zkstack_cli/crates/zkstack/src/commands/chain/set_token_multiplier_setter.rs index 36ddc4b6f07a..aa52d3e86be1 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/set_token_multiplier_setter.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/set_token_multiplier_setter.rs @@ -1,3 +1,5 @@ +use std::path::Path; + use anyhow::Context; use common::{ forge::{Forge, ForgeScript, ForgeScriptArgs}, @@ -5,10 +7,7 @@ use common::{ spinner::Spinner, wallets::Wallet, }; -use config::{ - forge_interface::script_params::ACCEPT_GOVERNANCE_SCRIPT_PARAMS, zkstack_config::ZkStackConfig, - EcosystemConfig, -}; +use config::{forge_interface::script_params::ACCEPT_GOVERNANCE_SCRIPT_PARAMS, ChainConfig}; use ethers::{abi::parse_abi, contract::BaseContract, utils::hex}; use lazy_static::lazy_static; use xshell::Shell; @@ -16,9 +15,9 @@ use zksync_basic_types::Address; use crate::{ messages::{ - MSG_CHAIN_NOT_INITIALIZED, MSG_L1_SECRETS_MUST_BE_PRESENTED, - MSG_TOKEN_MULTIPLIER_SETTER_UPDATED_TO, MSG_UPDATING_TOKEN_MULTIPLIER_SETTER_SPINNER, - MSG_WALLETS_CONFIG_MUST_BE_PRESENT, MSG_WALLET_TOKEN_MULTIPLIER_SETTER_NOT_FOUND, + MSG_L1_SECRETS_MUST_BE_PRESENTED, MSG_TOKEN_MULTIPLIER_SETTER_UPDATED_TO, + MSG_UPDATING_TOKEN_MULTIPLIER_SETTER_SPINNER, MSG_WALLETS_CONFIG_MUST_BE_PRESENT, + MSG_WALLET_TOKEN_MULTIPLIER_SETTER_NOT_FOUND, }, utils::forge::{check_the_balance, fill_forge_private_key}, }; @@ -32,20 +31,16 @@ lazy_static! { ); } -pub async fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { - let ecosystem_config = ZkStackConfig::ecosystem(shell)?; - let chain_config = ecosystem_config - .load_current_chain() - .context(MSG_CHAIN_NOT_INITIALIZED)?; - let contracts_config = chain_config.get_contracts_config()?; - let l1_url = chain_config +pub async fn run(args: ForgeScriptArgs, shell: &Shell, chain: ChainConfig) -> anyhow::Result<()> { + let contracts_config = chain.get_contracts_config()?; + let l1_url = chain .get_secrets_config()? .l1 .context(MSG_L1_SECRETS_MUST_BE_PRESENTED)? .l1_rpc_url .expose_str() .to_string(); - let token_multiplier_setter_address = chain_config + let token_multiplier_setter_address = chain .get_wallets_config() .context(MSG_WALLETS_CONFIG_MUST_BE_PRESENT)? .token_multiplier_setter @@ -55,8 +50,8 @@ pub async fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { let spinner = Spinner::new(MSG_UPDATING_TOKEN_MULTIPLIER_SETTER_SPINNER); set_token_multiplier_setter( shell, - &ecosystem_config, - &chain_config.get_wallets_config()?.governor, + &chain.path_to_foundry(), + &chain.get_wallets_config()?.governor, contracts_config.l1.chain_admin_addr, token_multiplier_setter_address, &args.clone(), @@ -75,7 +70,7 @@ pub async fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { pub async fn set_token_multiplier_setter( shell: &Shell, - ecosystem_config: &EcosystemConfig, + foundry_contracts_path: &Path, governor: &Wallet, chain_admin_address: Address, target_address: Address, @@ -94,8 +89,7 @@ pub async fn set_token_multiplier_setter( (chain_admin_address, target_address), ) .unwrap(); - let foundry_contracts_path = ecosystem_config.path_to_foundry(); - let forge = Forge::new(&foundry_contracts_path) + let forge = Forge::new(foundry_contracts_path) .script( &ACCEPT_GOVERNANCE_SCRIPT_PARAMS.script(), forge_args.clone(), diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/setup_legacy_bridge.rs b/zkstack_cli/crates/zkstack/src/commands/chain/setup_legacy_bridge.rs index f61c640ffb6b..2aa341693784 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/setup_legacy_bridge.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/setup_legacy_bridge.rs @@ -8,7 +8,7 @@ use config::{ script_params::SETUP_LEGACY_BRIDGE, setup_legacy_bridge::SetupLegacyBridgeInput, }, traits::SaveConfig, - ChainConfig, ContractsConfig, EcosystemConfig, + ChainConfig, ContractsConfig, WalletsConfig, }; use xshell::Shell; @@ -20,7 +20,7 @@ use crate::{ pub async fn setup_legacy_bridge( shell: &Shell, chain_config: &ChainConfig, - ecosystem_config: &EcosystemConfig, + wallets: &WalletsConfig, contracts_config: &ContractsConfig, forge_args: ForgeScriptArgs, ) -> anyhow::Result<()> { @@ -59,7 +59,7 @@ pub async fn setup_legacy_bridge( ) .with_broadcast(); - forge = fill_forge_private_key(forge, Some(&ecosystem_config.get_wallets()?.governor))?; + forge = fill_forge_private_key(forge, Some(&wallets.governor))?; let spinner = Spinner::new(MSG_DEPLOYING_PAYMASTER); check_the_balance(&forge).await?; diff --git a/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/create.rs b/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/create.rs index 53d9c27be60b..05cfeafd4752 100644 --- a/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/create.rs +++ b/zkstack_cli/crates/zkstack/src/commands/ecosystem/args/create.rs @@ -2,6 +2,7 @@ use std::path::PathBuf; use clap::{Parser, ValueHint}; use common::{Prompt, PromptConfirm, PromptSelect}; +use config::get_default_era_chain_id; use serde::{Deserialize, Serialize}; use slugify_rs::slugify; use strum::IntoEnumIterator; @@ -52,9 +53,20 @@ impl EcosystemCreateArgs { // Make the only chain as a default one self.chain.set_as_default = Some(true); - let chain = - self.chain - .fill_values_with_prompt(0, &l1_network, vec![], link_to_code.clone())?; + let chains_path = PathBuf::from("chains"); + + let era_chain_id = get_default_era_chain_id(); + + let chain = self.chain.fill_values_with_prompt( + shell, + 0, + 1, + Some(l1_network), + vec![], + Some(link_to_code.clone()), + Some(chains_path), + era_chain_id, + )?; let start_containers = self.start_containers.unwrap_or_else(|| { PromptConfirm::new(MSG_START_CONTAINERS_PROMPT) diff --git a/zkstack_cli/crates/zkstack/src/commands/ecosystem/create.rs b/zkstack_cli/crates/zkstack/src/commands/ecosystem/create.rs index 7d766d859f7c..f39ad90bbe97 100644 --- a/zkstack_cli/crates/zkstack/src/commands/ecosystem/create.rs +++ b/zkstack_cli/crates/zkstack/src/commands/ecosystem/create.rs @@ -62,7 +62,8 @@ fn create(args: EcosystemCreateArgs, shell: &Shell) -> anyhow::Result<()> { let link_to_code = resolve_link_to_code(shell, shell.current_dir(), args.link_to_code.clone())?; let spinner = Spinner::new(MSG_CREATING_INITIAL_CONFIGURATIONS_SPINNER); - let chain_config = args.chain_config(); + let mut chain_config = args.chain_config(); + chain_config.link_to_code = link_to_code.display().to_string(); let chains_path = shell.create_dir("chains")?; let default_chain_name = args.chain_args.chain_name.clone(); @@ -97,7 +98,7 @@ fn create(args: EcosystemCreateArgs, shell: &Shell) -> anyhow::Result<()> { spinner.finish(); let spinner = Spinner::new(MSG_CREATING_DEFAULT_CHAIN_SPINNER); - create_chain_inner(chain_config, &ecosystem_config, shell)?; + create_chain_inner(chain_config, shell)?; spinner.finish(); if args.start_containers { diff --git a/zkstack_cli/crates/zkstack/src/commands/ecosystem/init.rs b/zkstack_cli/crates/zkstack/src/commands/ecosystem/init.rs index 3c7e729e29b7..c0da87b139af 100644 --- a/zkstack_cli/crates/zkstack/src/commands/ecosystem/init.rs +++ b/zkstack_cli/crates/zkstack/src/commands/ecosystem/init.rs @@ -186,33 +186,11 @@ async fn deploy_ecosystem( let ecosystem_contracts_path = match &ecosystem.ecosystem_contracts_path { Some(path) => Some(path.clone()), - None => { - let input_path: String = Prompt::new(MSG_ECOSYSTEM_CONTRACTS_PATH_PROMPT) - .allow_empty() - .validate_with(|val: &String| { - if val.is_empty() { - return Ok(()); - } - PathBuf::from_str(val) - .map(|_| ()) - .map_err(|_| MSG_ECOSYSTEM_CONTRACTS_PATH_INVALID_ERR.to_string()) - }) - .ask(); - if input_path.is_empty() { - None - } else { - Some(input_path.into()) - } - } + None => prompt_ecosystem_contracts_path(), }; let ecosystem_preexisting_configs_path = - ecosystem_config - .get_preexisting_configs_path() - .join(format!( - "{}.yaml", - ecosystem_config.l1_network.to_string().to_lowercase() - )); + ecosystem_config.get_preexisting_ecosystem_contracts_path(); // currently there are not some preexisting ecosystem contracts in // chains, so we need check if this file exists. @@ -235,6 +213,25 @@ async fn deploy_ecosystem( ContractsConfig::read(shell, ecosystem_contracts_path) } +pub fn prompt_ecosystem_contracts_path() -> Option { + let input_path: String = Prompt::new(MSG_ECOSYSTEM_CONTRACTS_PATH_PROMPT) + .allow_empty() + .validate_with(|val: &String| { + if val.is_empty() { + return Ok(()); + } + PathBuf::from_str(val) + .map(|_| ()) + .map_err(|_| MSG_ECOSYSTEM_CONTRACTS_PATH_INVALID_ERR.to_string()) + }) + .ask(); + if input_path.is_empty() { + None + } else { + Some(input_path.into()) + } +} + async fn deploy_ecosystem_inner( shell: &Shell, forge_args: ForgeScriptArgs, @@ -268,7 +265,7 @@ async fn deploy_ecosystem_inner( accept_admin( shell, - config, + &config.path_to_foundry(), contracts_config.l1.chain_admin_addr, &config.get_wallets()?.governor, contracts_config.ecosystem_contracts.bridgehub_proxy_addr, @@ -290,7 +287,7 @@ async fn deploy_ecosystem_inner( accept_admin( shell, - config, + &config.path_to_foundry(), contracts_config.l1.chain_admin_addr, &config.get_wallets()?.governor, contracts_config.bridges.shared.l1_address, @@ -314,7 +311,7 @@ async fn deploy_ecosystem_inner( accept_admin( shell, - config, + &config.path_to_foundry(), contracts_config.l1.chain_admin_addr, &config.get_wallets()?.governor, contracts_config @@ -351,6 +348,13 @@ async fn init_chains( if list_of_chains.len() > 1 { genesis_args.reset_db_names(); } + let ecosystem_contracts_path = + Some(ecosystem_config.get_contracts_path().display().to_string()); + let wallets_path = Some(ecosystem_config.get_wallets_path().display().to_string()); + logger::debug(format!( + "Ecosystem contracts path: {:?}", + ecosystem_contracts_path + )); // Initialize chains for chain_name in &list_of_chains { logger::info(msg_initializing_chain(chain_name)); @@ -367,13 +371,16 @@ async fn init_chains( l1_rpc_url: Some(final_init_args.ecosystem.l1_rpc_url.clone()), no_port_reallocation: final_init_args.no_port_reallocation, dev: final_init_args.dev, + ecosystem_contracts_path: ecosystem_contracts_path.clone(), + wallets_path: wallets_path.clone(), }; - let final_chain_init_args = chain_init_args.fill_values_with_prompt(&chain_config); + let final_chain_init_args = chain_init_args + .fill_values_with_prompt(Some(ecosystem_config.clone()), &chain_config)?; chain::init::init( &final_chain_init_args, shell, - ecosystem_config, + Some(ecosystem_config.clone()), &chain_config, ) .await?; diff --git a/zkstack_cli/crates/zkstack/src/messages.rs b/zkstack_cli/crates/zkstack/src/messages.rs index bedcb233b19f..efde52169044 100644 --- a/zkstack_cli/crates/zkstack/src/messages.rs +++ b/zkstack_cli/crates/zkstack/src/messages.rs @@ -61,6 +61,8 @@ pub(super) fn msg_path_to_zksync_does_not_exist_err(path: &str) -> String { } /// Ecosystem and chain init related messages +pub(super) const MSG_ECOSYSTEM_CONTRACTS_PATH_HELP: &str = "Ecosystem contracts path"; +pub(super) const MSG_WALLETS_PATH_HELP: &str = "Wallets path"; pub(super) const MSG_L1_RPC_URL_HELP: &str = "L1 RPC URL"; pub(super) const MSG_NO_PORT_REALLOCATION_HELP: &str = "Do not reallocate ports"; pub(super) const MSG_GENESIS_ARGS_HELP: &str = "Genesis options"; @@ -102,6 +104,8 @@ pub(super) const MSG_RECREATE_ROCKS_DB_ERRROR: &str = "Failed to create rocks db pub(super) const MSG_ERA_OBSERVABILITY_ALREADY_SETUP: &str = "Era observability already setup"; pub(super) const MSG_DOWNLOADING_ERA_OBSERVABILITY_SPINNER: &str = "Downloading era observability..."; +pub(super) const MSG_WALLETS_PATH_PROMPT: &str = + "Provide the path to L1 wallets config. It should contain governance and operator wallets."; pub(super) fn msg_ecosystem_no_found_preexisting_contract(chains: &str) -> String { format!("Not found preexisting ecosystem Contracts with chains {chains}")