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) -> crate::error::Result<subxt::utils::H256> {
19 log_print!("🚀 Executing generic call");
20 log_print!("Pallet: {}", pallet.bright_green());
21 log_print!("Call: {}", call.bright_cyan());
22 log_print!("From: {}", from_keypair.to_account_id_ss58check().bright_yellow());
23 if let Some(tip) = &tip {
24 log_print!("Tip: {}", tip.bright_magenta());
25 }
26
27 let _signer = from_keypair
29 .to_subxt_signer()
30 .map_err(|e| QuantusError::NetworkError(format!("Failed to convert keypair: {e:?}")))?;
31
32 let metadata = quantus_client.client().metadata();
34 let pallet_metadata = metadata
35 .pallet_by_name(pallet)
36 .ok_or_else(|| QuantusError::Generic(format!("Pallet '{pallet}' not found in metadata")))?;
37
38 log_verbose!("✅ Found pallet '{}' with index {}", pallet, pallet_metadata.index());
39
40 let call_metadata = pallet_metadata.call_variant_by_name(call).ok_or_else(|| {
42 QuantusError::Generic(format!("Call '{call}' not found in pallet '{pallet}'"))
43 })?;
44
45 log_verbose!("✅ Found call '{}' with index {}", call, call_metadata.index);
46
47 let tip_amount = if let Some(tip_str) = &tip { tip_str.parse::<u128>().ok() } else { None };
49
50 log_print!("🔧 Creating extrinsic for {}.{}", pallet, call);
52
53 let tx_hash = match (pallet, call) {
54 ("Balances", "transfer_allow_death") =>
56 submit_balance_transfer(quantus_client, from_keypair, &args, false, tip_amount).await?,
57 ("Balances", "transfer_keep_alive") =>
58 submit_balance_transfer(quantus_client, from_keypair, &args, true, tip_amount).await?,
59
60 ("System", "remark") =>
62 submit_system_remark(quantus_client, from_keypair, &args, tip_amount).await?,
63
64 ("Sudo", "sudo") => submit_sudo_call(quantus_client, from_keypair, &args).await?,
66
67 ("TechCollective", "add_member") =>
69 submit_tech_collective_add_member(quantus_client, from_keypair, &args).await?,
70 ("TechCollective", "remove_member") =>
71 submit_tech_collective_remove_member(quantus_client, from_keypair, &args).await?,
72 ("TechCollective", "vote") =>
73 submit_tech_collective_vote(quantus_client, from_keypair, &args).await?,
74
75 ("ReversibleTransfers", "schedule_transfer") =>
77 submit_reversible_transfer(quantus_client, from_keypair, &args).await?,
78
79 ("Scheduler", "schedule") =>
81 submit_scheduler_schedule(quantus_client, from_keypair, &args).await?,
82 ("Scheduler", "cancel") =>
83 submit_scheduler_cancel(quantus_client, from_keypair, &args).await?,
84
85 (_, _) => {
87 log_error!(
88 "❌ Pallet '{}' or call '{}' is not supported yet in SubXT implementation",
89 pallet,
90 call
91 );
92 log_print!("💡 Supported pallets in SubXT:");
93 log_print!(" • Balances: transfer_allow_death, transfer_keep_alive");
94 log_print!(" • System: remark");
95 log_print!(" • Sudo: sudo");
96 log_print!(" • TechCollective: add_member, remove_member, vote");
97 log_print!(" • ReversibleTransfers: schedule_transfer");
98 log_print!(" • Scheduler: schedule, cancel");
99 log_print!("💡 For other calls, use the original 'quantus call' command");
100 return Err(QuantusError::Generic(format!(
101 "Unsupported pallet/call combination in SubXT: {pallet}.{call}"
102 )));
103 },
104 };
105
106 log_success!("🎉 SubXT transaction submitted successfully!");
107 log_print!("📋 Transaction hash: {}", format!("0x{}", hex::encode(tx_hash)).bright_yellow());
108
109 Ok(tx_hash)
110}
111
112async fn submit_balance_transfer(
114 quantus_client: &crate::chain::client::QuantusClient,
115 from_keypair: &QuantumKeyPair,
116 args: &[Value],
117 keep_alive: bool,
118 tip: Option<u128>,
119) -> crate::error::Result<subxt::utils::H256> {
120 if args.len() != 2 {
121 return Err(QuantusError::Generic(
122 "Balances transfer requires 2 arguments: [to_address, amount]".to_string(),
123 ));
124 }
125
126 let to_address = args[0].as_str().ok_or_else(|| {
127 QuantusError::Generic("First argument must be a string (to_address)".to_string())
128 })?;
129
130 let amount: u128 = args[1].as_str().unwrap_or("0").parse().map_err(|_| {
131 QuantusError::Generic("Second argument must be a number (amount)".to_string())
132 })?;
133
134 let (to_account_id, _) = AccountId32::from_ss58check_with_version(to_address)
136 .map_err(|e| QuantusError::Generic(format!("Invalid to_address: {e:?}")))?;
137
138 let to_account_id_bytes: [u8; 32] = *to_account_id.as_ref();
140 let to_account_id_subxt = subxt::ext::subxt_core::utils::AccountId32::from(to_account_id_bytes);
141
142 if keep_alive {
144 let transfer_call = quantus_subxt::api::tx().balances().transfer_keep_alive(
145 subxt::ext::subxt_core::utils::MultiAddress::Id(to_account_id_subxt),
146 amount,
147 );
148 crate::cli::common::submit_transaction(quantus_client, from_keypair, transfer_call, tip)
149 .await
150 } else {
151 let transfer_call = quantus_subxt::api::tx().balances().transfer_allow_death(
152 subxt::ext::subxt_core::utils::MultiAddress::Id(to_account_id_subxt),
153 amount,
154 );
155 crate::cli::common::submit_transaction(quantus_client, from_keypair, transfer_call, tip)
156 .await
157 }
158}
159
160async fn submit_system_remark(
162 quantus_client: &crate::chain::client::QuantusClient,
163 from_keypair: &QuantumKeyPair,
164 args: &[Value],
165 tip: Option<u128>,
166) -> crate::error::Result<subxt::utils::H256> {
167 if args.len() != 1 {
168 return Err(QuantusError::Generic(
169 "System remark requires 1 argument: [remark]".to_string(),
170 ));
171 }
172
173 let remark = args[0]
174 .as_str()
175 .ok_or_else(|| QuantusError::Generic("Argument must be a string (remark)".to_string()))?;
176
177 let remark_call = quantus_subxt::api::tx().system().remark(remark.as_bytes().to_vec());
178
179 crate::cli::common::submit_transaction(quantus_client, from_keypair, remark_call, tip).await
180}
181
182async fn submit_sudo_call(
184 _quantus_client: &crate::chain::client::QuantusClient,
185 _from_keypair: &QuantumKeyPair,
186 _args: &[Value],
187) -> crate::error::Result<subxt::utils::H256> {
188 log_error!("❌ Sudo calls through generic call are complex - use specific sudo wrappers");
190 log_print!("💡 Use dedicated subxt commands that already wrap calls in sudo");
191 Err(QuantusError::Generic(
192 "Sudo calls not supported in generic call - use specific commands".to_string(),
193 ))
194}
195
196async fn submit_tech_collective_add_member(
198 quantus_client: &crate::chain::client::QuantusClient,
199 from_keypair: &QuantumKeyPair,
200 args: &[Value],
201) -> crate::error::Result<subxt::utils::H256> {
202 if args.len() != 1 {
203 return Err(QuantusError::Generic(
204 "TechCollective add_member requires 1 argument: [member_address]".to_string(),
205 ));
206 }
207
208 let member_address = args[0].as_str().ok_or_else(|| {
209 QuantusError::Generic("Argument must be a string (member_address)".to_string())
210 })?;
211
212 let (member_account_id, _) = AccountId32::from_ss58check_with_version(member_address)
213 .map_err(|e| QuantusError::Generic(format!("Invalid member_address: {e:?}")))?;
214
215 let member_account_id_bytes: [u8; 32] = *member_account_id.as_ref();
217 let member_account_id_subxt =
218 subxt::ext::subxt_core::utils::AccountId32::from(member_account_id_bytes);
219
220 let sudo_call = quantus_subxt::api::tx().sudo().sudo(quantus_subxt::api::Call::TechCollective(
222 quantus_subxt::api::tech_collective::Call::add_member {
223 who: subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id_subxt),
224 },
225 ));
226
227 crate::cli::common::submit_transaction(quantus_client, from_keypair, sudo_call, None).await
228}
229
230async fn submit_tech_collective_remove_member(
232 quantus_client: &crate::chain::client::QuantusClient,
233 from_keypair: &QuantumKeyPair,
234 args: &[Value],
235) -> crate::error::Result<subxt::utils::H256> {
236 if args.len() != 1 {
237 return Err(QuantusError::Generic(
238 "TechCollective remove_member requires 1 argument: [member_address]".to_string(),
239 ));
240 }
241
242 let member_address = args[0].as_str().ok_or_else(|| {
243 QuantusError::Generic("Argument must be a string (member_address)".to_string())
244 })?;
245
246 let (member_account_id, _) = AccountId32::from_ss58check_with_version(member_address)
247 .map_err(|e| QuantusError::Generic(format!("Invalid member_address: {e:?}")))?;
248
249 let member_account_id_bytes: [u8; 32] = *member_account_id.as_ref();
251 let member_account_id_subxt =
252 subxt::ext::subxt_core::utils::AccountId32::from(member_account_id_bytes);
253
254 let sudo_call = quantus_subxt::api::tx().sudo().sudo(quantus_subxt::api::Call::TechCollective(
256 quantus_subxt::api::tech_collective::Call::remove_member {
257 who: subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id_subxt),
258 min_rank: 0, },
260 ));
261
262 crate::cli::common::submit_transaction(quantus_client, from_keypair, sudo_call, None).await
263}
264
265async fn submit_tech_collective_vote(
267 quantus_client: &crate::chain::client::QuantusClient,
268 from_keypair: &QuantumKeyPair,
269 args: &[Value],
270) -> crate::error::Result<subxt::utils::H256> {
271 if args.len() != 2 {
272 return Err(QuantusError::Generic(
273 "TechCollective vote requires 2 arguments: [referendum_index, aye]".to_string(),
274 ));
275 }
276
277 let referendum_index: u32 = args[0].as_u64().unwrap_or(0) as u32;
278 let aye = args[1].as_bool().unwrap_or(false);
279
280 let vote_call = quantus_subxt::api::tx().tech_collective().vote(referendum_index, aye);
281
282 crate::cli::common::submit_transaction(quantus_client, from_keypair, vote_call, None).await
283}
284
285async fn submit_reversible_transfer(
287 quantus_client: &crate::chain::client::QuantusClient,
288 from_keypair: &QuantumKeyPair,
289 args: &[Value],
290) -> crate::error::Result<subxt::utils::H256> {
291 if args.len() != 2 {
292 return Err(QuantusError::Generic(
293 "ReversibleTransfers schedule_transfer requires 2 arguments: [to_address, amount]"
294 .to_string(),
295 ));
296 }
297
298 let to_address = args[0].as_str().ok_or_else(|| {
299 QuantusError::Generic("First argument must be a string (to_address)".to_string())
300 })?;
301
302 let amount: u128 = args[1].as_str().unwrap_or("0").parse().map_err(|_| {
303 QuantusError::Generic("Second argument must be a number (amount)".to_string())
304 })?;
305
306 let (to_account_id, _) = AccountId32::from_ss58check_with_version(to_address)
307 .map_err(|e| QuantusError::Generic(format!("Invalid to_address: {e:?}")))?;
308
309 let to_account_id_bytes: [u8; 32] = *to_account_id.as_ref();
311 let to_account_id_subxt = subxt::ext::subxt_core::utils::AccountId32::from(to_account_id_bytes);
312
313 let schedule_call = quantus_subxt::api::tx().reversible_transfers().schedule_transfer(
314 subxt::ext::subxt_core::utils::MultiAddress::Id(to_account_id_subxt),
315 amount,
316 );
317
318 crate::cli::common::submit_transaction(quantus_client, from_keypair, schedule_call, None).await
319}
320
321async fn submit_scheduler_schedule(
323 _quantus_client: &crate::chain::client::QuantusClient,
324 _from_keypair: &QuantumKeyPair,
325 _args: &[Value],
326) -> crate::error::Result<subxt::utils::H256> {
327 log_error!("❌ Scheduler calls through generic call are complex");
328 log_print!("💡 Use dedicated scheduler commands for complex scheduling");
329 Err(QuantusError::Generic(
330 "Scheduler calls not supported in generic call - use scheduler commands".to_string(),
331 ))
332}
333
334async fn submit_scheduler_cancel(
336 _quantus_client: &crate::chain::client::QuantusClient,
337 _from_keypair: &QuantumKeyPair,
338 _args: &[Value],
339) -> crate::error::Result<subxt::utils::H256> {
340 log_error!("❌ Scheduler calls through generic call are complex");
341 log_print!("💡 Use dedicated scheduler commands for scheduling operations");
342 Err(QuantusError::Generic(
343 "Scheduler calls not supported in generic call - use scheduler commands".to_string(),
344 ))
345}
346
347pub async fn handle_generic_call(
349 pallet: &str,
350 call: &str,
351 args: Vec<Value>,
352 keypair: &QuantumKeyPair,
353 tip: Option<String>,
354 node_url: &str,
355) -> crate::error::Result<()> {
356 log_print!("🚀 Generic Call");
357
358 let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?;
359
360 execute_generic_call(&quantus_client, pallet, call, args, keypair, tip).await?;
361
362 Ok(())
363}