-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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` * refactor: similar code in `cast send` and `cast mktx` * update clap --------- Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
- Loading branch information
Showing
8 changed files
with
290 additions
and
51 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
use crate::tx; | ||
use clap::Parser; | ||
use ethers_core::types::NameOrAddress; | ||
use ethers_middleware::MiddlewareBuilder; | ||
use ethers_providers::Middleware; | ||
use ethers_signers::Signer; | ||
use eyre::Result; | ||
use foundry_cli::{ | ||
opts::{EthereumOpts, TransactionOpts}, | ||
utils, | ||
}; | ||
use foundry_common::types::ToAlloy; | ||
use foundry_config::Config; | ||
use std::str::FromStr; | ||
|
||
/// CLI arguments for `cast mktx`. | ||
#[derive(Debug, Parser)] | ||
pub struct MakeTxArgs { | ||
/// The destination of the transaction. | ||
/// | ||
/// If not provided, you must use `cast mktx --create`. | ||
#[arg(value_parser = NameOrAddress::from_str)] | ||
to: Option<NameOrAddress>, | ||
|
||
/// The signature of the function to call. | ||
sig: Option<String>, | ||
|
||
/// The arguments of the function to call. | ||
args: Vec<String>, | ||
|
||
/// Reuse the latest nonce for the sender account. | ||
#[arg(long, conflicts_with = "nonce")] | ||
resend: bool, | ||
|
||
#[command(subcommand)] | ||
command: Option<MakeTxSubcommands>, | ||
|
||
#[command(flatten)] | ||
tx: TransactionOpts, | ||
|
||
#[command(flatten)] | ||
eth: EthereumOpts, | ||
} | ||
|
||
#[derive(Debug, Parser)] | ||
pub enum MakeTxSubcommands { | ||
/// Use to deploy raw contract bytecode. | ||
#[clap(name = "--create")] | ||
Create { | ||
/// The initialization bytecode of the contract to deploy. | ||
code: String, | ||
|
||
/// The signature of the constructor. | ||
sig: Option<String>, | ||
|
||
/// The constructor arguments. | ||
args: Vec<String>, | ||
}, | ||
} | ||
|
||
impl MakeTxArgs { | ||
pub async fn run(self) -> Result<()> { | ||
let MakeTxArgs { to, mut sig, mut args, resend, command, mut tx, eth } = self; | ||
|
||
let code = if let Some(MakeTxSubcommands::Create { | ||
code, | ||
sig: constructor_sig, | ||
args: constructor_args, | ||
}) = command | ||
{ | ||
sig = constructor_sig; | ||
args = constructor_args; | ||
Some(code) | ||
} else { | ||
None | ||
}; | ||
|
||
tx::validate_to_address(&code, &to)?; | ||
|
||
let config = Config::from(ð); | ||
let provider = utils::get_provider(&config)?; | ||
let chain = utils::get_chain(config.chain, &provider).await?; | ||
let api_key = config.get_etherscan_api_key(Some(chain)); | ||
|
||
// Retrieve the signer, and bail if it can't be constructed. | ||
let signer = eth.wallet.signer().await?; | ||
let from = signer.address(); | ||
|
||
tx::validate_from_address(eth.wallet.from, from.to_alloy())?; | ||
|
||
if resend { | ||
tx.nonce = Some(provider.get_transaction_count(from, None).await?.to_alloy()); | ||
} | ||
|
||
let provider = provider.with_signer(signer); | ||
|
||
let (mut tx, _) = | ||
tx::build_tx(&provider, from, to, code, sig, args, tx, chain, api_key).await?; | ||
|
||
// Fill nonce, gas limit, gas price, and max priority fee per gas if needed | ||
provider.fill_transaction(&mut tx, None).await?; | ||
|
||
let signature = provider.sign_transaction(&tx, from).await?; | ||
let signed_tx = tx.rlp_signed(&signature); | ||
println!("{signed_tx}"); | ||
|
||
Ok(()) | ||
} | ||
} |
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
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
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,73 @@ | ||
use alloy_primitives::Address; | ||
use cast::{TxBuilder, TxBuilderOutput}; | ||
use ethers_core::types::NameOrAddress; | ||
use ethers_providers::Middleware; | ||
use eyre::Result; | ||
use foundry_cli::opts::TransactionOpts; | ||
use foundry_config::Chain; | ||
|
||
/// Prevents a misconfigured hwlib from sending a transaction that defies user-specified --from | ||
pub fn validate_from_address( | ||
specified_from: Option<Address>, | ||
signer_address: Address, | ||
) -> Result<()> { | ||
if let Some(specified_from) = specified_from { | ||
if specified_from != signer_address { | ||
eyre::bail!( | ||
"\ | ||
The specified sender via CLI/env vars does not match the sender configured via | ||
the hardware wallet's HD Path. | ||
Please use the `--hd-path <PATH>` parameter to specify the BIP32 Path which | ||
corresponds to the sender, or let foundry automatically detect it by not specifying any sender address." | ||
) | ||
} | ||
} | ||
Ok(()) | ||
} | ||
|
||
/// Ensures the transaction is either a contract deployment or a recipient address is specified | ||
pub fn validate_to_address(code: &Option<String>, to: &Option<NameOrAddress>) -> Result<()> { | ||
if code.is_none() && to.is_none() { | ||
eyre::bail!("Must specify a recipient address or contract code to deploy"); | ||
} | ||
Ok(()) | ||
} | ||
|
||
#[allow(clippy::too_many_arguments)] | ||
pub async fn build_tx<M: Middleware, F: Into<NameOrAddress>, T: Into<NameOrAddress>>( | ||
provider: &M, | ||
from: F, | ||
to: Option<T>, | ||
code: Option<String>, | ||
sig: Option<String>, | ||
args: Vec<String>, | ||
tx: TransactionOpts, | ||
chain: impl Into<Chain>, | ||
etherscan_api_key: Option<String>, | ||
) -> Result<TxBuilderOutput> { | ||
let mut builder = TxBuilder::new(provider, from, to, chain, tx.legacy).await?; | ||
builder | ||
.etherscan_api_key(etherscan_api_key) | ||
.gas(tx.gas_limit) | ||
.gas_price(tx.gas_price) | ||
.priority_gas_price(tx.priority_gas_price) | ||
.value(tx.value) | ||
.nonce(tx.nonce); | ||
|
||
let params = sig.as_deref().map(|sig| (sig, args)); | ||
if let Some(code) = code { | ||
let mut data = hex::decode(code)?; | ||
|
||
if let Some((sig, args)) = params { | ||
let (mut sigdata, _) = builder.create_args(sig, args).await?; | ||
data.append(&mut sigdata); | ||
} | ||
|
||
builder.set_data(data); | ||
} else { | ||
builder.args(params).await?; | ||
} | ||
|
||
let builder_output = builder.build(); | ||
Ok(builder_output) | ||
} |
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.