quantus_cli/cli/
high_security.rs1use crate::{
2 chain::quantus_subxt,
3 cli::{address_format::QuantusSS58, progress_spinner::wait_for_tx_confirmation},
4 log_error, log_print, log_success, log_verbose,
5};
6use clap::Subcommand;
7use colored::Colorize;
8use sp_core::crypto::{AccountId32 as SpAccountId32, Ss58Codec};
9
10#[derive(Subcommand, Debug)]
12pub enum HighSecurityCommands {
13 Status {
15 #[arg(long)]
17 account: String,
18 },
19
20 Set {
22 #[arg(long)]
24 interceptor: String,
25
26 #[arg(long, conflicts_with = "delay_seconds")]
28 delay_blocks: Option<u32>,
29
30 #[arg(long, conflicts_with = "delay_blocks")]
32 delay_seconds: Option<u64>,
33
34 #[arg(short, long)]
36 from: String,
37
38 #[arg(short, long)]
40 password: Option<String>,
41
42 #[arg(long)]
44 password_file: Option<String>,
45 },
46}
47
48pub async fn handle_high_security_command(
50 command: HighSecurityCommands,
51 node_url: &str,
52) -> crate::error::Result<()> {
53 let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?;
54
55 match command {
56 HighSecurityCommands::Status { account } => {
57 log_print!("🔍 Checking High Security Status");
58
59 let resolved_account = crate::cli::common::resolve_address(&account)?;
61 let account_id_sp = SpAccountId32::from_ss58check(&resolved_account).map_err(|e| {
62 crate::error::QuantusError::Generic(format!(
63 "Invalid account address '{resolved_account}': {e:?}"
64 ))
65 })?;
66 let account_id_bytes: [u8; 32] = *account_id_sp.as_ref();
67 let account_id = subxt::ext::subxt_core::utils::AccountId32::from(account_id_bytes);
68
69 let account_ss58 = account_id.to_quantus_ss58();
71
72 let storage_addr = quantus_subxt::api::storage()
74 .reversible_transfers()
75 .high_security_accounts(account_id);
76 let latest = quantus_client.get_latest_block().await?;
77 let value = quantus_client
78 .client()
79 .storage()
80 .at(latest)
81 .fetch(&storage_addr)
82 .await
83 .map_err(|e| {
84 crate::error::QuantusError::NetworkError(format!("Fetch error: {e:?}"))
85 })?;
86
87 log_print!("📋 Account: {}", account_ss58.bright_cyan());
88
89 if let Some(high_security_data) = value {
90 log_success!("✅ High Security: ENABLED");
91
92 let interceptor_ss58 = high_security_data.interceptor.to_quantus_ss58();
94
95 log_print!("🛡️ Guardian/Interceptor: {}", interceptor_ss58.bright_green());
96
97 match high_security_data.delay {
99 quantus_subxt::api::runtime_types::qp_scheduler::BlockNumberOrTimestamp::BlockNumber(blocks) => {
100 log_print!("⏱️ Delay: {} blocks", blocks.to_string().bright_yellow());
101 },
102 quantus_subxt::api::runtime_types::qp_scheduler::BlockNumberOrTimestamp::Timestamp(ms) => {
103 let seconds = ms / 1000;
104 log_print!("⏱️ Delay: {} seconds", seconds.to_string().bright_yellow());
105 },
106 }
107 } else {
108 log_print!("❌ High Security: DISABLED");
109 log_print!("💡 This account does not have high-security reversibility enabled.");
110 }
111
112 Ok(())
113 },
114
115 HighSecurityCommands::Set {
116 interceptor,
117 delay_blocks,
118 delay_seconds,
119 from,
120 password,
121 password_file,
122 } => {
123 log_print!("🛡️ Set High Security");
124 log_verbose!("📦 Using wallet: {}", from.bright_blue().bold());
125 let keypair = crate::wallet::load_keypair_from_wallet(&from, password, password_file)?;
126
127 let interceptor_resolved = crate::cli::common::resolve_address(&interceptor)?;
129 let interceptor_sp =
130 SpAccountId32::from_ss58check(&interceptor_resolved).map_err(|e| {
131 crate::error::QuantusError::Generic(format!(
132 "Invalid interceptor address '{interceptor_resolved}': {e:?}"
133 ))
134 })?;
135 let interceptor_bytes: [u8; 32] = *interceptor_sp.as_ref();
136 let interceptor_subxt =
137 subxt::ext::subxt_core::utils::AccountId32::from(interceptor_bytes);
138
139 use quantus_subxt::api::reversible_transfers::calls::types::set_high_security::Delay as HsDelay;
141 let delay_value = match (delay_blocks, delay_seconds) {
142 (Some(blocks), None) => HsDelay::BlockNumber(blocks),
143 (None, Some(seconds)) => HsDelay::Timestamp(seconds * 1000), (None, None) => {
146 log_error!("❌ You must specify either --delay-blocks or --delay-seconds");
147 return Err(crate::error::QuantusError::Generic(
148 "Missing delay parameter".to_string(),
149 ));
150 },
151 (Some(_), Some(_)) => {
152 unreachable!("clap conflicts_with ensures these are mutually exclusive")
153 },
154 };
155
156 log_verbose!("✍️ Creating set_high_security extrinsic...");
157
158 let tx_call = quantus_subxt::api::tx()
160 .reversible_transfers()
161 .set_high_security(delay_value, interceptor_subxt);
162
163 let tx_hash =
164 crate::cli::common::submit_transaction(&quantus_client, &keypair, tx_call, None)
165 .await?;
166
167 log_success!("✅ SUCCESS High security set! Hash: 0x{}", hex::encode(tx_hash.as_ref()));
168
169 let success = wait_for_tx_confirmation(quantus_client.client(), tx_hash).await?;
170 if success {
171 log_success!("🎉 FINISHED High security configuration confirmed on-chain");
172 } else {
173 log_error!("❌ Transaction failed or not included");
174 }
175
176 Ok(())
177 },
178 }
179}