quantus_cli/cli/
high_security.rs1use crate::{
2 chain::quantus_subxt, cli::address_format::QuantusSS58, log_error, log_print, log_success,
3 log_verbose,
4};
5use clap::Subcommand;
6use colored::Colorize;
7use sp_core::crypto::{AccountId32 as SpAccountId32, Ss58Codec};
8
9#[derive(Subcommand, Debug)]
11pub enum HighSecurityCommands {
12 Status {
14 #[arg(long)]
16 account: String,
17 },
18
19 Set {
21 #[arg(long)]
23 interceptor: String,
24
25 #[arg(long, conflicts_with = "delay_seconds")]
27 delay_blocks: Option<u32>,
28
29 #[arg(long, conflicts_with = "delay_blocks")]
31 delay_seconds: Option<u64>,
32
33 #[arg(short, long)]
35 from: String,
36
37 #[arg(short, long)]
39 password: Option<String>,
40
41 #[arg(long)]
43 password_file: Option<String>,
44 },
45
46 Entrusted {
48 #[arg(short, long)]
50 from: String,
51 },
52}
53
54pub async fn handle_high_security_command(
56 command: HighSecurityCommands,
57 node_url: &str,
58 execution_mode: crate::cli::common::ExecutionMode,
59) -> crate::error::Result<()> {
60 let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?;
61
62 match command {
63 HighSecurityCommands::Status { account } => {
64 log_print!("🔍 Checking High Security Status");
65
66 let resolved_account = crate::cli::common::resolve_address(&account)?;
68 let account_id_sp = SpAccountId32::from_ss58check(&resolved_account).map_err(|e| {
69 crate::error::QuantusError::Generic(format!(
70 "Invalid account address '{resolved_account}': {e:?}"
71 ))
72 })?;
73 let account_id_bytes: [u8; 32] = *account_id_sp.as_ref();
74 let account_id = subxt::ext::subxt_core::utils::AccountId32::from(account_id_bytes);
75
76 let account_ss58 = account_id.to_quantus_ss58();
78
79 let storage_addr = quantus_subxt::api::storage()
81 .reversible_transfers()
82 .high_security_accounts(account_id);
83 let latest = quantus_client.get_latest_block().await?;
84 let value = quantus_client
85 .client()
86 .storage()
87 .at(latest)
88 .fetch(&storage_addr)
89 .await
90 .map_err(|e| {
91 crate::error::QuantusError::NetworkError(format!("Fetch error: {e:?}"))
92 })?;
93
94 log_print!("📋 Account: {}", account_ss58.bright_cyan());
95
96 if let Some(high_security_data) = value {
97 log_success!("✅ High Security: ENABLED");
98
99 let interceptor_ss58 = high_security_data.interceptor.to_quantus_ss58();
101
102 log_print!("🛡️ Guardian/Interceptor: {}", interceptor_ss58.bright_green());
103
104 match high_security_data.delay {
106 quantus_subxt::api::runtime_types::qp_scheduler::BlockNumberOrTimestamp::BlockNumber(blocks) => {
107 log_print!("⏱️ Delay: {} blocks", blocks.to_string().bright_yellow());
108 },
109 quantus_subxt::api::runtime_types::qp_scheduler::BlockNumberOrTimestamp::Timestamp(ms) => {
110 let seconds = ms / 1000;
111 log_print!("⏱️ Delay: {} seconds", seconds.to_string().bright_yellow());
112 },
113 }
114 } else {
115 log_print!("❌ High Security: DISABLED");
116 log_print!("💡 This account does not have high-security reversibility enabled.");
117 }
118
119 Ok(())
120 },
121
122 HighSecurityCommands::Set {
123 interceptor,
124 delay_blocks,
125 delay_seconds,
126 from,
127 password,
128 password_file,
129 } => {
130 log_print!("🛡️ Set High Security");
131 log_verbose!("📦 Using wallet: {}", from.bright_blue().bold());
132 let keypair = crate::wallet::load_keypair_from_wallet(&from, password, password_file)?;
133
134 let interceptor_resolved = crate::cli::common::resolve_address(&interceptor)?;
136 let interceptor_sp =
137 SpAccountId32::from_ss58check(&interceptor_resolved).map_err(|e| {
138 crate::error::QuantusError::Generic(format!(
139 "Invalid interceptor address '{interceptor_resolved}': {e:?}"
140 ))
141 })?;
142 let interceptor_bytes: [u8; 32] = *interceptor_sp.as_ref();
143 let interceptor_subxt =
144 subxt::ext::subxt_core::utils::AccountId32::from(interceptor_bytes);
145
146 use quantus_subxt::api::reversible_transfers::calls::types::set_high_security::Delay as HsDelay;
148 let delay_value = match (delay_blocks, delay_seconds) {
149 (Some(blocks), None) => HsDelay::BlockNumber(blocks),
150 (None, Some(seconds)) => HsDelay::Timestamp(seconds * 1000), (None, None) => {
153 log_error!("❌ You must specify either --delay-blocks or --delay-seconds");
154 return Err(crate::error::QuantusError::Generic(
155 "Missing delay parameter".to_string(),
156 ));
157 },
158 (Some(_), Some(_)) => {
159 unreachable!("clap conflicts_with ensures these are mutually exclusive")
160 },
161 };
162
163 log_verbose!("✍️ Creating set_high_security extrinsic...");
164
165 let tx_call = quantus_subxt::api::tx()
167 .reversible_transfers()
168 .set_high_security(delay_value, interceptor_subxt);
169
170 let tx_hash = crate::cli::common::submit_transaction(
171 &quantus_client,
172 &keypair,
173 tx_call,
174 None,
175 execution_mode,
176 )
177 .await?;
178
179 log_success!("✅ SUCCESS High security set! Hash: 0x{}", hex::encode(tx_hash.as_ref()));
180
181 Ok(())
182 },
183
184 HighSecurityCommands::Entrusted { from } => {
185 log_print!("🔍 Checking entrusted accounts");
186
187 let guardian_resolved = crate::cli::common::resolve_address(&from)?;
189 let guardian_sp = SpAccountId32::from_ss58check(&guardian_resolved).map_err(|e| {
190 crate::error::QuantusError::Generic(format!(
191 "Invalid guardian address '{guardian_resolved}': {e:?}"
192 ))
193 })?;
194 let guardian_bytes: [u8; 32] = *guardian_sp.as_ref();
195 let guardian_account = subxt::ext::subxt_core::utils::AccountId32::from(guardian_bytes);
196
197 let guardian_ss58 = guardian_account.to_quantus_ss58();
199
200 let storage_addr = quantus_subxt::api::storage()
202 .reversible_transfers()
203 .interceptor_index(guardian_account);
204 let latest = quantus_client.get_latest_block().await?;
205 let value = quantus_client
206 .client()
207 .storage()
208 .at(latest)
209 .fetch(&storage_addr)
210 .await
211 .map_err(|e| {
212 crate::error::QuantusError::NetworkError(format!("Fetch error: {e:?}"))
213 })?;
214
215 log_print!("🛡️ Guardian: {}", guardian_ss58.bright_cyan());
216
217 if let Some(entrusted_accounts) = value {
218 if entrusted_accounts.0.is_empty() {
219 log_print!("📋 No entrusted accounts found.");
220 } else {
221 log_success!("✅ Found {} entrusted account(s):", entrusted_accounts.0.len());
222
223 for (index, account_id) in entrusted_accounts.0.iter().enumerate() {
224 let account_ss58 = account_id.to_quantus_ss58();
225 log_print!(" {}. {}", index + 1, account_ss58.bright_green());
226 }
227 }
228 } else {
229 log_print!("📋 No entrusted accounts found.");
230 }
231
232 Ok(())
233 },
234 }
235}