1use crate::{
7 cmd::{
8 auth::{confirm_and_build, confirm_and_build_with_tempo_wallet},
9 batch_send::with_batch_calls,
10 },
11 tempo,
12 tx::{self, CastTxBuilder},
13};
14use alloy_consensus::SignableTransaction;
15use alloy_eips::eip2718::Encodable2718;
16use alloy_network::{EthereumWallet, NetworkTransactionBuilder};
17use alloy_primitives::{Address, hex};
18use alloy_provider::Provider;
19use clap::Parser;
20use eyre::Result;
21use foundry_cli::{
22 opts::{EthereumOpts, TransactionOpts},
23 utils::{self, resolve_lane},
24};
25use foundry_common::FoundryTransactionBuilder;
26use tempo_alloy::TempoNetwork;
27
28#[derive(Debug, Parser)]
32pub struct BatchMakeTxArgs {
33 #[arg(long = "call", value_name = "SPEC", required = true)]
40 pub calls: Vec<String>,
41
42 #[command(flatten)]
43 pub tx: TransactionOpts,
44
45 #[arg(long)]
47 pub force: bool,
48
49 #[command(flatten)]
50 pub eth: EthereumOpts,
51
52 #[arg(long)]
54 pub raw_unsigned: bool,
55
56 #[arg(long, requires = "from", conflicts_with = "raw_unsigned")]
58 pub ethsign: bool,
59}
60
61impl BatchMakeTxArgs {
62 pub async fn run(self) -> Result<()> {
63 let Self { calls, mut tx, force, eth, raw_unsigned, ethsign } = self;
64 let has_nonce = tx.nonce.is_some();
65 let has_session = tx.tempo.session_id()?.is_some();
66 let expires_at = tx.tempo.resolve_expires();
67
68 if has_session && raw_unsigned {
69 eyre::bail!("--tempo.session/TEMPO_SESSION_ID cannot be combined with --raw-unsigned");
70 }
71 if has_session && ethsign {
72 eyre::bail!("--tempo.session/TEMPO_SESSION_ID cannot be combined with --ethsign");
73 }
74
75 let (config, provider) = tempo::tempo_provider(ð)?;
76 let fee_provider = (!config.eth_rpc_curl).then_some(&provider);
78 let resolved_lane = resolve_lane(&mut tx.tempo, &config.root)?;
79 let lane = resolved_lane.as_ref();
80
81 let chain = utils::get_chain(config.chain, &provider).await?;
82 let (signer, tempo_access_key) = if raw_unsigned {
85 (None, eth.wallet.maybe_signer_for_chain(chain.id()).await?.1)
86 } else {
87 tempo::resolve_session_or_wallet_signer(&tx.tempo, ð.wallet, chain.id()).await?
88 };
89
90 if let Some(access_key) = &tempo_access_key {
92 tx.tempo.key_id = Some(access_key.key_id()?);
93 }
94
95 let builder = CastTxBuilder::<TempoNetwork, _, _>::new(&provider, tx, &config).await?;
96 let tx_builder = with_batch_calls(&calls, builder, &provider).await?;
97 tempo::print_expires(expires_at)?;
98
99 if raw_unsigned {
100 if eth.wallet.from.is_none() && !has_nonce {
101 eyre::bail!(
102 "Missing required parameters for raw unsigned transaction. When --from is not provided, you must specify: --nonce"
103 );
104 }
105
106 let from = eth.wallet.from.unwrap_or(Address::ZERO);
107 let Some(mut tx) = confirm_and_build(tx_builder, from, force, lane, false).await?
108 else {
109 return Ok(());
110 };
111 tempo::resolve_and_print_fee_token(fee_provider, Some(chain), &mut tx, Some(from))
112 .await?;
113 let raw_tx = hex::encode_prefixed(tx.build_unsigned()?.encoded_for_signing());
114 sh_println!("{raw_tx}")?;
115 return Ok(());
116 }
117
118 if ethsign {
119 let Some(mut tx) =
120 confirm_and_build(tx_builder, config.sender, force, lane, true).await?
121 else {
122 return Ok(());
123 };
124 tempo::resolve_and_print_fee_token(
125 fee_provider,
126 Some(chain),
127 &mut tx,
128 Some(config.sender),
129 )
130 .await?;
131 let signed_tx = provider.sign_transaction(tx).await?;
132 sh_println!("{signed_tx}")?;
133 return Ok(());
134 }
135
136 let signed_tx = if let Some(access_key) = &tempo_access_key {
137 let Some((mut tx, prepared)) =
138 confirm_and_build_with_tempo_wallet(tx_builder, access_key, force, lane).await?
139 else {
140 return Ok(());
141 };
142 tempo::resolve_and_print_fee_token(
143 fee_provider,
144 Some(chain),
145 &mut tx,
146 Some(prepared.account()),
147 )
148 .await?;
149 tx.sign_with_tempo_wallet(&prepared).await?
150 } else {
151 let (signer, from) = tx::resolve_send_signer(signer, ð).await?;
152 let Some(mut tx) = confirm_and_build(tx_builder, &signer, force, lane, false).await?
153 else {
154 return Ok(());
155 };
156 tempo::resolve_and_print_fee_token(fee_provider, Some(chain), &mut tx, Some(from))
157 .await?;
158 tx.build(&EthereumWallet::new(signer)).await?.encoded_2718()
159 };
160
161 sh_println!("{}", hex::encode_prefixed(signed_tx))?;
162
163 Ok(())
164 }
165}