From 924267e769c3299b4ed7f8d240b29cfe5e9d8fd6 Mon Sep 17 00:00:00 2001 From: Danil Date: Wed, 22 May 2024 14:01:10 +0200 Subject: [PATCH 1/3] fix(toolbox): Temporary disable fast mode for deploying l1 contracts for reth Signed-off-by: Danil --- .../crates/zk_inception/src/commands/ecosystem/init.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 869ed48308d0..1132c4ae8461 100644 --- a/zk_toolbox/crates/zk_inception/src/commands/ecosystem/init.rs +++ b/zk_toolbox/crates/zk_inception/src/commands/ecosystem/init.rs @@ -281,8 +281,12 @@ fn deploy_ecosystem_inner( .script(&DEPLOY_ECOSYSTEM.script(), forge_args.clone()) .with_ffi() .with_rpc_url(config.l1_rpc_url.clone()) - .with_broadcast() - .with_slow(); + .with_broadcast(); + + if config.l1_network == L1Network::Localhost { + // It's a kludge for reth, just because it doesn't behave properly with large amount of txs + forge = forge.with_slow(); + } forge = fill_forge_private_key(forge, wallets_config.deployer_private_key())?; From edf33d6196440225c6dbb59eff0ea5d9c8dd7c46 Mon Sep 17 00:00:00 2001 From: Danil Date: Wed, 22 May 2024 15:44:04 +0200 Subject: [PATCH 2/3] feat(zk-toolbox): Add balance check Signed-off-by: Danil --- zk_toolbox/crates/common/src/ethereum.rs | 18 ++++++--- zk_toolbox/crates/common/src/forge.rs | 38 +++++++++++++++++++ .../crates/common/src/prompt/confirm.rs | 3 +- .../zk_inception/src/accept_ownership.rs | 10 +++-- .../src/commands/chain/deploy_paymaster.rs | 8 ++-- .../zk_inception/src/commands/chain/init.rs | 12 ++++-- .../src/commands/chain/initialize_bridges.rs | 8 ++-- .../zk_inception/src/commands/chain/mod.rs | 4 +- .../src/commands/ecosystem/init.rs | 29 +++++++++----- zk_toolbox/crates/zk_inception/src/consts.rs | 2 + .../crates/zk_inception/src/forge_utils.rs | 19 ++++++++++ 11 files changed, 120 insertions(+), 31 deletions(-) diff --git a/zk_toolbox/crates/common/src/ethereum.rs b/zk_toolbox/crates/common/src/ethereum.rs index 7771b7500d4f..a3bb611d48d5 100644 --- a/zk_toolbox/crates/common/src/ethereum.rs +++ b/zk_toolbox/crates/common/src/ethereum.rs @@ -1,14 +1,25 @@ use std::{ops::Add, time::Duration}; use ethers::{ + core::k256::ecdsa::SigningKey, middleware::MiddlewareBuilder, - prelude::{Http, LocalWallet, Provider, Signer}, + prelude::{Http, LocalWallet, Provider}, + prelude::{SignerMiddleware, H256}, providers::Middleware, types::{Address, TransactionRequest}, }; use crate::wallets::Wallet; +pub fn create_ethers_client( + private_key: H256, + l1_rpc: String, +) -> anyhow::Result, ethers::prelude::Wallet>> { + let wallet = LocalWallet::from_bytes(private_key.as_bytes())?; + let client = Provider::::try_from(l1_rpc)?.with_signer(wallet); + Ok(client) +} + pub async fn distribute_eth( main_wallet: Wallet, addresses: Vec
, @@ -16,10 +27,7 @@ pub async fn distribute_eth( chain_id: u32, amount: u128, ) -> anyhow::Result<()> { - let wallet = LocalWallet::from_bytes(main_wallet.private_key.unwrap().as_bytes())? - .with_chain_id(chain_id); - let client = Provider::::try_from(l1_rpc)?.with_signer(wallet); - + let client = create_ethers_client(main_wallet.private_key.unwrap(), l1_rpc)?; let mut pending_txs = vec![]; let mut nonce = client.get_transaction_count(client.address(), None).await?; for address in addresses { diff --git a/zk_toolbox/crates/common/src/forge.rs b/zk_toolbox/crates/common/src/forge.rs index ac2d9252ba22..e6db788b02dd 100644 --- a/zk_toolbox/crates/common/src/forge.rs +++ b/zk_toolbox/crates/common/src/forge.rs @@ -1,12 +1,17 @@ use std::path::{Path, PathBuf}; +use std::str::FromStr; use clap::Parser; +use ethers::abi::Address; +use ethers::middleware::Middleware; +use ethers::prelude::U256; use ethers::{abi::AbiEncode, types::H256}; use serde::{Deserialize, Serialize}; use strum_macros::Display; use xshell::{cmd, Shell}; use crate::cmd::Cmd; +use crate::ethereum::create_ethers_client; /// Forge is a wrapper around the forge binary. pub struct Forge { @@ -93,6 +98,39 @@ impl ForgeScript { }); self } + // Do not start the script if balance is not enough + pub fn private_key(&self) -> Option { + self.args.args.iter().find_map(|a| { + if let ForgeScriptArg::PrivateKey { private_key } = a { + Some(H256::from_str(private_key).unwrap()) + } else { + None + } + }) + } + + pub fn rpc_url(&self) -> Option { + self.args.args.iter().find_map(|a| { + if let ForgeScriptArg::RpcUrl { url } = a { + Some(url.clone()) + } else { + None + } + }) + } + + pub async fn check_the_balance(&self, minimum_value: U256) -> anyhow::Result<(bool, Address)> { + let Some(rpc_url) = self.rpc_url() else { + return Ok((true, Address::zero())); + }; + let Some(private_key) = self.private_key() else { + return Ok((true, Address::zero())); + }; + let client = create_ethers_client(private_key, rpc_url)?; + let address = client.address(); + let balance = client.get_balance(client.address(), None).await?; + Ok((balance > minimum_value, address)) + } } const PROHIBITED_ARGS: [&str; 10] = [ diff --git a/zk_toolbox/crates/common/src/prompt/confirm.rs b/zk_toolbox/crates/common/src/prompt/confirm.rs index 19239c31c799..195654e7d65a 100644 --- a/zk_toolbox/crates/common/src/prompt/confirm.rs +++ b/zk_toolbox/crates/common/src/prompt/confirm.rs @@ -1,11 +1,12 @@ use cliclack::Confirm; +use std::fmt::Display; pub struct PromptConfirm { inner: Confirm, } impl PromptConfirm { - pub fn new(question: &str) -> Self { + pub fn new(question: impl Display) -> Self { Self { inner: Confirm::new(question), } diff --git a/zk_toolbox/crates/zk_inception/src/accept_ownership.rs b/zk_toolbox/crates/zk_inception/src/accept_ownership.rs index 420c4efcaa88..932666db70be 100644 --- a/zk_toolbox/crates/zk_inception/src/accept_ownership.rs +++ b/zk_toolbox/crates/zk_inception/src/accept_ownership.rs @@ -5,6 +5,7 @@ use common::{ use ethers::{abi::Address, types::H256}; use xshell::Shell; +use crate::forge_utils::check_the_balance; use crate::{ configs::{ forge_interface::accept_ownership::AcceptOwnershipInput, EcosystemConfig, SaveConfig, @@ -13,7 +14,7 @@ use crate::{ forge_utils::fill_forge_private_key, }; -pub fn accept_admin( +pub async fn accept_admin( shell: &Shell, ecosystem_config: &EcosystemConfig, governor_contract: Address, @@ -36,9 +37,10 @@ pub fn accept_admin( target_address, forge, ) + .await } -pub fn accept_owner( +pub async fn accept_owner( shell: &Shell, ecosystem_config: &EcosystemConfig, governor_contract: Address, @@ -61,9 +63,10 @@ pub fn accept_owner( target_address, forge, ) + .await } -fn accept_ownership( +async fn accept_ownership( shell: &Shell, ecosystem_config: &EcosystemConfig, governor_contract: Address, @@ -82,6 +85,7 @@ fn accept_ownership( forge = fill_forge_private_key(forge, governor)?; + check_the_balance(&forge).await?; let spinner = Spinner::new("Accepting governance"); forge.run(shell)?; spinner.finish(); diff --git a/zk_toolbox/crates/zk_inception/src/commands/chain/deploy_paymaster.rs b/zk_toolbox/crates/zk_inception/src/commands/chain/deploy_paymaster.rs index 23016856bfbe..1b0e78883d14 100644 --- a/zk_toolbox/crates/zk_inception/src/commands/chain/deploy_paymaster.rs +++ b/zk_toolbox/crates/zk_inception/src/commands/chain/deploy_paymaster.rs @@ -6,6 +6,7 @@ use common::{ }; use xshell::Shell; +use crate::forge_utils::check_the_balance; use crate::{ configs::{ forge_interface::paymaster::{DeployPaymasterInput, DeployPaymasterOutput}, @@ -15,16 +16,16 @@ use crate::{ forge_utils::fill_forge_private_key, }; -pub fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { +pub async fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { let chain_name = global_config().chain_name.clone(); let ecosystem_config = EcosystemConfig::from_file(shell)?; let chain_config = ecosystem_config .load_chain(chain_name) .context("Chain not initialized. Please create a chain first")?; - deploy_paymaster(shell, &chain_config, &ecosystem_config, args) + deploy_paymaster(shell, &chain_config, &ecosystem_config, args).await } -pub fn deploy_paymaster( +pub async fn deploy_paymaster( shell: &Shell, chain_config: &ChainConfig, ecosystem_config: &EcosystemConfig, @@ -46,6 +47,7 @@ pub fn deploy_paymaster( )?; let spinner = Spinner::new("Deploying paymaster"); + check_the_balance(&forge).await?; forge.run(shell)?; spinner.finish(); 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 ae14ef1fc2ac..1f6ac66b9d2a 100644 --- a/zk_toolbox/crates/zk_inception/src/commands/chain/init.rs +++ b/zk_toolbox/crates/zk_inception/src/commands/chain/init.rs @@ -8,6 +8,7 @@ use common::{ use xshell::Shell; use super::args::init::InitArgsFinal; +use crate::forge_utils::check_the_balance; use crate::{ accept_ownership::accept_admin, commands::chain::{ @@ -72,7 +73,8 @@ pub async fn init( chain_config.get_wallets_config()?.governor_private_key(), contracts_config.l1.diamond_proxy_addr, &init_args.forge_args.clone(), - )?; + ) + .await?; spinner.finish(); initialize_bridges::initialize_bridges( @@ -80,7 +82,8 @@ pub async fn init( chain_config, ecosystem_config, init_args.forge_args.clone(), - )?; + ) + .await?; if init_args.deploy_paymaster { deploy_paymaster::deploy_paymaster( @@ -88,7 +91,8 @@ pub async fn init( chain_config, ecosystem_config, init_args.forge_args.clone(), - )?; + ) + .await?; } genesis( @@ -124,7 +128,7 @@ async fn register_chain( .with_broadcast(); forge = fill_forge_private_key(forge, config.get_wallets()?.governor_private_key())?; - + check_the_balance(&forge).await?; forge.run(shell)?; let register_chain_output = diff --git a/zk_toolbox/crates/zk_inception/src/commands/chain/initialize_bridges.rs b/zk_toolbox/crates/zk_inception/src/commands/chain/initialize_bridges.rs index c28965a97c2b..84635c6cd032 100644 --- a/zk_toolbox/crates/zk_inception/src/commands/chain/initialize_bridges.rs +++ b/zk_toolbox/crates/zk_inception/src/commands/chain/initialize_bridges.rs @@ -9,6 +9,7 @@ use common::{ }; use xshell::{cmd, Shell}; +use crate::forge_utils::check_the_balance; use crate::{ configs::{ forge_interface::initialize_bridges::{ @@ -20,7 +21,7 @@ use crate::{ forge_utils::fill_forge_private_key, }; -pub fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { +pub async fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { let chain_name = global_config().chain_name.clone(); let ecosystem_config = EcosystemConfig::from_file(shell)?; let chain_config = ecosystem_config @@ -28,13 +29,13 @@ pub fn run(args: ForgeScriptArgs, shell: &Shell) -> anyhow::Result<()> { .context("Chain not initialized. Please create a chain first")?; let spinner = Spinner::new("Initializing bridges"); - initialize_bridges(shell, &chain_config, &ecosystem_config, args)?; + initialize_bridges(shell, &chain_config, &ecosystem_config, args).await?; spinner.finish(); Ok(()) } -pub fn initialize_bridges( +pub async fn initialize_bridges( shell: &Shell, chain_config: &ChainConfig, ecosystem_config: &EcosystemConfig, @@ -56,6 +57,7 @@ pub fn initialize_bridges( ecosystem_config.get_wallets()?.governor_private_key(), )?; + check_the_balance(&forge).await?; forge.run(shell)?; let output = diff --git a/zk_toolbox/crates/zk_inception/src/commands/chain/mod.rs b/zk_toolbox/crates/zk_inception/src/commands/chain/mod.rs index b7f219a7f159..759b4aaea557 100644 --- a/zk_toolbox/crates/zk_inception/src/commands/chain/mod.rs +++ b/zk_toolbox/crates/zk_inception/src/commands/chain/mod.rs @@ -32,7 +32,7 @@ pub(crate) async fn run(shell: &Shell, args: ChainCommands) -> anyhow::Result<() ChainCommands::Create(args) => create::run(args, shell), ChainCommands::Init(args) => init::run(args, shell).await, ChainCommands::Genesis(args) => genesis::run(args, shell).await, - ChainCommands::InitializeBridges(args) => initialize_bridges::run(args, shell), - ChainCommands::DeployPaymaster(args) => deploy_paymaster::run(args, shell), + ChainCommands::InitializeBridges(args) => initialize_bridges::run(args, shell).await, + ChainCommands::DeployPaymaster(args) => deploy_paymaster::run(args, shell).await, } } 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 1132c4ae8461..cceb07f98815 100644 --- a/zk_toolbox/crates/zk_inception/src/commands/ecosystem/init.rs +++ b/zk_toolbox/crates/zk_inception/src/commands/ecosystem/init.rs @@ -15,6 +15,7 @@ use common::{ use xshell::{cmd, Shell}; use super::args::init::{EcosystemArgsFinal, EcosystemInitArgs, EcosystemInitArgsFinal}; +use crate::forge_utils::check_the_balance; use crate::{ accept_ownership::accept_owner, commands::{ @@ -59,7 +60,8 @@ pub async fn run(args: EcosystemInitArgs, shell: &Shell) -> anyhow::Result<()> { shell, &ecosystem_config, &initial_deployment_config, - )?; + ) + .await?; if final_ecosystem_args.deploy_erc20 { logger::info("Deploying ERC20 contracts"); @@ -73,7 +75,8 @@ pub async fn run(args: EcosystemInitArgs, shell: &Shell) -> anyhow::Result<()> { &ecosystem_config, &contracts_config, final_ecosystem_args.forge_args.clone(), - )?; + ) + .await?; } // If the name of chain passed then we deploy exactly this chain otherwise deploy all chains @@ -146,7 +149,7 @@ pub async fn distribute_eth( Ok(()) } -fn init( +async fn init( init_args: &mut EcosystemInitArgsFinal, shell: &Shell, ecosystem_config: &EcosystemConfig, @@ -163,12 +166,13 @@ fn init( init_args.forge_args.clone(), ecosystem_config, initial_deployment_config, - )?; + ) + .await?; contracts.save(shell, ecosystem_config.config.clone().join(CONTRACTS_FILE))?; Ok(contracts) } -fn deploy_erc20( +async fn deploy_erc20( shell: &Shell, erc20_deployment_config: &Erc20DeploymentConfig, ecosystem_config: &EcosystemConfig, @@ -191,6 +195,7 @@ fn deploy_erc20( )?; let spinner = Spinner::new("Deploying ERC20 contracts..."); + check_the_balance(&forge).await?; forge.run(shell)?; spinner.finish(); @@ -200,7 +205,7 @@ fn deploy_erc20( Ok(result) } -fn deploy_ecosystem( +async fn deploy_ecosystem( shell: &Shell, ecosystem: &mut EcosystemArgsFinal, forge_args: ForgeScriptArgs, @@ -213,7 +218,8 @@ fn deploy_ecosystem( forge_args, ecosystem_config, initial_deployment_config, - ); + ) + .await; } let ecosystem_contracts_path = match &ecosystem.ecosystem_contracts_path { @@ -252,7 +258,7 @@ fn deploy_ecosystem( ContractsConfig::read(shell, ecosystem_contracts_path) } -fn deploy_ecosystem_inner( +async fn deploy_ecosystem_inner( shell: &Shell, forge_args: ForgeScriptArgs, config: &EcosystemConfig, @@ -291,6 +297,7 @@ fn deploy_ecosystem_inner( forge = fill_forge_private_key(forge, wallets_config.deployer_private_key())?; let spinner = Spinner::new("Deploying ecosystem contracts..."); + check_the_balance(&forge).await?; forge.run(shell)?; spinner.finish(); @@ -304,7 +311,8 @@ fn deploy_ecosystem_inner( config.get_wallets()?.governor_private_key(), contracts_config.ecosystem_contracts.bridgehub_proxy_addr, &forge_args, - )?; + ) + .await?; accept_owner( shell, @@ -313,7 +321,8 @@ fn deploy_ecosystem_inner( config.get_wallets()?.governor_private_key(), contracts_config.bridges.shared.l1_address, &forge_args, - )?; + ) + .await?; Ok(contracts_config) } diff --git a/zk_toolbox/crates/zk_inception/src/consts.rs b/zk_toolbox/crates/zk_inception/src/consts.rs index f00cdd48cd94..8993981c4c98 100644 --- a/zk_toolbox/crates/zk_inception/src/consts.rs +++ b/zk_toolbox/crates/zk_inception/src/consts.rs @@ -42,6 +42,8 @@ pub(super) const TEST_CONFIG_PATH: &str = "etc/test_config/constant/eth.json"; pub(super) const BASE_PATH: &str = "m/44'/60'/0'"; pub(super) const AMOUNT_FOR_DISTRIBUTION_TO_WALLETS: u128 = 1000000000000000000000; +pub(super) const MINIMUM_BALANCE_FOR_WALLET: u128 = 5000000000000000000; + #[derive(PartialEq, Debug, Clone)] pub struct ForgeScriptParams { input: &'static str, diff --git a/zk_toolbox/crates/zk_inception/src/forge_utils.rs b/zk_toolbox/crates/zk_inception/src/forge_utils.rs index f2f8a13b2c85..738fc1c241e8 100644 --- a/zk_toolbox/crates/zk_inception/src/forge_utils.rs +++ b/zk_toolbox/crates/zk_inception/src/forge_utils.rs @@ -1,3 +1,4 @@ +use crate::consts::MINIMUM_BALANCE_FOR_WALLET; use anyhow::anyhow; use common::forge::ForgeScript; use ethers::types::H256; @@ -12,3 +13,21 @@ pub fn fill_forge_private_key( } Ok(forge) } + +pub async fn check_the_balance(forge: &ForgeScript) -> anyhow::Result<()> { + let mut not_enough_money = true; + while not_enough_money { + let (success, address) = forge + .check_the_balance(MINIMUM_BALANCE_FOR_WALLET.into()) + .await?; + + not_enough_money = !success; + + if not_enough_money { + if common::PromptConfirm::new(format!("Address {address:?} doesn't have enough money to deploy contracts do you want to continue?")).ask() { + break; + } + } + } + Ok(()) +} From 01cd0572e6e9a78a1aa4ec1bbdbb387cddf32914 Mon Sep 17 00:00:00 2001 From: Danil Date: Thu, 23 May 2024 17:45:06 +0200 Subject: [PATCH 3/3] Simplify check the balance Signed-off-by: Danil --- zk_toolbox/crates/common/src/forge.rs | 16 ++++++++++------ .../crates/zk_inception/src/forge_utils.rs | 18 ++++++++---------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/zk_toolbox/crates/common/src/forge.rs b/zk_toolbox/crates/common/src/forge.rs index e6db788b02dd..28369beb7a80 100644 --- a/zk_toolbox/crates/common/src/forge.rs +++ b/zk_toolbox/crates/common/src/forge.rs @@ -4,7 +4,7 @@ use std::str::FromStr; use clap::Parser; use ethers::abi::Address; use ethers::middleware::Middleware; -use ethers::prelude::U256; +use ethers::prelude::{LocalWallet, Signer, U256}; use ethers::{abi::AbiEncode, types::H256}; use serde::{Deserialize, Serialize}; use strum_macros::Display; @@ -119,17 +119,21 @@ impl ForgeScript { }) } - pub async fn check_the_balance(&self, minimum_value: U256) -> anyhow::Result<(bool, Address)> { + pub fn address(&self) -> Option
{ + self.private_key() + .flat_map(|a| LocalWallet::from_bytes(a.as_bytes()).map(|a| a.address())) + } + + pub async fn check_the_balance(&self, minimum_value: U256) -> anyhow::Result { let Some(rpc_url) = self.rpc_url() else { - return Ok((true, Address::zero())); + return Ok(true) }; let Some(private_key) = self.private_key() else { - return Ok((true, Address::zero())); + return Ok(true) }; let client = create_ethers_client(private_key, rpc_url)?; - let address = client.address(); let balance = client.get_balance(client.address(), None).await?; - Ok((balance > minimum_value, address)) + Ok(balance > minimum_value)) } } diff --git a/zk_toolbox/crates/zk_inception/src/forge_utils.rs b/zk_toolbox/crates/zk_inception/src/forge_utils.rs index 738fc1c241e8..5ee7564ddf74 100644 --- a/zk_toolbox/crates/zk_inception/src/forge_utils.rs +++ b/zk_toolbox/crates/zk_inception/src/forge_utils.rs @@ -15,19 +15,17 @@ pub fn fill_forge_private_key( } pub async fn check_the_balance(forge: &ForgeScript) -> anyhow::Result<()> { - let mut not_enough_money = true; - while not_enough_money { - let (success, address) = forge - .check_the_balance(MINIMUM_BALANCE_FOR_WALLET.into()) - .await?; + let Some(address) = forge.address() else { + return Ok(()); + }; - not_enough_money = !success; - - if not_enough_money { - if common::PromptConfirm::new(format!("Address {address:?} doesn't have enough money to deploy contracts do you want to continue?")).ask() { + while !forge + .check_the_balance(MINIMUM_BALANCE_FOR_WALLET.into()) + .await? + { + if common::PromptConfirm::new(format!("Address {address:?} doesn't have enough money to deploy contracts do you want to continue?")).ask() { break; } - } } Ok(()) }