diff --git a/zkstack_cli/crates/config/src/forge_interface/enable_evm_emulator/mod.rs b/zkstack_cli/crates/config/src/forge_interface/enable_evm_emulator/mod.rs new file mode 100644 index 000000000000..61c794afe600 --- /dev/null +++ b/zkstack_cli/crates/config/src/forge_interface/enable_evm_emulator/mod.rs @@ -0,0 +1,12 @@ +use ethers::types::Address; +use serde::{Deserialize, Serialize}; + +use crate::traits::ZkStackConfig; + +impl ZkStackConfig for EnableEvmEmulatorInput {} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct EnableEvmEmulatorInput { + pub target_addr: Address, + pub governor: Address, +} diff --git a/zkstack_cli/crates/config/src/forge_interface/script_params.rs b/zkstack_cli/crates/config/src/forge_interface/script_params.rs index e7e21ad132b8..fd8d353f87f5 100644 --- a/zkstack_cli/crates/config/src/forge_interface/script_params.rs +++ b/zkstack_cli/crates/config/src/forge_interface/script_params.rs @@ -67,3 +67,10 @@ pub const SETUP_LEGACY_BRIDGE: ForgeScriptParams = ForgeScriptParams { output: "script-out/setup-legacy-bridge.toml", script_path: "deploy-scripts/dev/SetupLegacyBridge.s.sol", }; + +pub const ENABLE_EVM_EMULATOR_PARAMS: ForgeScriptParams = ForgeScriptParams { + input: "script-config/enable-evm-emulator.toml", + output: "script-out/output-enable-evm-emulator.toml", + script_path: "deploy-scripts/EnableEvmEmulator.s.sol", +}; + diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/enable_evm_emulator.rs b/zkstack_cli/crates/zkstack/src/commands/chain/enable_evm_emulator.rs new file mode 100644 index 000000000000..b20822c3a890 --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/commands/chain/enable_evm_emulator.rs @@ -0,0 +1,40 @@ +use anyhow::Context; +use common::{forge::ForgeScriptArgs, logger, spinner::Spinner}; +use config::EcosystemConfig; +use xshell::Shell; + +use crate::{ + enable_evm_emulator::enable_evm_emulator, + messages::{ + MSG_ENABLING_EVM_EMULATOR, MSG_CHAIN_NOT_INITIALIZED, MSG_EVM_EMULATOR_ENABLED, + MSG_L1_SECRETS_MUST_BE_PRESENTED, + }, +}; + +pub async fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { + let ecosystem_config = EcosystemConfig::from_file(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()?; + let l1_rpc_url = secrets + .l1 + .context(MSG_L1_SECRETS_MUST_BE_PRESENTED)? + .l1_rpc_url + .expose_str() + .to_string(); + + enable_evm_emulator( + shell, + &ecosystem_config, + contracts.l1.chain_admin_addr, + &chain_config.get_wallets_config()?.governor, + contracts.l1.diamond_proxy_addr, + &args, + l1_rpc_url.clone(), + ) + .await?; + logger::success(MSG_EVM_EMULATOR_ENABLED); + Ok(()) +} 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 d92c56d2eb10..a48f44b48066 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/init/mod.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/init/mod.rs @@ -7,6 +7,7 @@ use xshell::Shell; use crate::{ accept_ownership::accept_admin, + enable_evm_emulator::enable_evm_emulator, commands::chain::{ args::init::{ configs::{InitConfigsArgs, InitConfigsArgsFinal}, @@ -21,7 +22,7 @@ use crate::{ setup_legacy_bridge::setup_legacy_bridge, }, messages::{ - msg_initializing_chain, MSG_ACCEPTING_ADMIN_SPINNER, MSG_CHAIN_INITIALIZED, + msg_initializing_chain, MSG_ACCEPTING_ADMIN_SPINNER, MSG_CHAIN_INITIALIZED, MSG_ENABLING_EVM_EMULATOR, 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, @@ -136,6 +137,20 @@ pub async fn init( spinner.finish(); } + // Enable EVM emulation if needed (run by L2 Governor) + if chain_config.evm_emulator { + enable_evm_emulator( + shell, + ecosystem_config, + contracts_config.l1.chain_admin_addr, + &chain_config.get_wallets_config()?.governor, + contracts_config.l1.diamond_proxy_addr, + &init_args.forge_args.clone(), + init_args.l1_rpc_url.clone(), + ) + .await?; + } + // Deploy L2 contracts: L2SharedBridge, L2DefaultUpgrader, ... (run by L1 Governor) deploy_l2_contracts::deploy_l2_contracts( shell, diff --git a/zkstack_cli/crates/zkstack/src/commands/chain/mod.rs b/zkstack_cli/crates/zkstack/src/commands/chain/mod.rs index 82b8656154ab..9c696c15719d 100644 --- a/zkstack_cli/crates/zkstack/src/commands/chain/mod.rs +++ b/zkstack_cli/crates/zkstack/src/commands/chain/mod.rs @@ -11,6 +11,7 @@ use crate::commands::chain::{ }; mod accept_chain_ownership; +mod enable_evm_emulator; pub(crate) mod args; mod build_transactions; mod common; diff --git a/zkstack_cli/crates/zkstack/src/enable_evm_emulator.rs b/zkstack_cli/crates/zkstack/src/enable_evm_emulator.rs new file mode 100644 index 000000000000..93cacf66e55c --- /dev/null +++ b/zkstack_cli/crates/zkstack/src/enable_evm_emulator.rs @@ -0,0 +1,67 @@ +use common::{ + forge::{Forge, ForgeScript, ForgeScriptArgs}, + spinner::Spinner, + wallets::Wallet, +}; +use config::{forge_interface::script_params::ENABLE_EVM_EMULATOR_PARAMS, EcosystemConfig}; +use ethers::{abi::parse_abi, contract::BaseContract, types::Address}; +use lazy_static::lazy_static; +use xshell::Shell; + +use crate::{ + messages::MSG_ENABLING_EVM_EMULATOR, + utils::forge::{check_the_balance, fill_forge_private_key, WalletOwner}, +}; + +lazy_static! { + static ref ENABLE_EVM_EMULATOR: BaseContract = BaseContract::from( + parse_abi(&[ + "function chainAllowEvmEmulation(address chainAdmin, address target) public", + ]) + .unwrap(), + ); +} + +pub async fn enable_evm_emulator( + shell: &Shell, + ecosystem_config: &EcosystemConfig, + admin: Address, + governor: &Wallet, + target_address: Address, + forge_args: &ForgeScriptArgs, + l1_rpc_url: String, +) -> anyhow::Result<()> { + // Resume for accept admin doesn't work properly. Foundry assumes that if signature of the function is the same, + // than it's the same call, but because we are calling this function multiple times during the init process, + // code assumes that doing only once is enough, but actually we need to accept admin multiple times + let mut forge_args = forge_args.clone(); + forge_args.resume = false; + + let calldata = ENABLE_EVM_EMULATOR + .encode("chainAllowEvmEmulation", (admin, target_address)) + .unwrap(); + let foundry_contracts_path = ecosystem_config.path_to_foundry(); + let forge = Forge::new(&foundry_contracts_path) + .script( + &ENABLE_EVM_EMULATOR_PARAMS.script(), + forge_args.clone(), + ) + .with_ffi() + .with_rpc_url(l1_rpc_url) + .with_broadcast() + .with_calldata(&calldata); + enable_evm_inner(shell, governor, forge).await +} + +async fn enable_evm_inner( + shell: &Shell, + governor: &Wallet, + mut forge: ForgeScript, +) -> anyhow::Result<()> { + forge = fill_forge_private_key(forge, Some(governor), WalletOwner::Governor)?; + check_the_balance(&forge).await?; + let spinner = Spinner::new(MSG_ENABLING_EVM_EMULATOR); + forge.run(shell)?; + spinner.finish(); + Ok(()) +} diff --git a/zkstack_cli/crates/zkstack/src/main.rs b/zkstack_cli/crates/zkstack/src/main.rs index 8a115201fc81..2009e50a6b58 100644 --- a/zkstack_cli/crates/zkstack/src/main.rs +++ b/zkstack_cli/crates/zkstack/src/main.rs @@ -20,6 +20,7 @@ use crate::commands::{ }; pub mod accept_ownership; +pub mod enable_evm_emulator; mod commands; mod consts; mod defaults; diff --git a/zkstack_cli/crates/zkstack/src/messages.rs b/zkstack_cli/crates/zkstack/src/messages.rs index 14b89be773f1..b2b5c1a3f68f 100644 --- a/zkstack_cli/crates/zkstack/src/messages.rs +++ b/zkstack_cli/crates/zkstack/src/messages.rs @@ -85,6 +85,8 @@ pub(super) const MSG_CHAIN_INITIALIZED: &str = "Chain initialized successfully"; pub(super) const MSG_CHAIN_CONFIGS_INITIALIZED: &str = "Chain configs were initialized"; pub(super) const MSG_CHAIN_OWNERSHIP_TRANSFERRED: &str = "Chain ownership was transferred successfully"; +pub(super) const MSG_EVM_EMULATOR_ENABLED: &str = + "EVM emulator enabled successfully"; pub(super) const MSG_CHAIN_REGISTERED: &str = "Chain registraion was successful"; pub(super) const MSG_DISTRIBUTING_ETH_SPINNER: &str = "Distributing eth..."; pub(super) const MSG_MINT_BASE_TOKEN_SPINNER: &str = @@ -272,6 +274,9 @@ pub(super) const MSG_SERVER_URING_HELP: &str = "Enables uring support for RocksD /// Accept ownership related messages pub(super) const MSG_ACCEPTING_GOVERNANCE_SPINNER: &str = "Accepting governance..."; +/// EVM emulator related messages +pub(super) const MSG_ENABLING_EVM_EMULATOR: &str = "Enabling EVM emulator..."; + /// Containers related messages pub(super) const MSG_STARTING_CONTAINERS: &str = "Starting containers"; pub(super) const MSG_STARTING_DOCKER_CONTAINERS_SPINNER: &str =