1use crate::{
3 chain::quantus_subxt, error::QuantusError, log_error, log_print, log_success, log_verbose,
4 wallet::QuantumKeyPair,
5};
6use colored::Colorize;
7use serde_json::Value;
8use sp_core::crypto::{AccountId32, Ss58Codec};
9
10pub async fn execute_generic_call(
12 quantus_client: &crate::chain::client::QuantusClient,
13 pallet: &str,
14 call: &str,
15 args: Vec<Value>,
16 from_keypair: &QuantumKeyPair,
17 tip: Option<String>,
18 finalized: bool,
19) -> crate::error::Result<subxt::utils::H256> {
20 log_print!("🚀 Executing generic call");
21 log_print!("Pallet: {}", pallet.bright_green());
22 log_print!("Call: {}", call.bright_cyan());
23 log_print!("From: {}", from_keypair.to_account_id_ss58check().bright_yellow());
24 if let Some(tip) = &tip {
25 log_print!("Tip: {}", tip.bright_magenta());
26 }
27
28 let _signer = from_keypair
30 .to_subxt_signer()
31 .map_err(|e| QuantusError::NetworkError(format!("Failed to convert keypair: {e:?}")))?;
32
33 let metadata = quantus_client.client().metadata();
35 let pallet_metadata = metadata
36 .pallet_by_name(pallet)
37 .ok_or_else(|| QuantusError::Generic(format!("Pallet '{pallet}' not found in metadata")))?;
38
39 log_verbose!("✅ Found pallet '{}' with index {}", pallet, pallet_metadata.index());
40
41 let call_metadata = pallet_metadata.call_variant_by_name(call).ok_or_else(|| {
43 QuantusError::Generic(format!("Call '{call}' not found in pallet '{pallet}'"))
44 })?;
45
46 log_verbose!("✅ Found call '{}' with index {}", call, call_metadata.index);
47
48 let tip_amount = if let Some(tip_str) = &tip { tip_str.parse::<u128>().ok() } else { None };
50
51 log_print!("🔧 Creating extrinsic for {}.{}", pallet, call);
53
54 let tx_hash = match (pallet, call) {
55 ("Balances", "transfer_allow_death") =>
57 submit_balance_transfer(
58 quantus_client,
59 from_keypair,
60 &args,
61 false,
62 tip_amount,
63 finalized,
64 )
65 .await?,
66 ("Balances", "transfer_keep_alive") =>
67 submit_balance_transfer(
68 quantus_client,
69 from_keypair,
70 &args,
71 true,
72 tip_amount,
73 finalized,
74 )
75 .await?,
76
77 ("System", "remark") =>
79 submit_system_remark(quantus_client, from_keypair, &args, tip_amount, finalized).await?,
80
81 ("Sudo", "sudo") => submit_sudo_call(quantus_client, from_keypair, &args).await?,
83
84 ("TechCollective", "add_member") =>
86 submit_tech_collective_add_member(quantus_client, from_keypair, &args, finalized)
87 .await?,
88 ("TechCollective", "remove_member") =>
89 submit_tech_collective_remove_member(quantus_client, from_keypair, &args, finalized)
90 .await?,
91 ("TechCollective", "vote") =>
92 submit_tech_collective_vote(quantus_client, from_keypair, &args, finalized).await?,
93
94 ("ReversibleTransfers", "schedule_transfer") =>
96 submit_reversible_transfer(quantus_client, from_keypair, &args, finalized).await?,
97
98 ("Scheduler", "schedule") =>
100 submit_scheduler_schedule(quantus_client, from_keypair, &args).await?,
101 ("Scheduler", "cancel") =>
102 submit_scheduler_cancel(quantus_client, from_keypair, &args).await?,
103
104 (_, _) => {
106 log_error!(
107 "❌ Pallet '{}' or call '{}' is not supported yet in SubXT implementation",
108 pallet,
109 call
110 );
111 log_print!("💡 Supported pallets in SubXT:");
112 log_print!(" • Balances: transfer_allow_death, transfer_keep_alive");
113 log_print!(" • System: remark");
114 log_print!(" • Sudo: sudo");
115 log_print!(" • TechCollective: add_member, remove_member, vote");
116 log_print!(" • ReversibleTransfers: schedule_transfer");
117 log_print!(" • Scheduler: schedule, cancel");
118 log_print!("💡 For other calls, use the original 'quantus call' command");
119 return Err(QuantusError::Generic(format!(
120 "Unsupported pallet/call combination in SubXT: {pallet}.{call}"
121 )));
122 },
123 };
124
125 log_success!("🎉 SubXT transaction submitted successfully!");
126 log_print!("📋 Transaction hash: {}", format!("0x{}", hex::encode(tx_hash)).bright_yellow());
127
128 Ok(tx_hash)
129}
130
131async fn submit_balance_transfer(
133 quantus_client: &crate::chain::client::QuantusClient,
134 from_keypair: &QuantumKeyPair,
135 args: &[Value],
136 keep_alive: bool,
137 tip: Option<u128>,
138 finalized: bool,
139) -> crate::error::Result<subxt::utils::H256> {
140 if args.len() != 2 {
141 return Err(QuantusError::Generic(
142 "Balances transfer requires 2 arguments: [to_address, amount]".to_string(),
143 ));
144 }
145
146 let to_address = args[0].as_str().ok_or_else(|| {
147 QuantusError::Generic("First argument must be a string (to_address)".to_string())
148 })?;
149
150 let amount: u128 = args[1].as_str().unwrap_or("0").parse().map_err(|_| {
151 QuantusError::Generic("Second argument must be a number (amount)".to_string())
152 })?;
153
154 let (to_account_id, _) = AccountId32::from_ss58check_with_version(to_address)
156 .map_err(|e| QuantusError::Generic(format!("Invalid to_address: {e:?}")))?;
157
158 let to_account_id_bytes: [u8; 32] = *to_account_id.as_ref();
160 let to_account_id_subxt = subxt::ext::subxt_core::utils::AccountId32::from(to_account_id_bytes);
161
162 if keep_alive {
164 let transfer_call = quantus_subxt::api::tx().balances().transfer_keep_alive(
165 subxt::ext::subxt_core::utils::MultiAddress::Id(to_account_id_subxt),
166 amount,
167 );
168 crate::cli::common::submit_transaction(
169 quantus_client,
170 from_keypair,
171 transfer_call,
172 tip,
173 finalized,
174 )
175 .await
176 } else {
177 let transfer_call = quantus_subxt::api::tx().balances().transfer_allow_death(
178 subxt::ext::subxt_core::utils::MultiAddress::Id(to_account_id_subxt),
179 amount,
180 );
181 crate::cli::common::submit_transaction(
182 quantus_client,
183 from_keypair,
184 transfer_call,
185 tip,
186 finalized,
187 )
188 .await
189 }
190}
191
192async fn submit_system_remark(
194 quantus_client: &crate::chain::client::QuantusClient,
195 from_keypair: &QuantumKeyPair,
196 args: &[Value],
197 tip: Option<u128>,
198 finalized: bool,
199) -> crate::error::Result<subxt::utils::H256> {
200 if args.len() != 1 {
201 return Err(QuantusError::Generic(
202 "System remark requires 1 argument: [remark]".to_string(),
203 ));
204 }
205
206 let remark = args[0]
207 .as_str()
208 .ok_or_else(|| QuantusError::Generic("Argument must be a string (remark)".to_string()))?;
209
210 let remark_call = quantus_subxt::api::tx().system().remark(remark.as_bytes().to_vec());
211
212 crate::cli::common::submit_transaction(
213 quantus_client,
214 from_keypair,
215 remark_call,
216 tip,
217 finalized,
218 )
219 .await
220}
221
222async fn submit_sudo_call(
224 _quantus_client: &crate::chain::client::QuantusClient,
225 _from_keypair: &QuantumKeyPair,
226 _args: &[Value],
227) -> crate::error::Result<subxt::utils::H256> {
228 log_error!("❌ Sudo calls through generic call are complex - use specific sudo wrappers");
230 log_print!("💡 Use dedicated subxt commands that already wrap calls in sudo");
231 Err(QuantusError::Generic(
232 "Sudo calls not supported in generic call - use specific commands".to_string(),
233 ))
234}
235
236async fn submit_tech_collective_add_member(
238 quantus_client: &crate::chain::client::QuantusClient,
239 from_keypair: &QuantumKeyPair,
240 args: &[Value],
241 finalized: bool,
242) -> crate::error::Result<subxt::utils::H256> {
243 if args.len() != 1 {
244 return Err(QuantusError::Generic(
245 "TechCollective add_member requires 1 argument: [member_address]".to_string(),
246 ));
247 }
248
249 let member_address = args[0].as_str().ok_or_else(|| {
250 QuantusError::Generic("Argument must be a string (member_address)".to_string())
251 })?;
252
253 let (member_account_id, _) = AccountId32::from_ss58check_with_version(member_address)
254 .map_err(|e| QuantusError::Generic(format!("Invalid member_address: {e:?}")))?;
255
256 let member_account_id_bytes: [u8; 32] = *member_account_id.as_ref();
258 let member_account_id_subxt =
259 subxt::ext::subxt_core::utils::AccountId32::from(member_account_id_bytes);
260
261 let sudo_call = quantus_subxt::api::tx().sudo().sudo(quantus_subxt::api::Call::TechCollective(
263 quantus_subxt::api::tech_collective::Call::add_member {
264 who: subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id_subxt),
265 },
266 ));
267
268 crate::cli::common::submit_transaction(quantus_client, from_keypair, sudo_call, None, finalized)
269 .await
270}
271
272async fn submit_tech_collective_remove_member(
274 quantus_client: &crate::chain::client::QuantusClient,
275 from_keypair: &QuantumKeyPair,
276 args: &[Value],
277 finalized: bool,
278) -> crate::error::Result<subxt::utils::H256> {
279 if args.len() != 1 {
280 return Err(QuantusError::Generic(
281 "TechCollective remove_member requires 1 argument: [member_address]".to_string(),
282 ));
283 }
284
285 let member_address = args[0].as_str().ok_or_else(|| {
286 QuantusError::Generic("Argument must be a string (member_address)".to_string())
287 })?;
288
289 let (member_account_id, _) = AccountId32::from_ss58check_with_version(member_address)
290 .map_err(|e| QuantusError::Generic(format!("Invalid member_address: {e:?}")))?;
291
292 let member_account_id_bytes: [u8; 32] = *member_account_id.as_ref();
294 let member_account_id_subxt =
295 subxt::ext::subxt_core::utils::AccountId32::from(member_account_id_bytes);
296
297 let sudo_call = quantus_subxt::api::tx().sudo().sudo(quantus_subxt::api::Call::TechCollective(
299 quantus_subxt::api::tech_collective::Call::remove_member {
300 who: subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id_subxt),
301 min_rank: 0, },
303 ));
304
305 crate::cli::common::submit_transaction(quantus_client, from_keypair, sudo_call, None, finalized)
306 .await
307}
308
309async fn submit_tech_collective_vote(
311 quantus_client: &crate::chain::client::QuantusClient,
312 from_keypair: &QuantumKeyPair,
313 args: &[Value],
314 finalized: bool,
315) -> crate::error::Result<subxt::utils::H256> {
316 if args.len() != 2 {
317 return Err(QuantusError::Generic(
318 "TechCollective vote requires 2 arguments: [referendum_index, aye]".to_string(),
319 ));
320 }
321
322 let referendum_index: u32 = args[0].as_u64().unwrap_or(0) as u32;
323 let aye = args[1].as_bool().unwrap_or(false);
324
325 let vote_call = quantus_subxt::api::tx().tech_collective().vote(referendum_index, aye);
326
327 crate::cli::common::submit_transaction(quantus_client, from_keypair, vote_call, None, finalized)
328 .await
329}
330
331async fn submit_reversible_transfer(
333 quantus_client: &crate::chain::client::QuantusClient,
334 from_keypair: &QuantumKeyPair,
335 args: &[Value],
336 finalized: bool,
337) -> crate::error::Result<subxt::utils::H256> {
338 if args.len() != 2 {
339 return Err(QuantusError::Generic(
340 "ReversibleTransfers schedule_transfer requires 2 arguments: [to_address, amount]"
341 .to_string(),
342 ));
343 }
344
345 let to_address = args[0].as_str().ok_or_else(|| {
346 QuantusError::Generic("First argument must be a string (to_address)".to_string())
347 })?;
348
349 let amount: u128 = args[1].as_str().unwrap_or("0").parse().map_err(|_| {
350 QuantusError::Generic("Second argument must be a number (amount)".to_string())
351 })?;
352
353 let (to_account_id, _) = AccountId32::from_ss58check_with_version(to_address)
354 .map_err(|e| QuantusError::Generic(format!("Invalid to_address: {e:?}")))?;
355
356 let to_account_id_bytes: [u8; 32] = *to_account_id.as_ref();
358 let to_account_id_subxt = subxt::ext::subxt_core::utils::AccountId32::from(to_account_id_bytes);
359
360 let schedule_call = quantus_subxt::api::tx().reversible_transfers().schedule_transfer(
361 subxt::ext::subxt_core::utils::MultiAddress::Id(to_account_id_subxt),
362 amount,
363 );
364
365 crate::cli::common::submit_transaction(
366 quantus_client,
367 from_keypair,
368 schedule_call,
369 None,
370 finalized,
371 )
372 .await
373}
374
375async fn submit_scheduler_schedule(
377 _quantus_client: &crate::chain::client::QuantusClient,
378 _from_keypair: &QuantumKeyPair,
379 _args: &[Value],
380) -> crate::error::Result<subxt::utils::H256> {
381 log_error!("❌ Scheduler calls through generic call are complex");
382 log_print!("💡 Use dedicated scheduler commands for complex scheduling");
383 Err(QuantusError::Generic(
384 "Scheduler calls not supported in generic call - use scheduler commands".to_string(),
385 ))
386}
387
388async fn submit_scheduler_cancel(
390 _quantus_client: &crate::chain::client::QuantusClient,
391 _from_keypair: &QuantumKeyPair,
392 _args: &[Value],
393) -> crate::error::Result<subxt::utils::H256> {
394 log_error!("❌ Scheduler calls through generic call are complex");
395 log_print!("💡 Use dedicated scheduler commands for scheduling operations");
396 Err(QuantusError::Generic(
397 "Scheduler calls not supported in generic call - use scheduler commands".to_string(),
398 ))
399}
400
401pub async fn handle_generic_call(
403 pallet: &str,
404 call: &str,
405 args: Vec<Value>,
406 keypair: &QuantumKeyPair,
407 tip: Option<String>,
408 node_url: &str,
409 finalized: bool,
410) -> crate::error::Result<()> {
411 log_print!("🚀 Generic Call");
412
413 let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?;
414
415 execute_generic_call(&quantus_client, pallet, call, args, keypair, tip, finalized).await?;
416
417 Ok(())
418}