1use crate::{
3 chain::client::QuantusClient,
4 cli::send::{
5 batch_transfer, get_batch_limits, load_transfers_from_file, validate_and_format_amount,
6 },
7 error::Result,
8 log_info, log_print, log_success,
9};
10use clap::Subcommand;
11use colored::Colorize;
12
13#[derive(Subcommand, Debug)]
14pub enum BatchCommands {
15 Send {
17 #[arg(short, long)]
19 from: String,
20
21 #[arg(short, long)]
23 password: Option<String>,
24
25 #[arg(long)]
27 password_file: Option<String>,
28
29 #[arg(long)]
31 tip: Option<String>,
32
33 #[arg(long)]
35 batch_file: Option<String>,
36
37 #[arg(long)]
39 count: Option<u32>,
40
41 #[arg(long)]
43 to: Option<String>,
44
45 #[arg(long)]
47 amount: Option<String>,
48 },
49
50 Config {
52 #[arg(long)]
54 limits: bool,
55
56 #[arg(long)]
58 info: bool,
59 },
60}
61
62pub async fn handle_batch_command(
64 command: BatchCommands,
65 node_url: &str,
66 finalized: bool,
67) -> Result<()> {
68 match command {
69 BatchCommands::Send {
70 from,
71 password,
72 password_file,
73 tip,
74 batch_file,
75 count,
76 to,
77 amount,
78 } =>
79 handle_batch_send_command(
80 from,
81 node_url,
82 password,
83 password_file,
84 tip,
85 batch_file,
86 count,
87 to,
88 amount,
89 finalized,
90 )
91 .await,
92 BatchCommands::Config { limits, info } =>
93 handle_batch_config_command(node_url, limits, info).await,
94 }
95}
96
97async fn handle_batch_send_command(
99 from_wallet: String,
100 node_url: &str,
101 password: Option<String>,
102 password_file: Option<String>,
103 tip: Option<String>,
104 batch_file: Option<String>,
105 count: Option<u32>,
106 to: Option<String>,
107 amount: Option<String>,
108 finalized: bool,
109) -> Result<()> {
110 let quantus_client = QuantusClient::new(node_url).await?;
112
113 let transfers = if let Some(file_path) = batch_file {
115 load_transfers_from_file(&file_path).await?
117 } else if let (Some(count_val), Some(to_addr), Some(amount_str)) = (count, to, amount) {
118 let (parsed_amount, _) = validate_and_format_amount(&quantus_client, &amount_str).await?;
120 let mut transfers = Vec::new();
121 for _ in 0..count_val {
122 transfers.push((to_addr.clone(), parsed_amount));
123 }
124 transfers
125 } else {
126 return Err(crate::error::QuantusError::Generic(
127 "Either --batch-file or (--count + --to + --amount) must be provided".to_string(),
128 ));
129 };
130
131 if transfers.is_empty() {
132 return Err(crate::error::QuantusError::Generic("No transfers to process".to_string()));
133 }
134
135 log_info!("🚀 Initiating batch transfer with {} transfers", transfers.len());
136
137 let tip_amount = if let Some(tip_str) = tip {
139 let (tip_val, _) = validate_and_format_amount(&quantus_client, &tip_str).await?;
140 Some(tip_val)
141 } else {
142 None
143 };
144
145 let keypair = crate::wallet::load_keypair_from_wallet(&from_wallet, password, password_file)?;
147 let from_account_id = keypair.to_account_id_ss58check();
148
149 let balance = crate::cli::send::get_balance(&quantus_client, &from_account_id).await?;
151 let total_amount: u128 = transfers.iter().map(|(_, amount)| amount).sum();
152 let estimated_fee = 50_000_000_000u128; if balance < total_amount + estimated_fee {
155 let formatted_balance =
156 crate::cli::send::format_balance_with_symbol(&quantus_client, balance).await?;
157 let formatted_needed = crate::cli::send::format_balance_with_symbol(
158 &quantus_client,
159 total_amount + estimated_fee,
160 )
161 .await?;
162 return Err(crate::error::QuantusError::Generic(format!(
163 "Insufficient balance. Have: {formatted_balance}, Need: {formatted_needed} (including estimated fees)"
164 )));
165 }
166
167 let tx_hash =
169 batch_transfer(&quantus_client, &keypair, transfers, tip_amount, finalized).await?;
170
171 log_print!(
172 "✅ {} Batch transaction submitted! Hash: {:?}",
173 "SUCCESS".bright_green().bold(),
174 tx_hash
175 );
176
177 log_success!("🎉 {} Batch transaction confirmed!", "FINISHED".bright_green().bold());
178
179 let new_balance = crate::cli::send::get_balance(&quantus_client, &from_account_id).await?;
181 let formatted_new_balance =
182 crate::cli::send::format_balance_with_symbol(&quantus_client, new_balance).await?;
183 log_print!("💰 New balance: {}", formatted_new_balance.bright_yellow());
184
185 Ok(())
186}
187
188async fn handle_batch_config_command(
190 node_url: &str,
191 show_limits: bool,
192 show_info: bool,
193) -> Result<()> {
194 let quantus_client = QuantusClient::new(node_url).await?;
195
196 if show_limits {
197 log_info!("🔍 Checking batch transfer limits for chain...");
198
199 let (safe_limit, recommended_limit) = get_batch_limits(&quantus_client).await?;
200
201 log_print!("📊 {} Batch Transfer Limits", "CHAIN".bright_cyan().bold());
202 log_print!(" • Safe batch size: {} transfers", safe_limit.to_string().bright_green());
203 log_print!(
204 " • Maximum batch size: {} transfers",
205 recommended_limit.to_string().bright_yellow()
206 );
207 log_print!(" • For larger batches, split into multiple transactions");
208 }
209
210 if show_info {
211 log_print!("ℹ️ {} Batch Transfer Information", "CONFIG".bright_cyan().bold());
212 log_print!(" • Batch transfers use utility.batch() pallet");
213 log_print!(" • All transfers in one transaction (atomic)");
214 log_print!(" • Single nonce used for all transfers");
215 log_print!(" • Lower fees compared to individual transfers");
216 log_print!(" • If one transfer fails, entire batch fails");
217 log_print!("");
218 log_print!("📝 {} Usage Examples", "EXAMPLES".bright_cyan().bold());
219 log_print!(" quantus batch send --from alice --count 100 --to bob --amount 1000");
220 log_print!(" quantus batch send --from alice --batch-file transfers.json");
221 log_print!(" quantus batch config --limits");
222 }
223
224 if !show_limits && !show_info {
226 let quantus_client = QuantusClient::new(node_url).await?;
228
229 log_info!("🔍 Checking batch transfer limits for chain...");
231 let (safe_limit, recommended_limit) = get_batch_limits(&quantus_client).await?;
232 log_print!("📊 {} Batch Transfer Limits", "CHAIN".bright_cyan().bold());
233 log_print!(" • Safe batch size: {} transfers", safe_limit.to_string().bright_green());
234 log_print!(
235 " • Maximum batch size: {} transfers",
236 recommended_limit.to_string().bright_yellow()
237 );
238 log_print!(" • For larger batches, split into multiple transactions");
239
240 log_print!("ℹ️ {} Batch Transfer Information", "CONFIG".bright_cyan().bold());
242 log_print!(" • Batch transfers use utility.batch() pallet");
243 log_print!(" • All transfers in one transaction (atomic)");
244 log_print!(" • Single nonce used for all transfers");
245 log_print!(" • Lower fees compared to individual transfers");
246 log_print!(" • If one transfer fails, entire batch fails");
247 log_print!("");
248 log_print!("📝 {} Usage Examples", "EXAMPLES".bright_cyan().bold());
249 log_print!(" quantus batch send --from alice --count 100 --to bob --amount 1000");
250 log_print!(" quantus batch send --from alice --batch-file transfers.json");
251 log_print!(" quantus batch config --limits");
252 }
253
254 Ok(())
255}