-
Notifications
You must be signed in to change notification settings - Fork 140
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: cast mktx and mktx --create support (#911)
* Add mktx branching for zksync, added tests and nonce fix to have it available for the TxEIP712 * Cargo fmt * Move estimate and mktx common logic to cast zksync module * Put common logic in zksync cast module and the rest on mktx and estimate submodules for zksync * clippy and missing import
- Loading branch information
Showing
7 changed files
with
222 additions
and
85 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,93 +1,18 @@ | ||
use alloy_network::TransactionBuilder; | ||
use alloy_primitives::{hex, Address, Bytes, TxKind, U256}; | ||
use alloy_provider::Provider; | ||
use alloy_rpc_types::TransactionRequest; | ||
use alloy_serde::WithOtherFields; | ||
use alloy_zksync::network::{ | ||
transaction_request::TransactionRequest as ZkTransactionRequest, | ||
unsigned_tx::eip712::PaymasterParams, | ||
}; | ||
use clap::{command, Parser}; | ||
use cast::ZkTransactionOpts; | ||
use eyre::Result; | ||
use foundry_cli::utils; | ||
use foundry_config::Config; | ||
|
||
#[derive(Clone, Debug, Parser)] | ||
#[command(next_help_heading = "Transaction options")] | ||
pub struct ZkTransactionOpts { | ||
/// Paymaster address for the ZKSync transaction | ||
#[arg(long = "zk-paymaster-address", requires = "paymaster_input")] | ||
pub paymaster_address: Option<Address>, | ||
|
||
/// Paymaster input for the ZKSync transaction | ||
#[arg(long = "zk-paymaster-input", requires = "paymaster_address", value_parser = parse_hex_bytes)] | ||
pub paymaster_input: Option<Bytes>, | ||
|
||
/// Factory dependencies for the ZKSync transaction | ||
#[arg(long = "zk-factory-deps", value_parser = parse_hex_bytes, value_delimiter = ',')] | ||
pub factory_deps: Vec<Bytes>, | ||
|
||
// TODO: fix custom signature serialization and then add this field | ||
// /// Custom signature for the ZKSync transaction | ||
// #[arg(long = "zk-custom-signature", value_parser = parse_hex_bytes)] | ||
// pub custom_signature: Option<Bytes>, | ||
/// Gas per pubdata for the ZKSync transaction | ||
#[arg(long = "zk-gas-per-pubdata")] | ||
pub gas_per_pubdata: Option<U256>, | ||
} | ||
|
||
fn parse_hex_bytes(s: &str) -> Result<Bytes, String> { | ||
hex::decode(s).map(Bytes::from).map_err(|e| format!("Invalid hex string: {e}")) | ||
} | ||
|
||
impl ZkTransactionOpts { | ||
pub fn has_zksync_args(&self) -> bool { | ||
self.paymaster_address.is_some() | ||
|| !self.factory_deps.is_empty() | ||
// TODO: add this when fixing serialization || self.custom_signature.is_some() | ||
|| self.gas_per_pubdata.is_some() | ||
} | ||
} | ||
|
||
/// Estimates gas for a ZkSync transaction | ||
pub async fn estimate_gas( | ||
zk_tx: ZkTransactionOpts, | ||
config: &Config, | ||
evm_tx: WithOtherFields<TransactionRequest>, | ||
zk_code: Option<String>, | ||
config: &Config, | ||
) -> Result<u64> { | ||
let zk_provider = utils::get_provider_zksync(config)?; | ||
let is_create = evm_tx.to == Some(TxKind::Create); | ||
let mut tx: ZkTransactionRequest = evm_tx.inner.clone().into(); | ||
if let Some(gas_per_pubdata) = zk_tx.gas_per_pubdata { | ||
tx.set_gas_per_pubdata(gas_per_pubdata) | ||
} | ||
|
||
// TODO: Fix custom_signature serialization and then add this field | ||
// if let Some(custom_signature) = &zk_tx.custom_signature { | ||
// tx.set_custom_signature(custom_signature.clone()); | ||
// } | ||
|
||
if let (Some(paymaster), Some(paymaster_input)) = | ||
(zk_tx.paymaster_address, zk_tx.paymaster_input.clone()) | ||
{ | ||
tx.set_paymaster_params(PaymasterParams { paymaster, paymaster_input }); | ||
} | ||
|
||
if is_create { | ||
let evm_input: Vec<u8> = tx.input().cloned().map(|bytes| bytes.into()).unwrap_or_default(); | ||
let zk_code_decoded = hex::decode(zk_code.unwrap_or_default())?; | ||
// constructor input gets appended to the bytecode | ||
let zk_input = &evm_input[zk_code_decoded.len()..]; | ||
tx = tx.with_create_params( | ||
zk_code_decoded, | ||
zk_input.to_vec(), | ||
zk_tx.factory_deps.into_iter().map(|v| v.into()).collect(), | ||
)?; | ||
} else { | ||
tx.set_factory_deps(zk_tx.factory_deps.clone()); | ||
} | ||
|
||
// TODO: Check if alloy calls this for estimate_gas. If so, we do not need this. | ||
tx.prep_for_submission(); | ||
let tx = zk_tx.build_base_tx(evm_tx, zk_code)?; | ||
Ok(zk_provider.estimate_gas(&tx).await?) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
use alloy_network::TransactionBuilder; | ||
use alloy_rpc_types::TransactionRequest; | ||
use alloy_serde::WithOtherFields; | ||
use alloy_zksync::{ | ||
network::transaction_request::TransactionRequest as ZkTransactionRequest, | ||
provider::ZksyncProvider, | ||
}; | ||
use cast::ZkTransactionOpts; | ||
use eyre::Result; | ||
use foundry_cli::utils; | ||
use foundry_config::Config; | ||
|
||
/// Builds a complete ZkSync transaction request with fee estimation | ||
pub async fn build_tx( | ||
zk_tx: ZkTransactionOpts, | ||
evm_tx: WithOtherFields<TransactionRequest>, | ||
zk_code: String, | ||
config: &Config, | ||
) -> Result<ZkTransactionRequest> { | ||
let zk_provider = utils::get_provider_zksync(config)?; | ||
let mut tx = zk_tx.build_base_tx(evm_tx, Some(zk_code))?; | ||
|
||
let fee = ZksyncProvider::estimate_fee(&zk_provider, tx.clone()).await?; | ||
tx.set_max_fee_per_gas(fee.max_fee_per_gas); | ||
tx.set_max_priority_fee_per_gas(fee.max_priority_fee_per_gas); | ||
tx.set_gas_limit(fee.gas_limit); | ||
|
||
Ok(tx) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.