1use crate::{
2 chain::quantus_subxt,
3 cli::{common::resolve_address, progress_spinner::wait_for_tx_confirmation},
4 log_error, log_print, log_success,
5};
6use clap::Subcommand;
7use sp_core::crypto::{AccountId32 as SpAccountId32, Ss58Codec};
9
10const QUAN_DECIMALS: u128 = 1_000_000_000_000; #[derive(Subcommand, Debug)]
15pub enum RecoveryCommands {
16 Initiate {
18 #[arg(long)]
20 rescuer: String,
21 #[arg(long)]
23 lost: String,
24 #[arg(short, long)]
26 password: Option<String>,
27 #[arg(long)]
29 password_file: Option<String>,
30 },
31
32 Vouch {
34 #[arg(long)]
36 friend: String,
37 #[arg(long)]
39 lost: String,
40 #[arg(long)]
42 rescuer: String,
43 #[arg(short, long)]
45 password: Option<String>,
46 #[arg(long)]
48 password_file: Option<String>,
49 },
50
51 Claim {
53 #[arg(long)]
55 rescuer: String,
56 #[arg(long)]
58 lost: String,
59 #[arg(short, long)]
61 password: Option<String>,
62 #[arg(long)]
64 password_file: Option<String>,
65 },
66
67 Close {
69 #[arg(long)]
71 lost: String,
72 #[arg(long)]
74 rescuer: String,
75 #[arg(short, long)]
77 password: Option<String>,
78 #[arg(long)]
80 password_file: Option<String>,
81 },
82
83 CancelProxy {
85 #[arg(long)]
87 rescuer: String,
88 #[arg(long)]
90 lost: String,
91 #[arg(short, long)]
93 password: Option<String>,
94 #[arg(long)]
96 password_file: Option<String>,
97 },
98
99 Active {
101 #[arg(long)]
103 lost: String,
104 #[arg(long)]
106 rescuer: String,
107 },
108
109 ProxyOf {
111 #[arg(long)]
113 rescuer: String,
114 },
115
116 Config {
118 #[arg(long)]
120 account: String,
121 },
122
123 RecoverAll {
125 #[arg(long)]
127 rescuer: String,
128 #[arg(long)]
130 lost: String,
131 #[arg(long)]
133 dest: String,
134 #[arg(long, default_value_t = true)]
136 keep_alive: bool,
137 #[arg(short, long)]
139 password: Option<String>,
140 #[arg(long)]
142 password_file: Option<String>,
143 },
144
145 RecoverAmount {
147 #[arg(long)]
149 rescuer: String,
150 #[arg(long)]
152 lost: String,
153 #[arg(long)]
155 dest: String,
156 #[arg(long, value_name = "AMOUNT_QUAN")]
158 amount_quan: u128,
159 #[arg(long, default_value_t = true)]
161 keep_alive: bool,
162 #[arg(short, long)]
164 password: Option<String>,
165 #[arg(long)]
167 password_file: Option<String>,
168 },
169}
170
171pub async fn handle_recovery_command(
172 command: RecoveryCommands,
173 node_url: &str,
174) -> crate::error::Result<()> {
175 let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?;
176
177 match command {
178 RecoveryCommands::Initiate { rescuer, lost, password, password_file } => {
179 let rescuer_key =
180 crate::wallet::load_keypair_from_wallet(&rescuer, password, password_file)?;
181 let rescuer_addr = rescuer_key.to_account_id_ss58check();
182 log_print!("🔑 Rescuer: {}", rescuer);
183 log_print!("🔑 Rescuer address: {}", rescuer_addr);
184 let lost_resolved = resolve_address(&lost)?;
185 let lost_id_sp = SpAccountId32::from_ss58check(&lost_resolved).map_err(|e| {
186 crate::error::QuantusError::Generic(format!("Invalid lost address: {e:?}"))
187 })?;
188 let lost_id_bytes: [u8; 32] = *lost_id_sp.as_ref();
189 let lost_id = subxt::ext::subxt_core::utils::AccountId32::from(lost_id_bytes);
190 let call = quantus_subxt::api::tx()
191 .recovery()
192 .initiate_recovery(subxt::ext::subxt_core::utils::MultiAddress::Id(lost_id));
193 let tx_hash =
194 crate::cli::common::submit_transaction(&quantus_client, &rescuer_key, call, None)
195 .await
196 .map_err(|e| {
197 crate::error::QuantusError::NetworkError(format!(
198 "Failed to submit initiate_recovery transaction: {e}"
199 ))
200 })?;
201
202 log_print!("📋 Transaction submitted: 0x{}", hex::encode(tx_hash.as_ref()));
203 log_success!("✅ Initiate recovery submitted successfully");
204
205 let confirmation_result =
206 wait_for_tx_confirmation(quantus_client.client(), tx_hash).await;
207 match confirmation_result {
208 Ok(true) => {
209 log_success!("✅ Transaction confirmed");
210 Ok(())
211 },
212 Ok(false) => {
213 log_error!("⚠️ Transaction may not have been confirmed");
214 Ok(())
215 },
216 Err(e) => {
217 log_error!("❌ Failed to confirm transaction: {e}");
218 Err(e)
219 },
220 }
221 },
222
223 RecoveryCommands::Vouch { friend, lost, rescuer, password, password_file } => {
224 let friend_key =
225 crate::wallet::load_keypair_from_wallet(&friend, password, password_file)?;
226 let lost_resolved = resolve_address(&lost)?;
227 let rescuer_resolved = resolve_address(&rescuer)?;
228 let lost_sp = SpAccountId32::from_ss58check(&lost_resolved).map_err(|e| {
229 crate::error::QuantusError::Generic(format!("Invalid lost address: {e:?}"))
230 })?;
231 let lost_bytes: [u8; 32] = *lost_sp.as_ref();
232 let lost_id = subxt::ext::subxt_core::utils::AccountId32::from(lost_bytes);
233 let rescuer_sp = SpAccountId32::from_ss58check(&rescuer_resolved).map_err(|e| {
234 crate::error::QuantusError::Generic(format!("Invalid rescuer address: {e:?}"))
235 })?;
236 let rescuer_bytes: [u8; 32] = *rescuer_sp.as_ref();
237 let rescuer_id = subxt::ext::subxt_core::utils::AccountId32::from(rescuer_bytes);
238 let call = quantus_subxt::api::tx().recovery().vouch_recovery(
239 subxt::ext::subxt_core::utils::MultiAddress::Id(lost_id),
240 subxt::ext::subxt_core::utils::MultiAddress::Id(rescuer_id),
241 );
242 let tx_hash =
243 crate::cli::common::submit_transaction(&quantus_client, &friend_key, call, None)
244 .await
245 .map_err(|e| {
246 crate::error::QuantusError::NetworkError(format!(
247 "Failed to submit vouch_recovery transaction: {e}"
248 ))
249 })?;
250
251 log_print!("📋 Transaction submitted: 0x{}", hex::encode(tx_hash.as_ref()));
252 log_success!("✅ Vouch submitted successfully");
253
254 let confirmation_result =
255 wait_for_tx_confirmation(quantus_client.client(), tx_hash).await;
256 match confirmation_result {
257 Ok(true) => {
258 log_success!("✅ Transaction confirmed");
259 Ok(())
260 },
261 Ok(false) => {
262 log_error!("⚠️ Transaction may not have been confirmed");
263 Ok(())
264 },
265 Err(e) => {
266 log_error!("❌ Failed to confirm transaction: {e}");
267 Err(e)
268 },
269 }
270 },
271
272 RecoveryCommands::Claim { rescuer, lost, password, password_file } => {
273 let rescuer_key =
274 crate::wallet::load_keypair_from_wallet(&rescuer, password, password_file)?;
275 let lost_resolved = resolve_address(&lost)?;
276 let lost_sp = SpAccountId32::from_ss58check(&lost_resolved).map_err(|e| {
277 crate::error::QuantusError::Generic(format!("Invalid lost address: {e:?}"))
278 })?;
279 let lost_bytes: [u8; 32] = *lost_sp.as_ref();
280 let lost_id = subxt::ext::subxt_core::utils::AccountId32::from(lost_bytes);
281 let call = quantus_subxt::api::tx()
282 .recovery()
283 .claim_recovery(subxt::ext::subxt_core::utils::MultiAddress::Id(lost_id));
284 let tx_hash =
285 crate::cli::common::submit_transaction(&quantus_client, &rescuer_key, call, None)
286 .await
287 .map_err(|e| {
288 crate::error::QuantusError::NetworkError(format!(
289 "Failed to submit claim_recovery transaction: {e}"
290 ))
291 })?;
292
293 log_print!("📋 Transaction submitted: 0x{}", hex::encode(tx_hash.as_ref()));
294 log_success!("✅ Claim submitted successfully");
295
296 let confirmation_result =
297 wait_for_tx_confirmation(quantus_client.client(), tx_hash).await;
298 match confirmation_result {
299 Ok(true) => {
300 log_success!("✅ Transaction confirmed");
301 Ok(())
302 },
303 Ok(false) => {
304 log_error!("⚠️ Transaction may not have been confirmed");
305 Ok(())
306 },
307 Err(e) => {
308 log_error!("❌ Failed to confirm transaction: {e}");
309 Err(e)
310 },
311 }
312 },
313
314 RecoveryCommands::RecoverAll {
315 rescuer,
316 lost,
317 dest,
318 keep_alive,
319 password,
320 password_file,
321 } => {
322 use quantus_subxt::api::runtime_types::pallet_balances::pallet::Call as BalancesCall;
323
324 let rescuer_key =
325 crate::wallet::load_keypair_from_wallet(&rescuer, password, password_file)?;
326 let rescuer_addr = rescuer_key.to_account_id_ss58check();
327 log_print!("🔑 Rescuer: {}", rescuer);
328 log_print!("🔑 Rescuer address: {}", rescuer_addr);
329
330 let lost_resolved = resolve_address(&lost)?;
331 let dest_resolved = resolve_address(&dest)?;
332 log_print!("🆘 Lost input: {} -> {}", lost, lost_resolved);
333 log_print!("🎯 Dest input: {} -> {}", dest, dest_resolved);
334 log_print!("🛟 keep_alive: {}", keep_alive);
335
336 let lost_sp = SpAccountId32::from_ss58check(&lost_resolved).map_err(|e| {
337 crate::error::QuantusError::Generic(format!("Invalid lost address: {e:?}"))
338 })?;
339 let dest_sp = SpAccountId32::from_ss58check(&dest_resolved).map_err(|e| {
340 crate::error::QuantusError::Generic(format!("Invalid dest address: {e:?}"))
341 })?;
342
343 let lost_id_bytes: [u8; 32] = *lost_sp.as_ref();
344 let dest_id_bytes: [u8; 32] = *dest_sp.as_ref();
345 let lost_id = subxt::ext::subxt_core::utils::AccountId32::from(lost_id_bytes);
346 let dest_id = subxt::ext::subxt_core::utils::AccountId32::from(dest_id_bytes);
347
348 let rescuer_sp = SpAccountId32::from_ss58check(&rescuer_addr).map_err(|e| {
350 crate::error::QuantusError::Generic(format!(
351 "Invalid rescuer address from wallet: {e:?}"
352 ))
353 })?;
354 let rescuer_id_bytes: [u8; 32] = *rescuer_sp.as_ref();
355 let rescuer_id = subxt::ext::subxt_core::utils::AccountId32::from(rescuer_id_bytes);
356 let proxy_storage = quantus_subxt::api::storage().recovery().proxy(rescuer_id);
357 let latest = quantus_client.get_latest_block().await?;
358 let proxy_result =
359 quantus_client.client().storage().at(latest).fetch(&proxy_storage).await;
360 let proxy_of = match proxy_result {
361 Ok(Some(proxy)) => {
362 log_print!("🧩 Proxy mapping: rescuer proxies -> {}", format!("{}", proxy));
363 Some(proxy)
364 },
365 Ok(None) => {
366 log_error!(
367 "❌ No proxy mapping found for rescuer - recovery not set up properly"
368 );
369 return Err(crate::error::QuantusError::Generic(
370 "Rescuer has no proxy mapping. Recovery process may not be properly set up.".to_string()
371 ));
372 },
373 Err(e) => {
374 log_error!("❌ Proxy mapping fetch error: {:?}", e);
375 return Err(crate::error::QuantusError::NetworkError(format!(
376 "Failed to check proxy mapping: {e:?}"
377 )));
378 },
379 };
380
381 if let Some(proxy) = proxy_of {
383 let proxy_addr = format!("{proxy}");
384 if proxy_addr != lost_resolved {
385 log_error!(
386 "❌ Proxy mismatch! Rescuer proxies {} but we're trying to recover {}",
387 proxy_addr,
388 lost_resolved
389 );
390 return Err(crate::error::QuantusError::Generic(format!(
391 "Proxy mismatch: rescuer proxies {proxy_addr} but target is {lost_resolved}"
392 )));
393 }
394 log_print!("✅ Proxy validation successful");
395 }
396
397 let inner_call = quantus_subxt::api::Call::Balances(BalancesCall::transfer_all {
398 dest: subxt::ext::subxt_core::utils::MultiAddress::Id(dest_id),
399 keep_alive,
400 });
401 log_print!("🧱 Inner call: Balances.transfer_all(keep_alive={})", keep_alive);
402
403 let call = quantus_subxt::api::tx()
404 .recovery()
405 .as_recovered(subxt::ext::subxt_core::utils::MultiAddress::Id(lost_id), inner_call);
406
407 let tx_hash = match crate::cli::common::submit_transaction(
408 &quantus_client,
409 &rescuer_key,
410 call,
411 None,
412 )
413 .await
414 {
415 Ok(h) => h,
416 Err(e) => {
417 log_error!("❌ Submit error (recover_all): {:?}", e);
418 return Err(e);
419 },
420 };
421
422 log_print!("📋 Transaction submitted: 0x{}", hex::encode(tx_hash.as_ref()));
423 log_success!("✅ recover_all submitted successfully");
424
425 let confirmation_result =
426 wait_for_tx_confirmation(quantus_client.client(), tx_hash).await;
427 match confirmation_result {
428 Ok(true) => {
429 log_success!("✅ Transaction confirmed");
430 Ok(())
431 },
432 Ok(false) => {
433 log_error!("⚠️ Transaction may not have been confirmed");
434 Ok(())
435 },
436 Err(e) => {
437 log_error!("❌ Failed to confirm transaction: {e}");
438 Err(e)
439 },
440 }
441 },
442
443 RecoveryCommands::RecoverAmount {
444 rescuer,
445 lost,
446 dest,
447 amount_quan,
448 keep_alive,
449 password,
450 password_file,
451 } => {
452 use quantus_subxt::api::runtime_types::pallet_balances::pallet::Call as BalancesCall;
453
454 let rescuer_key =
455 crate::wallet::load_keypair_from_wallet(&rescuer, password, password_file)?;
456
457 let rescuer_addr = rescuer_key.to_account_id_ss58check();
458 log_print!("🔑 Rescuer: {}", rescuer);
459 log_print!("🔑 Rescuer address: {}", rescuer_addr);
460
461 let lost_resolved = resolve_address(&lost)?;
462 let dest_resolved = resolve_address(&dest)?;
463 log_print!("🆘 Lost input: {} -> {}", lost, lost_resolved);
464 log_print!("🎯 Dest input: {} -> {}", dest, dest_resolved);
465 log_print!("💵 amount_quan: {} (QUAN_DECIMALS={})", amount_quan, QUAN_DECIMALS);
466 log_print!("🛟 keep_alive: {}", keep_alive);
467
468 let lost_sp = SpAccountId32::from_ss58check(&lost_resolved).map_err(|e| {
469 crate::error::QuantusError::Generic(format!("Invalid lost address: {e:?}"))
470 })?;
471 let dest_sp = SpAccountId32::from_ss58check(&dest_resolved).map_err(|e| {
472 crate::error::QuantusError::Generic(format!("Invalid dest address: {e:?}"))
473 })?;
474
475 let lost_id_bytes: [u8; 32] = *lost_sp.as_ref();
476 let dest_id_bytes: [u8; 32] = *dest_sp.as_ref();
477 let lost_id = subxt::ext::subxt_core::utils::AccountId32::from(lost_id_bytes);
478 let dest_id = subxt::ext::subxt_core::utils::AccountId32::from(dest_id_bytes);
479
480 let amount_plancks = amount_quan.saturating_mul(QUAN_DECIMALS);
481 log_print!("💵 amount_plancks: {}", amount_plancks);
482
483 let latest = quantus_client.get_latest_block().await?;
484
485 log_print!("💰 Checking lost account balance...");
487 let balance_result = quantus_client
488 .client()
489 .storage()
490 .at(latest)
491 .fetch(&quantus_subxt::api::storage().system().account(lost_id.clone()))
492 .await;
493
494 let account_info = match balance_result {
495 Ok(Some(info)) => info,
496 Ok(None) => {
497 log_error!("❌ Lost account not found in storage");
498 return Err(crate::error::QuantusError::Generic(
499 "Lost account not found in storage".to_string(),
500 ));
501 },
502 Err(e) => {
503 log_error!("❌ Failed to fetch account balance: {:?}", e);
504 return Err(crate::error::QuantusError::NetworkError(format!(
505 "Failed to fetch account balance: {e:?}"
506 )));
507 },
508 };
509
510 let available_balance = account_info.data.free;
511 log_print!("💰 Available balance: {} plancks", available_balance);
512
513 if available_balance < amount_plancks {
514 log_error!(
515 "❌ Insufficient funds! Account has {} plancks but needs {} plancks",
516 available_balance,
517 amount_plancks
518 );
519 return Err(crate::error::QuantusError::Generic(format!(
520 "Insufficient funds: account has {available_balance} plancks but transfer requires {amount_plancks} plancks"
521 )));
522 }
523
524 log_print!("✅ Balance validation successful - sufficient funds available");
525
526 let inner_call =
527 quantus_subxt::api::Call::Balances(BalancesCall::transfer_keep_alive {
528 dest: subxt::ext::subxt_core::utils::MultiAddress::Id(dest_id),
529 value: amount_plancks,
530 });
531
532 let call = quantus_subxt::api::tx()
533 .recovery()
534 .as_recovered(subxt::ext::subxt_core::utils::MultiAddress::Id(lost_id), inner_call);
535
536 let tx_hash = match crate::cli::common::submit_transaction(
537 &quantus_client,
538 &rescuer_key,
539 call,
540 None,
541 )
542 .await
543 {
544 Ok(h) => h,
545 Err(e) => {
546 log_error!("❌ Submit error (recover_amount): {:?}", e);
547 return Err(e);
548 },
549 };
550
551 log_print!("📋 Transaction submitted: 0x{}", hex::encode(tx_hash.as_ref()));
552 log_success!("✅ recover_amount submitted successfully");
553
554 let confirmation_result =
555 wait_for_tx_confirmation(quantus_client.client(), tx_hash).await;
556 match confirmation_result {
557 Ok(true) => {
558 log_success!("✅ Transaction confirmed");
559 Ok(())
560 },
561 Ok(false) => {
562 log_error!("⚠️ Transaction may not have been confirmed");
563 Ok(())
564 },
565 Err(e) => {
566 log_error!("❌ Failed to confirm transaction: {e}");
567 Err(e)
568 },
569 }
570 },
571
572 RecoveryCommands::Close { lost, rescuer, password, password_file } => {
573 let lost_key = crate::wallet::load_keypair_from_wallet(&lost, password, password_file)?;
574 let rescuer_resolved = resolve_address(&rescuer)?;
575 let rescuer_sp = SpAccountId32::from_ss58check(&rescuer_resolved).map_err(|e| {
576 crate::error::QuantusError::Generic(format!("Invalid rescuer address: {e:?}"))
577 })?;
578 let rescuer_bytes: [u8; 32] = *rescuer_sp.as_ref();
579 let rescuer_id = subxt::ext::subxt_core::utils::AccountId32::from(rescuer_bytes);
580 let call = quantus_subxt::api::tx()
581 .recovery()
582 .close_recovery(subxt::ext::subxt_core::utils::MultiAddress::Id(rescuer_id));
583 let tx_hash =
584 crate::cli::common::submit_transaction(&quantus_client, &lost_key, call, None)
585 .await
586 .map_err(|e| {
587 crate::error::QuantusError::NetworkError(format!(
588 "Failed to submit close_recovery transaction: {e}"
589 ))
590 })?;
591
592 log_print!("📋 Transaction submitted: 0x{}", hex::encode(tx_hash.as_ref()));
593 log_success!("✅ close_recovery submitted successfully");
594
595 let confirmation_result =
596 wait_for_tx_confirmation(quantus_client.client(), tx_hash).await;
597 match confirmation_result {
598 Ok(true) => {
599 log_success!("✅ Transaction confirmed");
600 Ok(())
601 },
602 Ok(false) => {
603 log_error!("⚠️ Transaction may not have been confirmed");
604 Ok(())
605 },
606 Err(e) => {
607 log_error!("❌ Failed to confirm transaction: {e}");
608 Err(e)
609 },
610 }
611 },
612
613 RecoveryCommands::CancelProxy { rescuer, lost, password, password_file } => {
614 let rescuer_key =
615 crate::wallet::load_keypair_from_wallet(&rescuer, password, password_file)?;
616 let lost_resolved = resolve_address(&lost)?;
617 let lost_sp = SpAccountId32::from_ss58check(&lost_resolved).map_err(|e| {
618 crate::error::QuantusError::Generic(format!("Invalid lost address: {e:?}"))
619 })?;
620 let lost_bytes: [u8; 32] = *lost_sp.as_ref();
621 let lost_id = subxt::ext::subxt_core::utils::AccountId32::from(lost_bytes);
622 let call = quantus_subxt::api::tx()
623 .recovery()
624 .cancel_recovered(subxt::ext::subxt_core::utils::MultiAddress::Id(lost_id));
625 let tx_hash =
626 crate::cli::common::submit_transaction(&quantus_client, &rescuer_key, call, None)
627 .await
628 .map_err(|e| {
629 crate::error::QuantusError::NetworkError(format!(
630 "Failed to submit cancel_recovered transaction: {e}"
631 ))
632 })?;
633
634 log_print!("📋 Transaction submitted: 0x{}", hex::encode(tx_hash.as_ref()));
635 log_success!("✅ cancel_recovered submitted successfully");
636
637 let confirmation_result =
638 wait_for_tx_confirmation(quantus_client.client(), tx_hash).await;
639 match confirmation_result {
640 Ok(true) => {
641 log_success!("✅ Transaction confirmed");
642 Ok(())
643 },
644 Ok(false) => {
645 log_error!("⚠️ Transaction may not have been confirmed");
646 Ok(())
647 },
648 Err(e) => {
649 log_error!("❌ Failed to confirm transaction: {e}");
650 Err(e)
651 },
652 }
653 },
654
655 RecoveryCommands::Active { lost, rescuer } => {
656 let lost_resolved = resolve_address(&lost)?;
657 let rescuer_resolved = resolve_address(&rescuer)?;
658 let lost_sp = SpAccountId32::from_ss58check(&lost_resolved).map_err(|e| {
659 crate::error::QuantusError::Generic(format!("Invalid lost address: {e:?}"))
660 })?;
661 let lost_bytes: [u8; 32] = *lost_sp.as_ref();
662 let lost_id = subxt::ext::subxt_core::utils::AccountId32::from(lost_bytes);
663 let rescuer_sp = SpAccountId32::from_ss58check(&rescuer_resolved).map_err(|e| {
664 crate::error::QuantusError::Generic(format!("Invalid rescuer address: {e:?}"))
665 })?;
666 let rescuer_bytes: [u8; 32] = *rescuer_sp.as_ref();
667 let rescuer_id = subxt::ext::subxt_core::utils::AccountId32::from(rescuer_bytes);
668 let storage_addr =
669 quantus_subxt::api::storage().recovery().active_recoveries(lost_id, rescuer_id);
670 let latest = quantus_client.get_latest_block().await?;
671 let value = quantus_client
672 .client()
673 .storage()
674 .at(latest)
675 .fetch(&storage_addr)
676 .await
677 .map_err(|e| {
678 crate::error::QuantusError::NetworkError(format!("Fetch error: {e:?}"))
679 })?;
680 if let Some(active) = value {
681 log_print!(
682 "{}",
683 serde_json::json!({
684 "created": active.created,
685 "deposit": active.deposit,
686 "friends_vouched": active.friends.0.len(),
687 })
688 );
689 } else {
690 log_print!("{}", serde_json::json!({"active": false}));
691 }
692 Ok(())
693 },
694
695 RecoveryCommands::ProxyOf { rescuer } => {
696 let rescuer_resolved = resolve_address(&rescuer)?;
697 let rescuer_sp = SpAccountId32::from_ss58check(&rescuer_resolved).map_err(|e| {
698 crate::error::QuantusError::Generic(format!("Invalid rescuer address: {e:?}"))
699 })?;
700 let rescuer_bytes: [u8; 32] = *rescuer_sp.as_ref();
701 let rescuer_id = subxt::ext::subxt_core::utils::AccountId32::from(rescuer_bytes);
702 let storage_addr = quantus_subxt::api::storage().recovery().proxy(rescuer_id);
703 let latest = quantus_client.get_latest_block().await?;
704 let value = quantus_client
705 .client()
706 .storage()
707 .at(latest)
708 .fetch(&storage_addr)
709 .await
710 .map_err(|e| {
711 crate::error::QuantusError::NetworkError(format!("Fetch error: {e:?}"))
712 })?;
713 if let Some(lost_id) = value {
714 log_print!("{}", serde_json::json!({"lost": format!("{}", lost_id)}));
715 } else {
716 log_print!("{}", serde_json::json!({"lost": null}));
717 }
718 Ok(())
719 },
720
721 RecoveryCommands::Config { account } => {
722 let account_resolved = resolve_address(&account)?;
723 let account_sp = SpAccountId32::from_ss58check(&account_resolved).map_err(|e| {
724 crate::error::QuantusError::Generic(format!("Invalid account address: {e:?}"))
725 })?;
726 let account_bytes: [u8; 32] = *account_sp.as_ref();
727 let account_id = subxt::ext::subxt_core::utils::AccountId32::from(account_bytes);
728 let storage_addr = quantus_subxt::api::storage().recovery().recoverable(account_id);
729 let latest = quantus_client.get_latest_block().await?;
730 let value = quantus_client
731 .client()
732 .storage()
733 .at(latest)
734 .fetch(&storage_addr)
735 .await
736 .map_err(|e| {
737 crate::error::QuantusError::NetworkError(format!("Fetch error: {e:?}"))
738 })?;
739 if let Some(cfg) = value {
740 log_print!(
741 "{}",
742 serde_json::json!({
743 "delay_period": cfg.delay_period,
744 "deposit": cfg.deposit,
745 "friends": cfg.friends.0.iter().map(|f| format!("{f}")).collect::<Vec<_>>(),
746 "threshold": cfg.threshold,
747 })
748 );
749 } else {
750 log_print!("{}", serde_json::json!({"recoverable": false}));
751 }
752 Ok(())
753 },
754 }
755}