1use crate::tx::{self, CastTxBuilder};
2use alloy_network::{eip2718::Encodable2718, EthereumWallet, TransactionBuilder};
3use alloy_primitives::hex;
4use alloy_signer::Signer;
5use clap::Parser;
6use eyre::{OptionExt, Result};
7use foundry_cli::{
8 opts::{EthereumOpts, TransactionOpts},
9 utils::{get_provider, LoadConfig},
10};
11use foundry_common::ens::NameOrAddress;
12use std::{path::PathBuf, str::FromStr};
13
14#[derive(Debug, Parser)]
16pub struct MakeTxArgs {
17 #[arg(value_parser = NameOrAddress::from_str)]
21 to: Option<NameOrAddress>,
22
23 sig: Option<String>,
25
26 args: Vec<String>,
28
29 #[command(subcommand)]
30 command: Option<MakeTxSubcommands>,
31
32 #[command(flatten)]
33 tx: TransactionOpts,
34
35 #[arg(
37 long,
38 value_name = "BLOB_DATA_PATH",
39 conflicts_with = "legacy",
40 requires = "blob",
41 help_heading = "Transaction options"
42 )]
43 path: Option<PathBuf>,
44
45 #[command(flatten)]
46 eth: EthereumOpts,
47
48 #[arg(long, requires = "from")]
52 raw_unsigned: bool,
53}
54
55#[derive(Debug, Parser)]
56pub enum MakeTxSubcommands {
57 #[command(name = "--create")]
59 Create {
60 code: String,
62
63 sig: Option<String>,
65
66 args: Vec<String>,
68 },
69}
70
71impl MakeTxArgs {
72 pub async fn run(self) -> Result<()> {
73 let Self { to, mut sig, mut args, command, tx, path, eth, raw_unsigned } = self;
74
75 let blob_data = if let Some(path) = path { Some(std::fs::read(path)?) } else { None };
76
77 let code = if let Some(MakeTxSubcommands::Create {
78 code,
79 sig: constructor_sig,
80 args: constructor_args,
81 }) = command
82 {
83 sig = constructor_sig;
84 args = constructor_args;
85 Some(code)
86 } else {
87 None
88 };
89
90 let config = eth.load_config()?;
91
92 let provider = get_provider(&config)?;
93
94 let tx_builder = CastTxBuilder::new(provider, tx, &config)
95 .await?
96 .with_to(to)
97 .await?
98 .with_code_sig_and_args(code, sig, args)
99 .await?
100 .with_blob_data(blob_data)?;
101
102 if raw_unsigned {
103 let from = eth.wallet.from.ok_or_eyre("missing `--from` address")?;
105 let raw_tx = tx_builder.build_unsigned_raw(from).await?;
106
107 sh_println!("{raw_tx}")?;
108 return Ok(());
109 }
110
111 let signer = eth.wallet.signer().await?;
113 let from = signer.address();
114
115 tx::validate_from_address(eth.wallet.from, from)?;
116
117 let (tx, _) = tx_builder.build(&signer).await?;
118
119 let tx = tx.build(&EthereumWallet::new(signer)).await?;
120
121 let signed_tx = hex::encode(tx.encoded_2718());
122 sh_println!("0x{signed_tx}")?;
123
124 Ok(())
125 }
126}