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_error, 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(command: BatchCommands, node_url: &str) -> Result<()> {
64 match command {
65 BatchCommands::Send {
66 from,
67 password,
68 password_file,
69 tip,
70 batch_file,
71 count,
72 to,
73 amount,
74 } =>
75 handle_batch_send_command(
76 from,
77 node_url,
78 password,
79 password_file,
80 tip,
81 batch_file,
82 count,
83 to,
84 amount,
85 )
86 .await,
87 BatchCommands::Config { limits, info } =>
88 handle_batch_config_command(node_url, limits, info).await,
89 }
90}
91
92async fn handle_batch_send_command(
94 from_wallet: String,
95 node_url: &str,
96 password: Option<String>,
97 password_file: Option<String>,
98 tip: Option<String>,
99 batch_file: Option<String>,
100 count: Option<u32>,
101 to: Option<String>,
102 amount: Option<String>,
103) -> Result<()> {
104 let quantus_client = QuantusClient::new(node_url).await?;
106
107 let transfers = if let Some(file_path) = batch_file {
109 load_transfers_from_file(&file_path).await?
111 } else if let (Some(count_val), Some(to_addr), Some(amount_str)) = (count, to, amount) {
112 let (parsed_amount, _) = validate_and_format_amount(&quantus_client, &amount_str).await?;
114 let mut transfers = Vec::new();
115 for _ in 0..count_val {
116 transfers.push((to_addr.clone(), parsed_amount));
117 }
118 transfers
119 } else {
120 return Err(crate::error::QuantusError::Generic(
121 "Either --batch-file or (--count + --to + --amount) must be provided".to_string(),
122 ));
123 };
124
125 if transfers.is_empty() {
126 return Err(crate::error::QuantusError::Generic("No transfers to process".to_string()));
127 }
128
129 log_info!("đ Initiating batch transfer with {} transfers", transfers.len());
130
131 let tip_amount = if let Some(tip_str) = tip {
133 let (tip_val, _) = validate_and_format_amount(&quantus_client, &tip_str).await?;
134 Some(tip_val)
135 } else {
136 None
137 };
138
139 let keypair = crate::wallet::load_keypair_from_wallet(&from_wallet, password, password_file)?;
141 let from_account_id = keypair.to_account_id_ss58check();
142
143 let balance = crate::cli::send::get_balance(&quantus_client, &from_account_id).await?;
145 let total_amount: u128 = transfers.iter().map(|(_, amount)| amount).sum();
146 let estimated_fee = 50_000_000_000u128; if balance < total_amount + estimated_fee {
149 let formatted_balance =
150 crate::cli::send::format_balance_with_symbol(&quantus_client, balance).await?;
151 let formatted_needed = crate::cli::send::format_balance_with_symbol(
152 &quantus_client,
153 total_amount + estimated_fee,
154 )
155 .await?;
156 return Err(crate::error::QuantusError::Generic(format!(
157 "Insufficient balance. Have: {formatted_balance}, Need: {formatted_needed} (including estimated fees)"
158 )));
159 }
160
161 let tx_hash = batch_transfer(&quantus_client, &keypair, transfers, tip_amount).await?;
163
164 log_print!(
165 "â
{} Batch transaction submitted! Hash: {:?}",
166 "SUCCESS".bright_green().bold(),
167 tx_hash
168 );
169
170 let success =
171 crate::cli::progress_spinner::wait_for_tx_confirmation(quantus_client.client(), tx_hash)
172 .await?;
173
174 if success {
175 log_info!("â
Batch transaction confirmed and finalized on chain");
176 log_success!("đ {} Batch transaction confirmed!", "FINISHED".bright_green().bold());
177
178 let new_balance = crate::cli::send::get_balance(&quantus_client, &from_account_id).await?;
180 let formatted_new_balance =
181 crate::cli::send::format_balance_with_symbol(&quantus_client, new_balance).await?;
182 log_print!("đ° New balance: {}", formatted_new_balance.bright_yellow());
183 } else {
184 log_error!("Batch transaction failed!");
185 }
186
187 Ok(())
188}
189
190async fn handle_batch_config_command(
192 node_url: &str,
193 show_limits: bool,
194 show_info: bool,
195) -> Result<()> {
196 let quantus_client = QuantusClient::new(node_url).await?;
197
198 if show_limits {
199 log_info!("đ Checking batch transfer limits for chain...");
200
201 let (safe_limit, recommended_limit) = get_batch_limits(&quantus_client).await?;
202
203 log_print!("đ {} Batch Transfer Limits", "CHAIN".bright_cyan().bold());
204 log_print!(" âĸ Safe batch size: {} transfers", safe_limit.to_string().bright_green());
205 log_print!(
206 " âĸ Maximum batch size: {} transfers",
207 recommended_limit.to_string().bright_yellow()
208 );
209 log_print!(" âĸ For larger batches, split into multiple transactions");
210 }
211
212 if show_info {
213 log_print!("âšī¸ {} Batch Transfer Information", "CONFIG".bright_cyan().bold());
214 log_print!(" âĸ Batch transfers use utility.batch() pallet");
215 log_print!(" âĸ All transfers in one transaction (atomic)");
216 log_print!(" âĸ Single nonce used for all transfers");
217 log_print!(" âĸ Lower fees compared to individual transfers");
218 log_print!(" âĸ If one transfer fails, entire batch fails");
219 log_print!("");
220 log_print!("đ {} Usage Examples", "EXAMPLES".bright_cyan().bold());
221 log_print!(" quantus batch send --from alice --count 100 --to bob --amount 1000");
222 log_print!(" quantus batch send --from alice --batch-file transfers.json");
223 log_print!(" quantus batch config --limits");
224 }
225
226 if !show_limits && !show_info {
228 let quantus_client = QuantusClient::new(node_url).await?;
230
231 log_info!("đ Checking batch transfer limits for chain...");
233 let (safe_limit, recommended_limit) = get_batch_limits(&quantus_client).await?;
234 log_print!("đ {} Batch Transfer Limits", "CHAIN".bright_cyan().bold());
235 log_print!(" âĸ Safe batch size: {} transfers", safe_limit.to_string().bright_green());
236 log_print!(
237 " âĸ Maximum batch size: {} transfers",
238 recommended_limit.to_string().bright_yellow()
239 );
240 log_print!(" âĸ For larger batches, split into multiple transactions");
241
242 log_print!("âšī¸ {} Batch Transfer Information", "CONFIG".bright_cyan().bold());
244 log_print!(" âĸ Batch transfers use utility.batch() pallet");
245 log_print!(" âĸ All transfers in one transaction (atomic)");
246 log_print!(" âĸ Single nonce used for all transfers");
247 log_print!(" âĸ Lower fees compared to individual transfers");
248 log_print!(" âĸ If one transfer fails, entire batch fails");
249 log_print!("");
250 log_print!("đ {} Usage Examples", "EXAMPLES".bright_cyan().bold());
251 log_print!(" quantus batch send --from alice --count 100 --to bob --amount 1000");
252 log_print!(" quantus batch send --from alice --batch-file transfers.json");
253 log_print!(" quantus batch config --limits");
254 }
255
256 Ok(())
257}