diff --git a/etc/env/file_based/wallets/mainnet.yaml b/etc/env/file_based/wallets/mainnet.yaml new file mode 100644 index 00000000000..0e533a7028b --- /dev/null +++ b/etc/env/file_based/wallets/mainnet.yaml @@ -0,0 +1,20 @@ +# Wallets for the ecosystem with official Mainnet shared bridge +# All L1 transactions needs to be approved and executed by MatterLabs team +deployer: + address: 0x0000000000000000000000000000000000000000 + private_key: 0x0000000000000000000000000000000000000000000000000000000000000000 +operator: + address: 0x0000000000000000000000000000000000000000 + private_key: 0x0000000000000000000000000000000000000000000000000000000000000000 +blob_operator: + address: 0x0000000000000000000000000000000000000000 + private_key: 0x0000000000000000000000000000000000000000000000000000000000000000 +fee_account: + address: 0x0000000000000000000000000000000000000000 + private_key: 0x0000000000000000000000000000000000000000000000000000000000000000 +governor: + address: 0x0000000000000000000000000000000000000000 + private_key: 0x0000000000000000000000000000000000000000000000000000000000000000 +token_multiplier_setter: + address: 0x0000000000000000000000000000000000000000 + private_key: 0x0000000000000000000000000000000000000000000000000000000000000000 diff --git a/etc/env/file_based/wallets/sepolia.yaml b/etc/env/file_based/wallets/sepolia.yaml new file mode 100644 index 00000000000..744728738b6 --- /dev/null +++ b/etc/env/file_based/wallets/sepolia.yaml @@ -0,0 +1,20 @@ +# Wallets for the ecosystem with official Sepolia shared bridge +# All L1 transactions needs to be approved and executed by MatterLabs team +deployer: + address: 0x0000000000000000000000000000000000000000 + private_key: 0x0000000000000000000000000000000000000000000000000000000000000000 +operator: + address: 0x0000000000000000000000000000000000000000 + private_key: 0x0000000000000000000000000000000000000000000000000000000000000000 +blob_operator: + address: 0x0000000000000000000000000000000000000000 + private_key: 0x0000000000000000000000000000000000000000000000000000000000000000 +fee_account: + address: 0x0000000000000000000000000000000000000000 + private_key: 0x0000000000000000000000000000000000000000000000000000000000000000 +governor: + address: 0xd64e136566a9e04eb05b30184ff577f52682d182 + private_key: 0x0000000000000000000000000000000000000000000000000000000000000000 +token_multiplier_setter: + address: 0x0000000000000000000000000000000000000000 + private_key: 0x0000000000000000000000000000000000000000000000000000000000000000 diff --git a/zk_toolbox/crates/config/src/consts.rs b/zk_toolbox/crates/config/src/consts.rs index 80b204cc619..89146998c58 100644 --- a/zk_toolbox/crates/config/src/consts.rs +++ b/zk_toolbox/crates/config/src/consts.rs @@ -26,6 +26,9 @@ pub const ZKSYNC_ERA_GIT_REPO: &str = "https://github.com/matter-labs/zksync-era pub const DOCKER_COMPOSE_FILE: &str = "docker-compose.yml"; /// Path to the config file with mnemonic for localhost wallets pub(crate) const CONFIGS_PATH: &str = "etc/env/file_based"; +pub(crate) const WALLETS_DIR: &str = "wallets/"; +pub const MAINNET_FILE: &str = "mainnet.yaml"; +pub const SEPOLIA_FILE: &str = "sepolia.yaml"; /// Path to the docker-compose file for grafana pub const ERA_OBSERVABILITY_COMPOSE_FILE: &str = "era-observability/docker-compose.yml"; /// Path to era observability repository @@ -73,12 +76,14 @@ pub const EXPLORER_WORKER_DOCKER_IMAGE: &str = "matterlabs/block-explorer-worker pub const EXPLORER_BATCHES_PROCESSING_POLLING_INTERVAL: u64 = 1000; /// Path to ecosystem contacts -pub(crate) const ECOSYSTEM_PATH: &str = "etc/env/ecosystems"; +pub const ECOSYSTEM_PATH: &str = "etc/env/ecosystems"; /// Path to l1 contracts foundry folder inside zksync-era pub(crate) const L1_CONTRACTS_FOUNDRY: &str = "contracts/l1-contracts"; pub(crate) const ERA_CHAIN_ID: u32 = 270; +pub(crate) const ZKSYNC_MAINNET_CHAIN_ID: u32 = 324; +pub(crate) const ZKSYNC_SEPOLIA_CHAIN_ID: u32 = 300; pub(crate) const TEST_CONFIG_PATH: &str = "etc/test_config/constant/eth.json"; pub(crate) const BASE_PATH: &str = "m/44'/60'/0'"; diff --git a/zk_toolbox/crates/config/src/ecosystem.rs b/zk_toolbox/crates/config/src/ecosystem.rs index 7ff65d4612d..3eec393d444 100644 --- a/zk_toolbox/crates/config/src/ecosystem.rs +++ b/zk_toolbox/crates/config/src/ecosystem.rs @@ -14,7 +14,8 @@ 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, + LOCAL_ARTIFACTS_PATH, LOCAL_DB_PATH, WALLETS_FILE, ZKSYNC_MAINNET_CHAIN_ID, + ZKSYNC_SEPOLIA_CHAIN_ID, }, create_localhost_wallets, forge_interface::deploy_ecosystem::{ @@ -278,6 +279,14 @@ pub fn get_default_era_chain_id() -> L2ChainId { L2ChainId::from(ERA_CHAIN_ID) } +pub fn get_official_zksync_chain_id(network: L1Network) -> anyhow::Result { + match network { + L1Network::Mainnet => Ok(L2ChainId::from(ZKSYNC_MAINNET_CHAIN_ID)), + L1Network::Sepolia => Ok(L2ChainId::from(ZKSYNC_SEPOLIA_CHAIN_ID)), + _ => anyhow::bail!("Unsupported network"), + } +} + // Find file in all parents repository and return necessary path or an empty error if nothing has been found fn find_file(shell: &Shell, path_buf: PathBuf, file_name: &str) -> Result { let _dir = shell.push_dir(path_buf); diff --git a/zk_toolbox/crates/config/src/wallet_creation.rs b/zk_toolbox/crates/config/src/wallet_creation.rs index 6cfdf08a36d..65ff3718df2 100644 --- a/zk_toolbox/crates/config/src/wallet_creation.rs +++ b/zk_toolbox/crates/config/src/wallet_creation.rs @@ -2,11 +2,11 @@ use std::path::{Path, PathBuf}; use common::wallets::Wallet; use rand::thread_rng; -use types::WalletCreation; +use types::{L1Network, WalletCreation}; use xshell::Shell; use crate::{ - consts::{BASE_PATH, TEST_CONFIG_PATH}, + consts::{BASE_PATH, CONFIGS_PATH, MAINNET_FILE, SEPOLIA_FILE, TEST_CONFIG_PATH, WALLETS_DIR}, traits::{ReadConfig, SaveConfigWithBasePath}, EthMnemonicConfig, WalletsConfig, }; @@ -65,3 +65,20 @@ pub fn create_localhost_wallets( )?), }) } + +pub fn copy_official_zksync_wallets( + shell: &Shell, + base_path: &Path, + link_to_code: &Path, + network: L1Network, +) -> anyhow::Result<()> { + let path = link_to_code.join(CONFIGS_PATH).join(WALLETS_DIR); + let wallets_path = match network { + L1Network::Mainnet => path.join(MAINNET_FILE), + L1Network::Sepolia => path.join(SEPOLIA_FILE), + _ => anyhow::bail!("Official bridge is only available for sepolia and mainnet"), + }; + let wallets = WalletsConfig::read(shell, wallets_path)?; + wallets.save_with_base_path(shell, base_path)?; + Ok(()) +} diff --git a/zk_toolbox/crates/zk_inception/src/commands/chain/args/create.rs b/zk_toolbox/crates/zk_inception/src/commands/chain/args/create.rs index 3ea15d10f8b..5fc46c1b227 100644 --- a/zk_toolbox/crates/zk_inception/src/commands/chain/args/create.rs +++ b/zk_toolbox/crates/zk_inception/src/commands/chain/args/create.rs @@ -127,7 +127,7 @@ impl ChainCreateArgs { .ask() }); - let wallet_path: Option = if self.wallet_creation == Some(WalletCreation::InFile) { + let wallet_path: Option = if wallet_creation == WalletCreation::InFile { Some(self.wallet_path.unwrap_or_else(|| { Prompt::new(MSG_WALLET_PATH_PROMPT) .validate_with(|val: &String| { diff --git a/zk_toolbox/crates/zk_inception/src/commands/chain/args/init.rs b/zk_toolbox/crates/zk_inception/src/commands/chain/args/init.rs index 9dd6c490bd7..969c663ec7d 100644 --- a/zk_toolbox/crates/zk_inception/src/commands/chain/args/init.rs +++ b/zk_toolbox/crates/zk_inception/src/commands/chain/args/init.rs @@ -57,6 +57,18 @@ pub struct InitArgs { pub l1_rpc_url: Option, #[clap(long, help = MSG_PORT_OFFSET_HELP)] pub port_offset: Option, + #[arg( + long, + help = "Adhoc flag to run chain registraion from L1 side", + default_value_t = false + )] + pub only_l1: bool, + #[arg( + long, + help = "Adhoc flag to continue chain registraion from L2 side", + default_value_t = false + )] + pub only_l2: bool, } impl InitArgs { @@ -90,6 +102,8 @@ impl InitArgs { .port_offset .unwrap_or(PortOffset::from_chain_id(config.id as u16)) .into(), + only_l1: self.only_l1, + only_l2: self.only_l2, } } } @@ -101,4 +115,6 @@ pub struct InitArgsFinal { pub deploy_paymaster: bool, pub l1_rpc_url: String, pub port_offset: u16, + pub only_l1: bool, + pub only_l2: bool, } diff --git a/zk_toolbox/crates/zk_inception/src/commands/chain/init.rs b/zk_toolbox/crates/zk_inception/src/commands/chain/init.rs index 734e5e54863..8a9b97ec04a 100644 --- a/zk_toolbox/crates/zk_inception/src/commands/chain/init.rs +++ b/zk_toolbox/crates/zk_inception/src/commands/chain/init.rs @@ -69,7 +69,9 @@ pub async fn init( ecosystem_config: &EcosystemConfig, chain_config: &ChainConfig, ) -> anyhow::Result<()> { - copy_configs(shell, &ecosystem_config.link_to_code, &chain_config.configs)?; + if !init_args.only_l2 { + copy_configs(shell, &ecosystem_config.link_to_code, &chain_config.configs)?; + } let mut general_config = chain_config.get_general_config()?; apply_port_offset(init_args.port_offset, &mut general_config)?; @@ -85,11 +87,6 @@ pub async fn init( update_from_chain_config(&mut genesis_config, chain_config); genesis_config.save_with_base_path(shell, &chain_config.configs)?; - // Copy ecosystem contracts - let mut contracts_config = ecosystem_config.get_contracts_config()?; - contracts_config.l1.base_token_addr = chain_config.base_token.address; - contracts_config.save_with_base_path(shell, &chain_config.configs)?; - 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?; @@ -98,18 +95,60 @@ pub async fn init( secrets.consensus = Some(get_consensus_secrets(&consensus_keys)); secrets.save_with_base_path(shell, &chain_config.configs)?; - let spinner = Spinner::new(MSG_REGISTERING_CHAIN_SPINNER); - register_chain( - shell, - init_args.forge_args.clone(), - ecosystem_config, - chain_config, - &mut contracts_config, - init_args.l1_rpc_url.clone(), - ) - .await?; + // Create or copy contracts config + let mut contracts_config = if !init_args.only_l2 { + let mut config = ecosystem_config.get_contracts_config()?; + config.l1.base_token_addr = chain_config.base_token.address; + config + } else { + chain_config.get_contracts_config()? + }; contracts_config.save_with_base_path(shell, &chain_config.configs)?; - spinner.finish(); + + if !init_args.only_l2 { + // Register chain on L1 (signed 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, + init_args.l1_rpc_url.clone(), + ) + .await?; + contracts_config.save_with_base_path(shell, &chain_config.configs)?; + spinner.finish(); + + // Deploy L2 contracts (signed by L1 governor) + deploy_l2_contracts::deploy_l2_contracts( + shell, + chain_config, + ecosystem_config, + &mut contracts_config, + init_args.forge_args.clone(), + ) + .await?; + contracts_config.save_with_base_path(shell, &chain_config.configs)?; + + // Setup legacy bridge (signed by L1 governor) + if let Some(true) = chain_config.legacy_bridge { + setup_legacy_bridge( + shell, + chain_config, + ecosystem_config, + &contracts_config, + init_args.forge_args.clone(), + ) + .await?; + } + + if init_args.only_l1 { + return Ok(()); + } + } + + // Accept admin ownership of the chain (signed by L2 governor) let spinner = Spinner::new(MSG_ACCEPTING_ADMIN_SPINNER); accept_admin( shell, @@ -123,6 +162,7 @@ pub async fn init( .await?; spinner.finish(); + // Set token multiplier setter (signed by L2 governor) if chain_config.base_token != BaseToken::eth() { let spinner = Spinner::new(MSG_UPDATING_TOKEN_MULTIPLIER_SETTER_SPINNER); set_token_multiplier_setter( @@ -143,27 +183,6 @@ pub async fn init( spinner.finish(); } - deploy_l2_contracts::deploy_l2_contracts( - shell, - chain_config, - ecosystem_config, - &mut contracts_config, - init_args.forge_args.clone(), - ) - .await?; - contracts_config.save_with_base_path(shell, &chain_config.configs)?; - - if let Some(true) = chain_config.legacy_bridge { - setup_legacy_bridge( - shell, - chain_config, - ecosystem_config, - &contracts_config, - init_args.forge_args.clone(), - ) - .await?; - } - if init_args.deploy_paymaster { deploy_paymaster::deploy_paymaster( shell, diff --git a/zk_toolbox/crates/zk_inception/src/commands/ecosystem/args/create.rs b/zk_toolbox/crates/zk_inception/src/commands/ecosystem/args/create.rs index 2e5c50f4538..6af95d9e833 100644 --- a/zk_toolbox/crates/zk_inception/src/commands/ecosystem/args/create.rs +++ b/zk_toolbox/crates/zk_inception/src/commands/ecosystem/args/create.rs @@ -17,6 +17,7 @@ use crate::{ MSG_LINK_TO_CODE_HELP, MSG_LINK_TO_CODE_PROMPT, MSG_LINK_TO_CODE_SELECTION_CLONE, MSG_LINK_TO_CODE_SELECTION_PATH, MSG_NOT_MAIN_REPO_OR_FORK_ERR, MSG_REPOSITORY_ORIGIN_PROMPT, MSG_START_CONTAINERS_HELP, MSG_START_CONTAINERS_PROMPT, + MSG_USE_OFFICIAL_BRIDGE_HELP, MSG_USE_OFFICIAL_BRIDGE_INVALID_L1_ERR, }, }; @@ -31,6 +32,8 @@ pub struct EcosystemCreateArgs { #[clap(flatten)] #[serde(flatten)] pub chain: ChainCreateArgs, + #[arg(long, help = MSG_USE_OFFICIAL_BRIDGE_HELP, default_value_t = false)] + pub use_official_bridge: bool, #[clap( long, help = MSG_START_CONTAINERS_HELP, default_missing_value = "true", num_args = 0..=1 )] @@ -68,6 +71,11 @@ impl EcosystemCreateArgs { let l1_network = self .l1_network .unwrap_or_else(|| PromptSelect::new(MSG_L1_NETWORK_PROMPT, L1Network::iter()).ask()); + if self.use_official_bridge + && (l1_network != L1Network::Sepolia && l1_network != L1Network::Mainnet) + { + bail!(MSG_USE_OFFICIAL_BRIDGE_INVALID_L1_ERR); + } // Make the only chain as a default one self.chain.set_as_default = Some(true); @@ -87,6 +95,7 @@ impl EcosystemCreateArgs { wallet_path: chain.wallet_path.clone(), chain_args: chain, start_containers, + use_official_bridge: self.use_official_bridge, }) } } @@ -100,6 +109,7 @@ pub struct EcosystemCreateArgsFinal { pub wallet_path: Option, pub chain_args: ChainCreateArgsFinal, pub start_containers: bool, + pub use_official_bridge: bool, } impl EcosystemCreateArgsFinal { diff --git a/zk_toolbox/crates/zk_inception/src/commands/ecosystem/create.rs b/zk_toolbox/crates/zk_inception/src/commands/ecosystem/create.rs index 356b5322980..89919c9b449 100644 --- a/zk_toolbox/crates/zk_inception/src/commands/ecosystem/create.rs +++ b/zk_toolbox/crates/zk_inception/src/commands/ecosystem/create.rs @@ -3,9 +3,9 @@ use std::{path::PathBuf, str::FromStr}; use anyhow::{bail, Context}; use common::{git, logger, spinner::Spinner}; use config::{ - create_local_configs_dir, create_wallets, get_default_era_chain_id, - traits::SaveConfigWithBasePath, EcosystemConfig, EcosystemConfigFromFileError, - ZKSYNC_ERA_GIT_REPO, + copy_official_zksync_wallets, create_local_configs_dir, create_wallets, + get_default_era_chain_id, get_official_zksync_chain_id, traits::SaveConfigWithBasePath, + EcosystemConfig, EcosystemConfigFromFileError, ZKSYNC_ERA_GIT_REPO, }; use xshell::Shell; @@ -16,7 +16,7 @@ use crate::{ ecosystem::{ args::create::EcosystemCreateArgs, create_configs::{ - create_apps_config, create_erc20_deployment_config, + copy_official_zksync_contracts, create_apps_config, create_erc20_deployment_config, create_initial_deployments_config, }, }, @@ -80,6 +80,10 @@ fn create(args: EcosystemCreateArgs, shell: &Shell) -> anyhow::Result<()> { create_erc20_deployment_config(shell, &configs_path)?; create_apps_config(shell, &configs_path)?; + let mut zksync_chain_id = get_default_era_chain_id(); + if args.use_official_bridge { + zksync_chain_id = get_official_zksync_chain_id(args.l1_network)?; + } let ecosystem_config = EcosystemConfig { name: ecosystem_name.clone(), l1_network: args.l1_network, @@ -87,22 +91,37 @@ fn create(args: EcosystemCreateArgs, shell: &Shell) -> anyhow::Result<()> { bellman_cuda_dir: None, chains: chains_path.clone(), config: configs_path, - era_chain_id: get_default_era_chain_id(), + era_chain_id: zksync_chain_id, default_chain: default_chain_name.clone(), prover_version: chain_config.prover_version, wallet_creation: args.wallet_creation, shell: shell.clone().into(), }; - // Use 0 id for ecosystem wallets - create_wallets( - shell, - &ecosystem_config.config, - &ecosystem_config.link_to_code, - 0, - args.wallet_creation, - args.wallet_path, - )?; + if args.use_official_bridge { + copy_official_zksync_wallets( + shell, + &ecosystem_config.config, + &ecosystem_config.link_to_code, + args.l1_network, + )?; + copy_official_zksync_contracts( + shell, + &ecosystem_config.config, + &ecosystem_config.link_to_code, + args.l1_network, + )?; + } else { + // Use 0 id for ecosystem wallets + create_wallets( + shell, + &ecosystem_config.config, + &ecosystem_config.link_to_code, + 0, + args.wallet_creation, + args.wallet_path, + )?; + } ecosystem_config.save_with_base_path(shell, ".")?; spinner.finish(); diff --git a/zk_toolbox/crates/zk_inception/src/commands/ecosystem/create_configs.rs b/zk_toolbox/crates/zk_inception/src/commands/ecosystem/create_configs.rs index 38358355ff9..93ff0864b10 100644 --- a/zk_toolbox/crates/zk_inception/src/commands/ecosystem/create_configs.rs +++ b/zk_toolbox/crates/zk_inception/src/commands/ecosystem/create_configs.rs @@ -2,9 +2,10 @@ use std::path::Path; use config::{ forge_interface::deploy_ecosystem::input::{Erc20DeploymentConfig, InitialDeploymentConfig}, - traits::{SaveConfigWithBasePath, SaveConfigWithCommentAndBasePath}, - AppsEcosystemConfig, + traits::{ReadConfig, SaveConfigWithBasePath, SaveConfigWithCommentAndBasePath}, + AppsEcosystemConfig, ContractsConfig, ECOSYSTEM_PATH, MAINNET_FILE, SEPOLIA_FILE, }; +use types::L1Network; use xshell::Shell; use crate::messages::{MSG_SAVE_ERC20_CONFIG_ATTENTION, MSG_SAVE_INITIAL_CONFIG_ATTENTION}; @@ -43,3 +44,20 @@ pub fn create_apps_config( config.save_with_base_path(shell, ecosystem_configs_path)?; Ok(config) } + +pub fn copy_official_zksync_contracts( + shell: &Shell, + base_path: &Path, + link_to_code: &Path, + network: L1Network, +) -> anyhow::Result<()> { + let path = link_to_code.join(ECOSYSTEM_PATH); + let contracts_path = match network { + L1Network::Mainnet => path.join(MAINNET_FILE), + L1Network::Sepolia => path.join(SEPOLIA_FILE), + _ => anyhow::bail!("Official bridge is only available for sepolia and mainnet"), + }; + let contracts = ContractsConfig::read(shell, contracts_path)?; + contracts.save_with_base_path(shell, base_path)?; + Ok(()) +} diff --git a/zk_toolbox/crates/zk_inception/src/commands/ecosystem/init.rs b/zk_toolbox/crates/zk_inception/src/commands/ecosystem/init.rs index 7d34437ef2d..e022dc574f4 100644 --- a/zk_toolbox/crates/zk_inception/src/commands/ecosystem/init.rs +++ b/zk_toolbox/crates/zk_inception/src/commands/ecosystem/init.rs @@ -120,6 +120,8 @@ pub async fn run(args: EcosystemInitArgs, shell: &Shell) -> anyhow::Result<()> { deploy_paymaster: final_ecosystem_args.deploy_paymaster, l1_rpc_url: final_ecosystem_args.ecosystem.l1_rpc_url.clone(), port_offset: PortOffset::from_chain_id(chain_config.id as u16).into(), + only_l1: false, + only_l2: false, }; chain::init::init( diff --git a/zk_toolbox/crates/zk_inception/src/messages.rs b/zk_toolbox/crates/zk_inception/src/messages.rs index c5b77f63eba..a4477791b46 100644 --- a/zk_toolbox/crates/zk_inception/src/messages.rs +++ b/zk_toolbox/crates/zk_inception/src/messages.rs @@ -27,6 +27,9 @@ pub(super) const MSG_L1_NETWORK_PROMPT: &str = "Select the L1 network"; pub(super) const MSG_START_CONTAINERS_PROMPT: &str = "Do you want to start containers after creating the ecosystem?"; pub(super) const MSG_CREATING_ECOSYSTEM: &str = "Creating ecosystem"; +pub(super) const MSG_USE_OFFICIAL_BRIDGE_HELP: &str = "Use official bridge (for sepolia or mainnet). Requires approval and chain registration on L1 by MatterLabs."; +pub(super) const MSG_USE_OFFICIAL_BRIDGE_INVALID_L1_ERR: &str = + "Official bridge is only available for sepolia and mainnet"; pub fn msg_created_ecosystem(name: &str) -> String { format!("Ecosystem {name} created successfully (All subsequent commands should be executed from ecosystem folder `cd {name}`)")