From 3456a1993a931cb6729b2b404125cfb0d2117554 Mon Sep 17 00:00:00 2001 From: avilagaston9 Date: Thu, 20 Nov 2025 00:32:54 -0300 Subject: [PATCH 1/5] feat(l2): accelerate deployer --- cmd/ethrex/l2/deployer.rs | 314 ++++++++++++++++++++++++++++++++------ crates/l2/sdk/src/sdk.rs | 196 +++++++++++++++++++----- 2 files changed, 421 insertions(+), 89 deletions(-) diff --git a/cmd/ethrex/l2/deployer.rs b/cmd/ethrex/l2/deployer.rs index 8bf30c6e4e2..88703a784e9 100644 --- a/cmd/ethrex/l2/deployer.rs +++ b/cmd/ethrex/l2/deployer.rs @@ -16,12 +16,11 @@ use ethrex_common::{ use ethrex_l2::utils::test_data_io::read_genesis_file; use ethrex_l2_common::{calldata::Value, prover::ProverType, utils::get_address_from_secret_key}; use ethrex_l2_rpc::signer::{LocalSigner, Signer}; -use ethrex_l2_sdk::register_fee_token; use ethrex_l2_sdk::{ - build_generic_tx, calldata::encode_calldata, create2_deploy_from_bytecode, - deploy_with_proxy_from_bytecode, initialize_contract, send_generic_transaction, - wait_for_transaction_receipt, + build_generic_tx, calldata::encode_calldata, create2_deploy_from_bytecode_no_wait, + initialize_contract_no_wait, send_generic_transaction, wait_for_transaction_receipt, }; +use ethrex_l2_sdk::{deploy_with_proxy_from_bytecode_no_wait, register_fee_token_no_wait}; use ethrex_rpc::{ EthClient, clients::Overrides, @@ -475,6 +474,8 @@ pub enum DeployerError { BytecodeNotFound, #[error("Failed to parse genesis")] Genesis, + #[error("Transaction receipt error")] + TransactionReceiptError, } /// Bytecode of the OnChainProposer contract. @@ -520,6 +521,11 @@ const TRANSFER_OWNERSHIP_SIGNATURE: &str = "transferOwnership(address)"; const ACCEPT_OWNERSHIP_SIGNATURE: &str = "acceptOwnership()"; const BRIDGE_INITIALIZER_SIGNATURE: &str = "initialize(address,address,uint256)"; +// Gas limit for deploying and initializing contracts +// Needed to avoid estimating gas of initializations when the +// deploy transaction is still pending +const TRANSACTION_GAS_LIMIT: u64 = 10_000_000; + #[derive(Clone)] pub struct ContractAddresses { pub on_chain_proposer_address: Address, @@ -549,11 +555,47 @@ pub async fn deploy_l1_contracts( info!("Deploying contracts"); - let contract_addresses = deploy_contracts(ð_client, &opts, &signer).await?; + let (contract_addresses, deploy_tx_hashes) = + deploy_contracts(ð_client, &opts, &signer).await?; info!("Initializing contracts"); - initialize_contracts(contract_addresses.clone(), ð_client, &opts, &signer).await?; + let initialize_tx_hashes = + initialize_contracts(contract_addresses.clone(), ð_client, &opts, &signer).await?; + + info!("Waiting for deployment transactions receipts"); + + for tx_hash in deploy_tx_hashes { + if tx_hash == H256::default() { + continue; + } + let receipt = wait_for_transaction_receipt(tx_hash, ð_client, 100).await?; + if !receipt.receipt.status { + error!("Receipt status is false for tx_hash: {:#x}", tx_hash); + return Err(DeployerError::TransactionReceiptError); + } + info!( + "Gas used for tx_hash {:#x}: {}", + tx_hash, receipt.tx_info.gas_used + ); + } + + info!("Waiting for initialization transactions receipts"); + + for tx_hash in initialize_tx_hashes { + if tx_hash == H256::default() { + continue; + } + let receipt = wait_for_transaction_receipt(tx_hash, ð_client, 100).await?; + if !receipt.receipt.status { + error!("Receipt status is false for tx_hash: {:#x}", tx_hash); + return Err(DeployerError::TransactionReceiptError); + } + info!( + "Gas used for tx_hash {:#x}: {}", + tx_hash, receipt.tx_info.gas_used + ); + } if opts.deposit_rich { let _ = make_deposits(contract_addresses.bridge_address, ð_client, &opts) @@ -576,11 +618,23 @@ async fn deploy_contracts( eth_client: &EthClient, opts: &DeployerOptions, deployer: &Signer, -) -> Result { +) -> Result<(ContractAddresses, Vec), DeployerError> { trace!("Deploying contracts"); info!("Deploying OnChainProposer"); + let gas_price = eth_client + .get_gas_price_with_extra(20) + .await? + .try_into() + .map_err(|_| { + EthClientError::InternalError("Failed to convert gas_price to a u64".to_owned()) + })?; + + let mut nonce = eth_client + .get_nonce(deployer.address(), BlockIdentifier::Tag(BlockTag::Latest)) + .await?; + let salt = if opts.randomize_contract_deployment { H256::random().as_bytes().to_vec() } else { @@ -601,8 +655,23 @@ async fn deploy_contracts( return Err(DeployerError::BytecodeNotFound); } - let on_chain_proposer_deployment = - deploy_with_proxy_from_bytecode(deployer, eth_client, &bytecode, &salt).await?; + let on_chain_proposer_deployment = deploy_with_proxy_from_bytecode_no_wait( + deployer, + eth_client, + &bytecode, + &salt, + Overrides { + nonce: Some(nonce), + gas_limit: Some(TRANSACTION_GAS_LIMIT), + max_fee_per_gas: Some(gas_price), + max_priority_fee_per_gas: Some(gas_price), + ..Default::default() + }, + ) + .await?; + + nonce += 2; + info!( "OnChainProposer deployed:\n Proxy -> address={:#x}, tx_hash={:#x}\n Impl -> address={:#x}, tx_hash={:#x}", on_chain_proposer_deployment.proxy_address, @@ -613,9 +682,20 @@ async fn deploy_contracts( info!("Deploying CommonBridge"); - let bridge_deployment = - deploy_with_proxy_from_bytecode(deployer, eth_client, COMMON_BRIDGE_BYTECODE, &salt) - .await?; + let bridge_deployment = deploy_with_proxy_from_bytecode_no_wait( + deployer, + eth_client, + COMMON_BRIDGE_BYTECODE, + &salt, + Overrides { + nonce: Some(nonce), + gas_limit: Some(TRANSACTION_GAS_LIMIT), + max_fee_per_gas: Some(gas_price), + max_priority_fee_per_gas: Some(gas_price), + ..Default::default() + }, + ) + .await?; info!( "CommonBridge deployed:\n Proxy -> address={:#x}, tx_hash={:#x}\n Impl -> address={:#x}, tx_hash={:#x}", @@ -625,14 +705,23 @@ async fn deploy_contracts( bridge_deployment.implementation_tx_hash, ); + nonce += 2; + let sequencer_registry_deployment = if opts.deploy_based_contracts { info!("Deploying SequencerRegistry"); - let sequencer_registry_deployment = deploy_with_proxy_from_bytecode( + let sequencer_registry_deployment = deploy_with_proxy_from_bytecode_no_wait( deployer, eth_client, SEQUENCER_REGISTRY_BYTECODE, &salt, + Overrides { + nonce: Some(nonce), + gas_limit: Some(TRANSACTION_GAS_LIMIT), + max_fee_per_gas: Some(gas_price), + max_priority_fee_per_gas: Some(gas_price), + ..Default::default() + }, ) .await?; @@ -649,23 +738,31 @@ async fn deploy_contracts( }; // if it's a required proof type, but no address has been specified, deploy it. - let sp1_verifier_address = match opts.sp1_verifier_address { - _ if opts.aligned => Address::zero(), - Some(addr) if opts.sp1 => addr, + let (sp1_verifier_deployment_tx_hash, sp1_verifier_address) = match opts.sp1_verifier_address { + _ if opts.aligned => (H256::default(), Address::zero()), + Some(addr) if opts.sp1 => (H256::default(), addr), None if opts.sp1 => { info!("Deploying SP1Verifier"); - let (verifier_deployment_tx_hash, sp1_verifier_address) = create2_deploy_from_bytecode( - &[], - SP1_VERIFIER_BYTECODE, - deployer, - &salt, - eth_client, - ) - .await?; + let (verifier_deployment_tx_hash, sp1_verifier_address) = + create2_deploy_from_bytecode_no_wait( + &[], + SP1_VERIFIER_BYTECODE, + deployer, + &salt, + eth_client, + Overrides { + nonce: Some(nonce), + gas_limit: Some(TRANSACTION_GAS_LIMIT), + max_fee_per_gas: Some(gas_price), + max_priority_fee_per_gas: Some(gas_price), + ..Default::default() + }, + ) + .await?; info!(address = %format!("{sp1_verifier_address:#x}"), tx_hash = %format!("{verifier_deployment_tx_hash:#x}"), "SP1Verifier deployed"); - sp1_verifier_address + (verifier_deployment_tx_hash, sp1_verifier_address) } - _ => Address::zero(), + _ => (H256::default(), Address::zero()), }; // we can't deploy the risc0 contract because of uncompatible licenses @@ -714,15 +811,28 @@ async fn deploy_contracts( tdx_verifier_address = ?tdx_verifier_address, "Contracts deployed" ); - Ok(ContractAddresses { - on_chain_proposer_address: on_chain_proposer_deployment.proxy_address, - bridge_address: bridge_deployment.proxy_address, - sp1_verifier_address, - risc0_verifier_address, - tdx_verifier_address, - sequencer_registry_address: sequencer_registry_deployment.proxy_address, - aligned_aggregator_address, - }) + + let receipts = vec![ + on_chain_proposer_deployment.implementation_tx_hash, + on_chain_proposer_deployment.proxy_tx_hash, + bridge_deployment.implementation_tx_hash, + bridge_deployment.proxy_tx_hash, + sequencer_registry_deployment.implementation_tx_hash, + sequencer_registry_deployment.proxy_tx_hash, + sp1_verifier_deployment_tx_hash, + ]; + Ok(( + ContractAddresses { + on_chain_proposer_address: on_chain_proposer_deployment.proxy_address, + bridge_address: bridge_deployment.proxy_address, + sp1_verifier_address, + risc0_verifier_address, + tdx_verifier_address, + sequencer_registry_address: sequencer_registry_deployment.proxy_address, + aligned_aggregator_address, + }, + receipts, + )) } fn deploy_tdx_contracts( @@ -817,8 +927,22 @@ async fn initialize_contracts( eth_client: &EthClient, opts: &DeployerOptions, initializer: &Signer, -) -> Result<(), DeployerError> { +) -> Result, DeployerError> { trace!("Initializing contracts"); + let mut tx_hashes = vec![]; + let gas_price = eth_client + .get_gas_price_with_extra(20) + .await? + .try_into() + .map_err(|_| { + EthClientError::InternalError("Failed to convert gas_price to a u64".to_owned()) + })?; + let mut nonce = eth_client + .get_nonce( + initializer.address(), + BlockIdentifier::Tag(BlockTag::Pending), + ) + .await?; trace!(committer_l1_address = %opts.committer_l1_address, "Using committer L1 address for OnChainProposer initialization"); @@ -875,16 +999,26 @@ async fn initialize_contracts( let deployer = Signer::Local(LocalSigner::new(opts.private_key)); - let initialize_tx_hash = initialize_contract( + let initialize_tx_hash = initialize_contract_no_wait( contract_addresses.on_chain_proposer_address, on_chain_proposer_initialization_calldata, &deployer, eth_client, + Overrides { + nonce: Some(nonce), + gas_limit: Some(TRANSACTION_GAS_LIMIT), + max_fee_per_gas: Some(gas_price), + max_priority_fee_per_gas: Some(gas_price), + ..Default::default() + }, ) .await?; info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "OnChainProposer initialized"); + nonce += 1; + tx_hashes.push(initialize_tx_hash); + info!("Initializing SequencerRegistry"); let initialize_tx_hash = { let calldata_values = vec![ @@ -896,15 +1030,24 @@ async fn initialize_contracts( let sequencer_registry_initialization_calldata = encode_calldata("initialize(address,address)", &calldata_values)?; - initialize_contract( + initialize_contract_no_wait( contract_addresses.sequencer_registry_address, sequencer_registry_initialization_calldata, &deployer, eth_client, + Overrides { + nonce: Some(nonce), + gas_limit: Some(TRANSACTION_GAS_LIMIT), + max_fee_per_gas: Some(gas_price), + max_priority_fee_per_gas: Some(gas_price), + ..Default::default() + }, ) .await? }; info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "SequencerRegistry initialized"); + nonce += 1; + tx_hashes.push(initialize_tx_hash); } else { // Initialize only OnChainProposer without Based config let calldata_values = vec![ @@ -931,14 +1074,23 @@ async fn initialize_contracts( let on_chain_proposer_initialization_calldata = encode_calldata(INITIALIZE_ON_CHAIN_PROPOSER_SIGNATURE, &calldata_values)?; - let initialize_tx_hash = initialize_contract( + let initialize_tx_hash = initialize_contract_no_wait( contract_addresses.on_chain_proposer_address, on_chain_proposer_initialization_calldata, initializer, eth_client, + Overrides { + nonce: Some(nonce), + gas_limit: Some(TRANSACTION_GAS_LIMIT), + max_fee_per_gas: Some(gas_price), + max_priority_fee_per_gas: Some(gas_price), + ..Default::default() + }, ) .await?; info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "OnChainProposer initialized"); + nonce += 1; + tx_hashes.push(initialize_tx_hash); } let initialize_bridge_address_tx_hash = { @@ -946,11 +1098,18 @@ async fn initialize_contracts( let on_chain_proposer_initialization_calldata = encode_calldata(INITIALIZE_BRIDGE_ADDRESS_SIGNATURE, &calldata_values)?; - initialize_contract( + initialize_contract_no_wait( contract_addresses.on_chain_proposer_address, on_chain_proposer_initialization_calldata, initializer, eth_client, + Overrides { + nonce: Some(nonce), + gas_limit: Some(TRANSACTION_GAS_LIMIT), + max_fee_per_gas: Some(gas_price), + max_priority_fee_per_gas: Some(gas_price), + ..Default::default() + }, ) .await? }; @@ -960,6 +1119,9 @@ async fn initialize_contracts( "OnChainProposer bridge address initialized" ); + nonce += 1; + tx_hashes.push(initialize_bridge_address_tx_hash); + if opts.on_chain_proposer_owner != initializer.address() { let transfer_ownership_tx_hash = { let owener_transfer_calldata = encode_calldata( @@ -967,15 +1129,25 @@ async fn initialize_contracts( &[Value::Address(opts.on_chain_proposer_owner)], )?; - initialize_contract( + initialize_contract_no_wait( contract_addresses.on_chain_proposer_address, owener_transfer_calldata, initializer, eth_client, + Overrides { + nonce: Some(nonce), + gas_limit: Some(TRANSACTION_GAS_LIMIT), + max_fee_per_gas: Some(gas_price), + max_priority_fee_per_gas: Some(gas_price), + ..Default::default() + }, ) .await? }; + tx_hashes.push(transfer_ownership_tx_hash); + nonce += 1; + if let Some(owner_pk) = opts.on_chain_proposer_owner_pk { let signer = Signer::Local(LocalSigner::new(owner_pk)); let accept_ownership_calldata = encode_calldata(ACCEPT_OWNERSHIP_SIGNATURE, &[])?; @@ -985,12 +1157,19 @@ async fn initialize_contracts( contract_addresses.on_chain_proposer_address, opts.on_chain_proposer_owner, accept_ownership_calldata.into(), - Overrides::default(), + Overrides { + nonce: Some(nonce), + gas_limit: Some(TRANSACTION_GAS_LIMIT), + max_fee_per_gas: Some(gas_price), + max_priority_fee_per_gas: Some(gas_price), + ..Default::default() + }, ) .await?; let accept_tx_hash = send_generic_transaction(eth_client, accept_tx, &signer).await?; - wait_for_transaction_receipt(accept_tx_hash, eth_client, 100).await?; + tx_hashes.push(accept_tx_hash); + nonce += 1; info!( transfer_tx_hash = %format!("{transfer_ownership_tx_hash:#x}"), @@ -1015,25 +1194,44 @@ async fn initialize_contracts( let bridge_initialization_calldata = encode_calldata(BRIDGE_INITIALIZER_SIGNATURE, &calldata_values)?; - initialize_contract( + initialize_contract_no_wait( contract_addresses.bridge_address, bridge_initialization_calldata, initializer, eth_client, + Overrides { + nonce: Some(nonce), + gas_limit: Some(TRANSACTION_GAS_LIMIT), + max_fee_per_gas: Some(gas_price), + max_priority_fee_per_gas: Some(gas_price), + ..Default::default() + }, ) .await? }; info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "CommonBridge initialized"); + tx_hashes.push(initialize_tx_hash); + nonce += 1; if let Some(fee_token) = opts.initial_fee_token { - register_fee_token( + let register_tx_hash = register_fee_token_no_wait( eth_client, contract_addresses.bridge_address, fee_token, initializer, + Overrides { + nonce: Some(nonce), + gas_limit: Some(TRANSACTION_GAS_LIMIT), + max_fee_per_gas: Some(gas_price), + max_priority_fee_per_gas: Some(gas_price), + ..Default::default() + }, ) .await?; info!(?fee_token, "CommonBridge initial fee token registered"); + info!(tx_hash = %format!("{register_tx_hash:#x}"), "Initial fee token registration transaction sent"); + tx_hashes.push(register_tx_hash); + nonce += 1; } if opts.bridge_owner != initializer.address() { @@ -1041,13 +1239,23 @@ async fn initialize_contracts( TRANSFER_OWNERSHIP_SIGNATURE, &[Value::Address(opts.bridge_owner)], )?; - let transfer_tx_hash = initialize_contract( + let transfer_tx_hash = initialize_contract_no_wait( contract_addresses.bridge_address, transfer_calldata, initializer, eth_client, + Overrides { + nonce: Some(nonce), + gas_limit: Some(TRANSACTION_GAS_LIMIT), + max_fee_per_gas: Some(gas_price), + max_priority_fee_per_gas: Some(gas_price), + ..Default::default() + }, ) .await?; + + tx_hashes.push(transfer_tx_hash); + if let Some(owner_pk) = opts.bridge_owner_pk { let signer = Signer::Local(LocalSigner::new(owner_pk)); let accept_calldata = encode_calldata(ACCEPT_OWNERSHIP_SIGNATURE, &[])?; @@ -1057,16 +1265,24 @@ async fn initialize_contracts( contract_addresses.bridge_address, opts.bridge_owner, accept_calldata.into(), - Overrides::default(), + Overrides { + gas_limit: Some(TRANSACTION_GAS_LIMIT), + max_fee_per_gas: Some(gas_price), + max_priority_fee_per_gas: Some(gas_price), + ..Default::default() + }, ) .await?; + let accept_tx_hash = send_generic_transaction(eth_client, accept_tx, &signer).await?; - wait_for_transaction_receipt(accept_tx_hash, eth_client, 100).await?; + + tx_hashes.push(accept_tx_hash); info!( transfer_tx_hash = %format!("{transfer_tx_hash:#x}"), accept_tx_hash = %format!("{accept_tx_hash:#x}"), "CommonBridge ownership transferred and accepted" ); + info!("Used nonce {}", nonce); } else { info!( transfer_tx_hash = %format!("{transfer_tx_hash:#x}"), @@ -1076,7 +1292,7 @@ async fn initialize_contracts( } trace!("Contracts initialized"); - Ok(()) + Ok(tx_hashes) } async fn make_deposits( diff --git a/crates/l2/sdk/src/sdk.rs b/crates/l2/sdk/src/sdk.rs index 3c8b13ece76..7ee1b19ed0e 100644 --- a/crates/l2/sdk/src/sdk.rs +++ b/crates/l2/sdk/src/sdk.rs @@ -25,6 +25,7 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::ops::{Add, Div}; use std::str::FromStr; use std::{fs::read_to_string, path::Path}; +use tracing::info; use tracing::{error, warn}; pub mod calldata; @@ -458,16 +459,24 @@ pub async fn create2_deploy_from_bytecode( Ok((deploy_tx_hash, contract_address)) } -/// Deploys a contract behind an OpenZeppelin's `ERC1967Proxy`. -/// The embedded `ERC1967_PROXY_BYTECODE` may be empty if the crate was compiled -/// without the `COMPILE_CONTRACTS` env var set. In that case, this function -/// will return `DeployError::ProxyBytecodeNotFound`. -async fn deploy_proxy( +pub async fn create2_deploy_from_bytecode_no_wait( + constructor_args: &[u8], + bytecode: &[u8], deployer: &Signer, - eth_client: &EthClient, - implementation_address: Address, salt: &[u8], + eth_client: &EthClient, + overrides: Overrides, ) -> Result<(H256, Address), DeployError> { + let init_code = [bytecode, constructor_args].concat(); + + let (deploy_tx_hash, contract_address) = + create2_deploy_no_wait(salt, &init_code, deployer, eth_client, overrides).await?; + + Ok((deploy_tx_hash, contract_address)) +} + +/// Builds the init code for deploying a contract behind an OpenZeppelin `ERC1967Proxy`. +fn build_proxy_init_code(implementation_address: Address) -> Result { #[allow(clippy::const_is_empty)] if ERC1967_PROXY_BYTECODE.is_empty() { return Err(DeployError::ProxyBytecodeNotFound); @@ -479,12 +488,39 @@ async fn deploy_proxy( init_code.extend(H256::from_low_u64_be(0x40).0); init_code.extend(H256::zero().0); - let (deploy_tx_hash, proxy_address) = - create2_deploy(salt, &Bytes::from(init_code), deployer, eth_client) - .await - .map_err(DeployError::from)?; + Ok(Bytes::from(init_code)) +} + +/// Deploys a contract behind an OpenZeppelin's `ERC1967Proxy`. +/// The embedded `ERC1967_PROXY_BYTECODE` may be empty if the crate was compiled +/// without the `COMPILE_CONTRACTS` env var set. In that case, this function +/// will return `DeployError::ProxyBytecodeNotFound`. +async fn deploy_proxy( + deployer: &Signer, + eth_client: &EthClient, + implementation_address: Address, + salt: &[u8], +) -> Result<(H256, Address), DeployError> { + let init_code = build_proxy_init_code(implementation_address)?; + + create2_deploy(salt, &init_code, deployer, eth_client) + .await + .map_err(DeployError::from) +} - Ok((deploy_tx_hash, proxy_address)) +/// Same as `deploy_proxy`, but does not wait for the transaction receipt. +async fn deploy_proxy_no_wait( + deployer: &Signer, + eth_client: &EthClient, + implementation_address: Address, + salt: &[u8], + overrides: Overrides, +) -> Result<(H256, Address), DeployError> { + let init_code = build_proxy_init_code(implementation_address)?; + + create2_deploy_no_wait(salt, &init_code, deployer, eth_client, overrides) + .await + .map_err(DeployError::from) } /// Deploys a contract behind an OpenZeppelin's `ERC1967Proxy`. @@ -508,6 +544,27 @@ pub async fn deploy_with_proxy( }) } +/// Same as `deploy_with_proxy`, but does not wait for the transaction receipts. +pub async fn deploy_with_proxy_no_wait( + deployer: &Signer, + eth_client: &EthClient, + contract_path: &Path, + salt: &[u8], +) -> Result { + let (implementation_tx_hash, implementation_address) = + create2_deploy_from_path(&[], contract_path, deployer, salt, eth_client).await?; + + let (proxy_tx_hash, proxy_address) = + deploy_proxy(deployer, eth_client, implementation_address, salt).await?; + + Ok(ProxyDeployment { + proxy_address, + proxy_tx_hash, + implementation_address, + implementation_tx_hash, + }) +} + /// Same as `deploy_with_proxy`, but takes the contract bytecode directly instead of a path. pub async fn deploy_with_proxy_from_bytecode( deployer: &Signer, @@ -529,12 +586,57 @@ pub async fn deploy_with_proxy_from_bytecode( }) } -async fn create2_deploy( +/// Same as `deploy_with_proxy_from_bytecode`, but does not wait for the transaction receipts. +pub async fn deploy_with_proxy_from_bytecode_no_wait( + deployer: &Signer, + eth_client: &EthClient, + bytecode: &[u8], + salt: &[u8], + overrides: Overrides, +) -> Result { + let (implementation_tx_hash, implementation_address) = create2_deploy_from_bytecode_no_wait( + &[], + bytecode, + deployer, + salt, + eth_client, + overrides.clone(), + ) + .await?; + + info!( + "Deployed implementation at {implementation_address:#x} with tx {implementation_tx_hash:#x}" + ); + + let (proxy_tx_hash, proxy_address) = deploy_proxy_no_wait( + deployer, + eth_client, + implementation_address, + salt, + Overrides { + nonce: overrides.nonce.map(|nonce| nonce + 1), + ..overrides + }, + ) + .await?; + + info!("Deployed proxy at {proxy_address:#x} with tx {proxy_tx_hash:#x}"); + + Ok(ProxyDeployment { + proxy_address, + proxy_tx_hash, + implementation_address, + implementation_tx_hash, + }) +} + +async fn build_create2_deploy_tx( salt: &[u8], init_code: &[u8], deployer: &Signer, eth_client: &EthClient, -) -> Result<(H256, Address), EthClientError> { + overrides: Overrides, +) -> Result { let calldata = [salt, init_code].concat(); let gas_price = eth_client .get_gas_price_with_extra(20) @@ -544,7 +646,7 @@ async fn create2_deploy( EthClientError::InternalError("Failed to convert gas_price to a u64".to_owned()) })?; - let deploy_tx = build_generic_tx( + build_generic_tx( eth_client, TxType::EIP1559, DETERMINISTIC_DEPLOYMENT_PROXY_ADDRESS, @@ -553,21 +655,45 @@ async fn create2_deploy( Overrides { max_fee_per_gas: Some(gas_price), max_priority_fee_per_gas: Some(gas_price), - ..Default::default() + ..overrides }, ) - .await?; + .await +} +async fn create2_deploy( + salt: &[u8], + init_code: &[u8], + deployer: &Signer, + eth_client: &EthClient, +) -> Result<(H256, Address), EthClientError> { + let deploy_tx = + build_create2_deploy_tx(salt, init_code, deployer, eth_client, Overrides::default()) + .await?; let deploy_tx_hash = send_tx_bump_gas_exponential_backoff(eth_client, deploy_tx, deployer).await?; - wait_for_transaction_receipt(deploy_tx_hash, eth_client, 10).await?; - let deployed_address = create2_address(salt, keccak(init_code)); Ok((deploy_tx_hash, deployed_address)) } +async fn create2_deploy_no_wait( + salt: &[u8], + init_code: &[u8], + deployer: &Signer, + eth_client: &EthClient, + overrides: Overrides, +) -> Result<(H256, Address), EthClientError> { + let deploy_tx = + build_create2_deploy_tx(salt, init_code, deployer, eth_client, overrides).await?; + + let deploy_tx_hash = send_generic_transaction(eth_client, deploy_tx, deployer).await?; + + let deployed_address = create2_address(salt, keccak(init_code)); + Ok((deploy_tx_hash, deployed_address)) +} + #[allow(clippy::indexing_slicing)] fn create2_address(salt: &[u8], init_code_hash: H256) -> Address { Address::from_slice( @@ -584,36 +710,25 @@ fn create2_address(salt: &[u8], init_code_hash: H256) -> Address { ) } -pub async fn initialize_contract( +pub async fn initialize_contract_no_wait( contract_address: Address, initialize_calldata: Vec, initializer: &Signer, eth_client: &EthClient, + overrides: Overrides, ) -> Result { - let gas_price = eth_client - .get_gas_price_with_extra(20) - .await? - .try_into() - .map_err(|_| { - EthClientError::InternalError("Failed to convert gas_price to a u64".to_owned()) - })?; - let initialize_tx = build_generic_tx( eth_client, TxType::EIP1559, contract_address, initializer.address(), initialize_calldata.into(), - Overrides { - max_fee_per_gas: Some(gas_price), - max_priority_fee_per_gas: Some(gas_price), - ..Default::default() - }, + overrides, ) .await?; let initialize_tx_hash = - send_tx_bump_gas_exponential_backoff(eth_client, initialize_tx, initializer).await?; + send_generic_transaction(eth_client, initialize_tx, initializer).await?; Ok(initialize_tx_hash) } @@ -1117,23 +1232,24 @@ async fn _call_bytes32_variable( Ok(arr) } -pub async fn register_fee_token( +pub async fn register_fee_token_no_wait( client: &EthClient, bridge_address: Address, fee_token: Address, signer: &Signer, -) -> Result<(), EthClientError> { + overrides: Overrides, +) -> Result { let calldata = encode_calldata(REGISTER_FEE_TOKEN_SIGNATURE, &[Value::Address(fee_token)])?; + let tx_register = build_generic_tx( client, TxType::EIP1559, bridge_address, signer.address(), calldata.into(), - Overrides::default(), + overrides, ) .await?; - let tx_hash = send_generic_transaction(client, tx_register, signer).await?; - wait_for_transaction_receipt(tx_hash, client, 100).await?; - Ok(()) + + send_generic_transaction(client, tx_register, signer).await } From 2146f6ebf4827b5aec6e1ebe4b67fded9384f778 Mon Sep 17 00:00:00 2001 From: avilagaston9 Date: Tue, 25 Nov 2025 12:14:43 -0300 Subject: [PATCH 2/5] Fix PR --- cmd/ethrex/l2/deployer.rs | 84 +++++++++++++++++---------------------- crates/l2/sdk/src/sdk.rs | 56 ++++++++++++++++---------- 2 files changed, 72 insertions(+), 68 deletions(-) diff --git a/cmd/ethrex/l2/deployer.rs b/cmd/ethrex/l2/deployer.rs index 88703a784e9..15f005bf87a 100644 --- a/cmd/ethrex/l2/deployer.rs +++ b/cmd/ethrex/l2/deployer.rs @@ -563,38 +563,17 @@ pub async fn deploy_l1_contracts( let initialize_tx_hashes = initialize_contracts(contract_addresses.clone(), ð_client, &opts, &signer).await?; - info!("Waiting for deployment transactions receipts"); + info!("Waiting for transactions receipts"); - for tx_hash in deploy_tx_hashes { - if tx_hash == H256::default() { + for tx_hash in deploy_tx_hashes.iter().chain(initialize_tx_hashes.iter()) { + if *tx_hash == H256::default() { continue; } - let receipt = wait_for_transaction_receipt(tx_hash, ð_client, 100).await?; + let receipt = wait_for_transaction_receipt(*tx_hash, ð_client, 100).await?; if !receipt.receipt.status { - error!("Receipt status is false for tx_hash: {:#x}", tx_hash); + error!("Receipt status is false for tx_hash: {tx_hash:#x}"); return Err(DeployerError::TransactionReceiptError); } - info!( - "Gas used for tx_hash {:#x}: {}", - tx_hash, receipt.tx_info.gas_used - ); - } - - info!("Waiting for initialization transactions receipts"); - - for tx_hash in initialize_tx_hashes { - if tx_hash == H256::default() { - continue; - } - let receipt = wait_for_transaction_receipt(tx_hash, ð_client, 100).await?; - if !receipt.receipt.status { - error!("Receipt status is false for tx_hash: {:#x}", tx_hash); - return Err(DeployerError::TransactionReceiptError); - } - info!( - "Gas used for tx_hash {:#x}: {}", - tx_hash, receipt.tx_info.gas_used - ); } if opts.deposit_rich { @@ -725,6 +704,8 @@ async fn deploy_contracts( ) .await?; + nonce += 2; + info!( "SequencerRegistry deployed:\n Proxy -> address={:#x}, tx_hash={:#x}\n Impl -> address={:#x}, tx_hash={:#x}", sequencer_registry_deployment.proxy_address, @@ -937,7 +918,7 @@ async fn initialize_contracts( .map_err(|_| { EthClientError::InternalError("Failed to convert gas_price to a u64".to_owned()) })?; - let mut nonce = eth_client + let mut initializer_nonce = eth_client .get_nonce( initializer.address(), BlockIdentifier::Tag(BlockTag::Pending), @@ -969,6 +950,10 @@ async fn initialize_contracts( let deployer_address = get_address_from_secret_key(&opts.private_key).map_err(DeployerError::InternalError)?; + let mut deployer_nonce = eth_client + .get_nonce(deployer_address, BlockIdentifier::Tag(BlockTag::Pending)) + .await?; + info!("Initializing OnChainProposer"); if opts.deploy_based_contracts { @@ -1005,7 +990,7 @@ async fn initialize_contracts( &deployer, eth_client, Overrides { - nonce: Some(nonce), + nonce: Some(deployer_nonce), gas_limit: Some(TRANSACTION_GAS_LIMIT), max_fee_per_gas: Some(gas_price), max_priority_fee_per_gas: Some(gas_price), @@ -1016,7 +1001,7 @@ async fn initialize_contracts( info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "OnChainProposer initialized"); - nonce += 1; + deployer_nonce += 1; tx_hashes.push(initialize_tx_hash); info!("Initializing SequencerRegistry"); @@ -1036,7 +1021,7 @@ async fn initialize_contracts( &deployer, eth_client, Overrides { - nonce: Some(nonce), + nonce: Some(deployer_nonce), gas_limit: Some(TRANSACTION_GAS_LIMIT), max_fee_per_gas: Some(gas_price), max_priority_fee_per_gas: Some(gas_price), @@ -1046,7 +1031,6 @@ async fn initialize_contracts( .await? }; info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "SequencerRegistry initialized"); - nonce += 1; tx_hashes.push(initialize_tx_hash); } else { // Initialize only OnChainProposer without Based config @@ -1080,7 +1064,7 @@ async fn initialize_contracts( initializer, eth_client, Overrides { - nonce: Some(nonce), + nonce: Some(initializer_nonce), gas_limit: Some(TRANSACTION_GAS_LIMIT), max_fee_per_gas: Some(gas_price), max_priority_fee_per_gas: Some(gas_price), @@ -1089,7 +1073,7 @@ async fn initialize_contracts( ) .await?; info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "OnChainProposer initialized"); - nonce += 1; + initializer_nonce += 1; tx_hashes.push(initialize_tx_hash); } @@ -1104,7 +1088,7 @@ async fn initialize_contracts( initializer, eth_client, Overrides { - nonce: Some(nonce), + nonce: Some(initializer_nonce), gas_limit: Some(TRANSACTION_GAS_LIMIT), max_fee_per_gas: Some(gas_price), max_priority_fee_per_gas: Some(gas_price), @@ -1119,23 +1103,23 @@ async fn initialize_contracts( "OnChainProposer bridge address initialized" ); - nonce += 1; + initializer_nonce += 1; tx_hashes.push(initialize_bridge_address_tx_hash); if opts.on_chain_proposer_owner != initializer.address() { let transfer_ownership_tx_hash = { - let owener_transfer_calldata = encode_calldata( + let owner_transfer_calldata = encode_calldata( TRANSFER_OWNERSHIP_SIGNATURE, &[Value::Address(opts.on_chain_proposer_owner)], )?; initialize_contract_no_wait( contract_addresses.on_chain_proposer_address, - owener_transfer_calldata, + owner_transfer_calldata, initializer, eth_client, Overrides { - nonce: Some(nonce), + nonce: Some(initializer_nonce), gas_limit: Some(TRANSACTION_GAS_LIMIT), max_fee_per_gas: Some(gas_price), max_priority_fee_per_gas: Some(gas_price), @@ -1146,10 +1130,13 @@ async fn initialize_contracts( }; tx_hashes.push(transfer_ownership_tx_hash); - nonce += 1; + initializer_nonce += 1; if let Some(owner_pk) = opts.on_chain_proposer_owner_pk { let signer = Signer::Local(LocalSigner::new(owner_pk)); + let owner_nonce = eth_client + .get_nonce(signer.address(), BlockIdentifier::Tag(BlockTag::Pending)) + .await?; let accept_ownership_calldata = encode_calldata(ACCEPT_OWNERSHIP_SIGNATURE, &[])?; let accept_tx = build_generic_tx( eth_client, @@ -1158,7 +1145,7 @@ async fn initialize_contracts( opts.on_chain_proposer_owner, accept_ownership_calldata.into(), Overrides { - nonce: Some(nonce), + nonce: Some(owner_nonce), gas_limit: Some(TRANSACTION_GAS_LIMIT), max_fee_per_gas: Some(gas_price), max_priority_fee_per_gas: Some(gas_price), @@ -1167,9 +1154,7 @@ async fn initialize_contracts( ) .await?; let accept_tx_hash = send_generic_transaction(eth_client, accept_tx, &signer).await?; - tx_hashes.push(accept_tx_hash); - nonce += 1; info!( transfer_tx_hash = %format!("{transfer_ownership_tx_hash:#x}"), @@ -1200,7 +1185,7 @@ async fn initialize_contracts( initializer, eth_client, Overrides { - nonce: Some(nonce), + nonce: Some(initializer_nonce), gas_limit: Some(TRANSACTION_GAS_LIMIT), max_fee_per_gas: Some(gas_price), max_priority_fee_per_gas: Some(gas_price), @@ -1211,7 +1196,7 @@ async fn initialize_contracts( }; info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "CommonBridge initialized"); tx_hashes.push(initialize_tx_hash); - nonce += 1; + initializer_nonce += 1; if let Some(fee_token) = opts.initial_fee_token { let register_tx_hash = register_fee_token_no_wait( @@ -1220,7 +1205,7 @@ async fn initialize_contracts( fee_token, initializer, Overrides { - nonce: Some(nonce), + nonce: Some(initializer_nonce), gas_limit: Some(TRANSACTION_GAS_LIMIT), max_fee_per_gas: Some(gas_price), max_priority_fee_per_gas: Some(gas_price), @@ -1231,7 +1216,7 @@ async fn initialize_contracts( info!(?fee_token, "CommonBridge initial fee token registered"); info!(tx_hash = %format!("{register_tx_hash:#x}"), "Initial fee token registration transaction sent"); tx_hashes.push(register_tx_hash); - nonce += 1; + initializer_nonce += 1; } if opts.bridge_owner != initializer.address() { @@ -1245,7 +1230,7 @@ async fn initialize_contracts( initializer, eth_client, Overrides { - nonce: Some(nonce), + nonce: Some(initializer_nonce), gas_limit: Some(TRANSACTION_GAS_LIMIT), max_fee_per_gas: Some(gas_price), max_priority_fee_per_gas: Some(gas_price), @@ -1258,6 +1243,9 @@ async fn initialize_contracts( if let Some(owner_pk) = opts.bridge_owner_pk { let signer = Signer::Local(LocalSigner::new(owner_pk)); + let owner_nonce = eth_client + .get_nonce(signer.address(), BlockIdentifier::Tag(BlockTag::Pending)) + .await?; let accept_calldata = encode_calldata(ACCEPT_OWNERSHIP_SIGNATURE, &[])?; let accept_tx = build_generic_tx( eth_client, @@ -1267,6 +1255,7 @@ async fn initialize_contracts( accept_calldata.into(), Overrides { gas_limit: Some(TRANSACTION_GAS_LIMIT), + nonce: Some(owner_nonce), max_fee_per_gas: Some(gas_price), max_priority_fee_per_gas: Some(gas_price), ..Default::default() @@ -1282,7 +1271,6 @@ async fn initialize_contracts( accept_tx_hash = %format!("{accept_tx_hash:#x}"), "CommonBridge ownership transferred and accepted" ); - info!("Used nonce {}", nonce); } else { info!( transfer_tx_hash = %format!("{transfer_tx_hash:#x}"), diff --git a/crates/l2/sdk/src/sdk.rs b/crates/l2/sdk/src/sdk.rs index 7ee1b19ed0e..c4dd2741a8a 100644 --- a/crates/l2/sdk/src/sdk.rs +++ b/crates/l2/sdk/src/sdk.rs @@ -25,7 +25,6 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::ops::{Add, Div}; use std::str::FromStr; use std::{fs::read_to_string, path::Path}; -use tracing::info; use tracing::{error, warn}; pub mod calldata; @@ -453,9 +452,16 @@ pub async fn create2_deploy_from_bytecode( salt: &[u8], eth_client: &EthClient, ) -> Result<(H256, Address), DeployError> { - let init_code = [bytecode, constructor_args].concat(); - let (deploy_tx_hash, contract_address) = - create2_deploy(salt, &init_code, deployer, eth_client).await?; + let (deploy_tx_hash, contract_address) = create2_deploy_from_bytecode_no_wait( + constructor_args, + bytecode, + deployer, + salt, + eth_client, + Overrides::default(), + ) + .await?; + wait_for_transaction_receipt(deploy_tx_hash, eth_client, 10).await?; Ok((deploy_tx_hash, contract_address)) } @@ -550,12 +556,31 @@ pub async fn deploy_with_proxy_no_wait( eth_client: &EthClient, contract_path: &Path, salt: &[u8], + overrides: Overrides, ) -> Result { - let (implementation_tx_hash, implementation_address) = - create2_deploy_from_path(&[], contract_path, deployer, salt, eth_client).await?; + let bytecode_hex = read_to_string(contract_path)?; + let bytecode = hex::decode(bytecode_hex.trim_start_matches("0x").trim())?; + let (implementation_tx_hash, implementation_address) = create2_deploy_from_bytecode_no_wait( + &[], + &bytecode, + deployer, + salt, + eth_client, + overrides.clone(), + ) + .await?; - let (proxy_tx_hash, proxy_address) = - deploy_proxy(deployer, eth_client, implementation_address, salt).await?; + let (proxy_tx_hash, proxy_address) = deploy_proxy_no_wait( + deployer, + eth_client, + implementation_address, + salt, + Overrides { + nonce: overrides.nonce.map(|nonce| nonce + 1), + ..overrides + }, + ) + .await?; Ok(ProxyDeployment { proxy_address, @@ -604,10 +629,6 @@ pub async fn deploy_with_proxy_from_bytecode_no_wait( ) .await?; - info!( - "Deployed implementation at {implementation_address:#x} with tx {implementation_tx_hash:#x}" - ); - let (proxy_tx_hash, proxy_address) = deploy_proxy_no_wait( deployer, eth_client, @@ -620,8 +641,6 @@ pub async fn deploy_with_proxy_from_bytecode_no_wait( ) .await?; - info!("Deployed proxy at {proxy_address:#x} with tx {proxy_tx_hash:#x}"); - Ok(ProxyDeployment { proxy_address, proxy_tx_hash, @@ -667,13 +686,10 @@ async fn create2_deploy( deployer: &Signer, eth_client: &EthClient, ) -> Result<(H256, Address), EthClientError> { - let deploy_tx = - build_create2_deploy_tx(salt, init_code, deployer, eth_client, Overrides::default()) - .await?; - let deploy_tx_hash = - send_tx_bump_gas_exponential_backoff(eth_client, deploy_tx, deployer).await?; + let (deploy_tx_hash, deployed_address) = + create2_deploy_no_wait(salt, init_code, deployer, eth_client, Overrides::default()).await?; - let deployed_address = create2_address(salt, keccak(init_code)); + wait_for_transaction_receipt(deploy_tx_hash, eth_client, 10).await?; Ok((deploy_tx_hash, deployed_address)) } From 7e89695669b0bbad9c3f60797948f97e8e99813e Mon Sep 17 00:00:00 2001 From: avilagaston9 Date: Wed, 26 Nov 2025 19:08:51 -0300 Subject: [PATCH 3/5] Fix deployer --- cmd/ethrex/l2/deployer.rs | 58 ++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 16 deletions(-) diff --git a/cmd/ethrex/l2/deployer.rs b/cmd/ethrex/l2/deployer.rs index 8451c32d22b..8fe2f711295 100644 --- a/cmd/ethrex/l2/deployer.rs +++ b/cmd/ethrex/l2/deployer.rs @@ -918,12 +918,6 @@ async fn initialize_contracts( .map_err(|_| { EthClientError::InternalError("Failed to convert gas_price to a u64".to_owned()) })?; - let mut initializer_nonce = eth_client - .get_nonce( - initializer.address(), - BlockIdentifier::Tag(BlockTag::Pending), - ) - .await?; trace!(committer_l1_address = %opts.committer_l1_address, "Using committer L1 address for OnChainProposer initialization"); @@ -950,10 +944,6 @@ async fn initialize_contracts( let deployer_address = get_address_from_secret_key(&opts.private_key.secret_bytes()) .map_err(DeployerError::InternalError)?; - let mut deployer_nonce = eth_client - .get_nonce(deployer_address, BlockIdentifier::Tag(BlockTag::Pending)) - .await?; - info!("Initializing OnChainProposer"); if opts.deploy_based_contracts { @@ -983,6 +973,9 @@ async fn initialize_contracts( )?; let deployer = Signer::Local(LocalSigner::new(opts.private_key)); + let deployer_nonce = eth_client + .get_nonce(deployer.address(), BlockIdentifier::Tag(BlockTag::Pending)) + .await?; let initialize_tx_hash = initialize_contract_no_wait( contract_addresses.on_chain_proposer_address, @@ -1001,11 +994,13 @@ async fn initialize_contracts( info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "OnChainProposer initialized"); - deployer_nonce += 1; tx_hashes.push(initialize_tx_hash); info!("Initializing SequencerRegistry"); let initialize_tx_hash = { + let deployer_nonce = eth_client + .get_nonce(deployer.address(), BlockIdentifier::Tag(BlockTag::Pending)) + .await?; let calldata_values = vec![ Value::Address(opts.sequencer_registry_owner.ok_or( DeployerError::ConfigValueNotSet("--sequencer-registry-owner".to_string()), @@ -1057,6 +1052,12 @@ async fn initialize_contracts( trace!(calldata_values = ?calldata_values, "OnChainProposer initialization calldata values"); let on_chain_proposer_initialization_calldata = encode_calldata(INITIALIZE_ON_CHAIN_PROPOSER_SIGNATURE, &calldata_values)?; + let initializer_nonce = eth_client + .get_nonce( + initializer.address(), + BlockIdentifier::Tag(BlockTag::Pending), + ) + .await?; let initialize_tx_hash = initialize_contract_no_wait( contract_addresses.on_chain_proposer_address, @@ -1073,11 +1074,16 @@ async fn initialize_contracts( ) .await?; info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "OnChainProposer initialized"); - initializer_nonce += 1; tx_hashes.push(initialize_tx_hash); } let initialize_bridge_address_tx_hash = { + let initializer_nonce = eth_client + .get_nonce( + initializer.address(), + BlockIdentifier::Tag(BlockTag::Pending), + ) + .await?; let calldata_values = vec![Value::Address(contract_addresses.bridge_address)]; let on_chain_proposer_initialization_calldata = encode_calldata(INITIALIZE_BRIDGE_ADDRESS_SIGNATURE, &calldata_values)?; @@ -1103,10 +1109,15 @@ async fn initialize_contracts( "OnChainProposer bridge address initialized" ); - initializer_nonce += 1; tx_hashes.push(initialize_bridge_address_tx_hash); if opts.on_chain_proposer_owner != initializer.address() { + let initializer_nonce = eth_client + .get_nonce( + initializer.address(), + BlockIdentifier::Tag(BlockTag::Pending), + ) + .await?; let transfer_ownership_tx_hash = { let owner_transfer_calldata = encode_calldata( TRANSFER_OWNERSHIP_SIGNATURE, @@ -1130,7 +1141,6 @@ async fn initialize_contracts( }; tx_hashes.push(transfer_ownership_tx_hash); - initializer_nonce += 1; if let Some(owner_pk) = opts.on_chain_proposer_owner_pk { let signer = Signer::Local(LocalSigner::new(owner_pk)); @@ -1171,6 +1181,12 @@ async fn initialize_contracts( info!("Initializing CommonBridge"); let initialize_tx_hash = { + let initializer_nonce = eth_client + .get_nonce( + initializer.address(), + BlockIdentifier::Tag(BlockTag::Pending), + ) + .await?; let calldata_values = vec![ Value::Address(initializer.address()), Value::Address(contract_addresses.on_chain_proposer_address), @@ -1196,9 +1212,14 @@ async fn initialize_contracts( }; info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "CommonBridge initialized"); tx_hashes.push(initialize_tx_hash); - initializer_nonce += 1; if let Some(fee_token) = opts.initial_fee_token { + let initializer_nonce = eth_client + .get_nonce( + initializer.address(), + BlockIdentifier::Tag(BlockTag::Pending), + ) + .await?; let register_tx_hash = register_fee_token_no_wait( eth_client, contract_addresses.bridge_address, @@ -1216,10 +1237,15 @@ async fn initialize_contracts( info!(?fee_token, "CommonBridge initial fee token registered"); info!(tx_hash = %format!("{register_tx_hash:#x}"), "Initial fee token registration transaction sent"); tx_hashes.push(register_tx_hash); - initializer_nonce += 1; } if opts.bridge_owner != initializer.address() { + let initializer_nonce = eth_client + .get_nonce( + initializer.address(), + BlockIdentifier::Tag(BlockTag::Pending), + ) + .await?; let transfer_calldata = encode_calldata( TRANSFER_OWNERSHIP_SIGNATURE, &[Value::Address(opts.bridge_owner)], From 69bc2b4d7e7eb8e4ff3578c0fd3af1285d605a79 Mon Sep 17 00:00:00 2001 From: avilagaston9 Date: Thu, 27 Nov 2025 11:57:26 -0300 Subject: [PATCH 4/5] Add comment --- cmd/ethrex/l2/deployer.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/ethrex/l2/deployer.rs b/cmd/ethrex/l2/deployer.rs index 8fe2f711295..d3805dbac5f 100644 --- a/cmd/ethrex/l2/deployer.rs +++ b/cmd/ethrex/l2/deployer.rs @@ -649,6 +649,7 @@ async fn deploy_contracts( ) .await?; + // We can increase the nonce after each deployment since the deployer is the same nonce += 2; info!( From 78a5bedb7cd89a1751ae60b98209b19549ecda4c Mon Sep 17 00:00:00 2001 From: avilagaston9 Date: Thu, 27 Nov 2025 12:22:08 -0300 Subject: [PATCH 5/5] Refactor sdk --- crates/l2/sdk/src/sdk.rs | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/crates/l2/sdk/src/sdk.rs b/crates/l2/sdk/src/sdk.rs index c4dd2741a8a..ca342940d12 100644 --- a/crates/l2/sdk/src/sdk.rs +++ b/crates/l2/sdk/src/sdk.rs @@ -507,11 +507,16 @@ async fn deploy_proxy( implementation_address: Address, salt: &[u8], ) -> Result<(H256, Address), DeployError> { - let init_code = build_proxy_init_code(implementation_address)?; - - create2_deploy(salt, &init_code, deployer, eth_client) - .await - .map_err(DeployError::from) + let (tx_hash, address) = deploy_proxy_no_wait( + deployer, + eth_client, + implementation_address, + salt, + Overrides::default(), + ) + .await?; + wait_for_transaction_receipt(tx_hash, eth_client, 10).await?; + Ok((tx_hash, address)) } /// Same as `deploy_proxy`, but does not wait for the transaction receipt. @@ -680,20 +685,6 @@ async fn build_create2_deploy_tx( .await } -async fn create2_deploy( - salt: &[u8], - init_code: &[u8], - deployer: &Signer, - eth_client: &EthClient, -) -> Result<(H256, Address), EthClientError> { - let (deploy_tx_hash, deployed_address) = - create2_deploy_no_wait(salt, init_code, deployer, eth_client, Overrides::default()).await?; - - wait_for_transaction_receipt(deploy_tx_hash, eth_client, 10).await?; - - Ok((deploy_tx_hash, deployed_address)) -} - async fn create2_deploy_no_wait( salt: &[u8], init_code: &[u8],