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)]
43 pub calls: Vec<String>,
44
45 #[command(flatten)]
46 pub tx: TransactionOpts,
47
48 #[arg(long)]
50 pub force: bool,
51
52 #[command(flatten)]
53 pub eth: EthereumOpts,
54
55 #[arg(long)]
57 pub raw_unsigned: bool,
58
59 #[arg(long, requires = "from", conflicts_with = "raw_unsigned")]
61 pub ethsign: bool,
62}
63
64impl BatchMakeTxArgs {
65 pub async fn run(self) -> Result<()> {
66 let Self { calls, mut tx, force, eth, raw_unsigned, ethsign } = self;
67 let has_nonce = tx.nonce.is_some();
68 let has_session = tx.tempo.session_id()?.is_some();
69 let expires_at = tx.tempo.resolve_expires();
70
71 if has_session && raw_unsigned {
72 eyre::bail!("--tempo.session/TEMPO_SESSION_ID cannot be combined with --raw-unsigned");
73 }
74 if has_session && ethsign {
75 eyre::bail!("--tempo.session/TEMPO_SESSION_ID cannot be combined with --ethsign");
76 }
77
78 let (config, provider) = tempo::tempo_provider(ð)?;
79 let fee_provider = (!config.eth_rpc_curl).then_some(&provider);
81 let resolved_lane = resolve_lane(&mut tx.tempo, &config.root)?;
82 let lane = resolved_lane.as_ref();
83
84 let chain = utils::get_chain(config.chain, &provider).await?;
85 let (signer, tempo_access_key) = if raw_unsigned {
88 (None, eth.wallet.maybe_signer_for_chain(chain.id()).await?.1)
89 } else {
90 tempo::resolve_session_or_wallet_signer(&tx.tempo, ð.wallet, chain.id()).await?
91 };
92
93 if let Some(access_key) = &tempo_access_key {
95 tx.tempo.key_id = Some(access_key.key_id()?);
96 }
97
98 let builder = CastTxBuilder::<TempoNetwork, _, _>::new(&provider, tx, &config).await?;
99 let tx_builder = with_batch_calls(&calls, builder, &provider).await?;
100 tempo::print_expires(expires_at)?;
101
102 if raw_unsigned {
103 if eth.wallet.from.is_none() && !has_nonce {
104 eyre::bail!(
105 "Missing required parameters for raw unsigned transaction. When --from is not provided, you must specify: --nonce"
106 );
107 }
108
109 let from = eth.wallet.from.unwrap_or(Address::ZERO);
110 let Some(mut tx) = confirm_and_build(tx_builder, from, force, lane, false).await?
111 else {
112 return Ok(());
113 };
114 tempo::resolve_and_print_fee_token(fee_provider, &mut tx, Some(from)).await?;
115 let raw_tx = hex::encode_prefixed(tx.build_unsigned()?.encoded_for_signing());
116 sh_println!("{raw_tx}")?;
117 return Ok(());
118 }
119
120 if ethsign {
121 let Some(mut tx) =
122 confirm_and_build(tx_builder, config.sender, force, lane, true).await?
123 else {
124 return Ok(());
125 };
126 tempo::resolve_and_print_fee_token(fee_provider, &mut tx, Some(config.sender)).await?;
127 let signed_tx = provider.sign_transaction(tx).await?;
128 sh_println!("{signed_tx}")?;
129 return Ok(());
130 }
131
132 let signed_tx = if let Some(access_key) = &tempo_access_key {
133 let Some((mut tx, prepared)) =
134 confirm_and_build_with_tempo_wallet(tx_builder, access_key, force, lane).await?
135 else {
136 return Ok(());
137 };
138 tempo::resolve_and_print_fee_token(fee_provider, &mut tx, Some(prepared.account()))
139 .await?;
140 tx.sign_with_tempo_wallet(&prepared).await?
141 } else {
142 let (signer, from) = tx::resolve_send_signer(signer, ð).await?;
143 let Some(mut tx) = confirm_and_build(tx_builder, &signer, force, lane, false).await?
144 else {
145 return Ok(());
146 };
147 tempo::resolve_and_print_fee_token(fee_provider, &mut tx, Some(from)).await?;
148 tx.build(&EthereumWallet::new(signer)).await?.encoded_2718()
149 };
150
151 sh_println!("{}", hex::encode_prefixed(signed_tx))?;
152
153 Ok(())
154 }
155}