1use crate::{
3 chain::quantus_subxt,
4 cli::{common::submit_transaction, progress_spinner::wait_for_tx_confirmation},
5 error::QuantusError,
6 log_error, log_print, log_success, log_verbose,
7};
8use clap::Subcommand;
9use colored::Colorize;
10use std::{path::PathBuf, str::FromStr};
11
12#[derive(Subcommand, Debug)]
14pub enum TechReferendaCommands {
15 Submit {
17 #[arg(long)]
19 preimage_hash: String,
20
21 #[arg(short, long)]
23 from: String,
24
25 #[arg(short, long)]
27 password: Option<String>,
28
29 #[arg(long)]
31 password_file: Option<String>,
32 },
33
34 SubmitWithPreimage {
36 #[arg(short, long)]
38 wasm_file: PathBuf,
39
40 #[arg(short, long)]
42 from: String,
43
44 #[arg(short, long)]
46 password: Option<String>,
47
48 #[arg(long)]
50 password_file: Option<String>,
51 },
52
53 List,
55
56 Get {
58 #[arg(short, long)]
60 index: u32,
61 },
62
63 Status {
65 #[arg(short, long)]
67 index: u32,
68 },
69
70 PlaceDecisionDeposit {
72 #[arg(short, long)]
74 index: u32,
75
76 #[arg(short, long)]
78 from: String,
79
80 #[arg(short, long)]
82 password: Option<String>,
83
84 #[arg(long)]
86 password_file: Option<String>,
87 },
88
89 Cancel {
91 #[arg(short, long)]
93 index: u32,
94
95 #[arg(short, long)]
97 from: String,
98
99 #[arg(short, long)]
101 password: Option<String>,
102
103 #[arg(long)]
105 password_file: Option<String>,
106 },
107
108 Kill {
110 #[arg(short, long)]
112 index: u32,
113
114 #[arg(short, long)]
116 from: String,
117
118 #[arg(short, long)]
120 password: Option<String>,
121
122 #[arg(long)]
124 password_file: Option<String>,
125 },
126
127 Nudge {
129 #[arg(short, long)]
131 index: u32,
132
133 #[arg(short, long)]
135 from: String,
136
137 #[arg(short, long)]
139 password: Option<String>,
140
141 #[arg(long)]
143 password_file: Option<String>,
144 },
145
146 RefundSubmissionDeposit {
148 #[arg(short, long)]
150 index: u32,
151
152 #[arg(short, long)]
154 from: String,
155
156 #[arg(short, long)]
158 password: Option<String>,
159
160 #[arg(long)]
162 password_file: Option<String>,
163 },
164
165 RefundDecisionDeposit {
167 #[arg(short, long)]
169 index: u32,
170
171 #[arg(short, long)]
173 from: String,
174
175 #[arg(short, long)]
177 password: Option<String>,
178
179 #[arg(long)]
181 password_file: Option<String>,
182 },
183
184 Config,
186}
187
188pub async fn handle_tech_referenda_command(
190 command: TechReferendaCommands,
191 node_url: &str,
192) -> crate::error::Result<()> {
193 let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?;
194
195 match command {
196 TechReferendaCommands::Submit { preimage_hash, from, password, password_file } =>
197 submit_runtime_upgrade(&quantus_client, &preimage_hash, &from, password, password_file)
198 .await,
199 TechReferendaCommands::SubmitWithPreimage { wasm_file, from, password, password_file } =>
200 submit_runtime_upgrade_with_preimage(
201 &quantus_client,
202 &wasm_file,
203 &from,
204 password,
205 password_file,
206 )
207 .await,
208 TechReferendaCommands::List => list_proposals(&quantus_client).await,
209 TechReferendaCommands::Get { index } => get_proposal_details(&quantus_client, index).await,
210 TechReferendaCommands::Status { index } =>
211 get_proposal_status(&quantus_client, index).await,
212 TechReferendaCommands::PlaceDecisionDeposit { index, from, password, password_file } =>
213 place_decision_deposit(&quantus_client, index, &from, password, password_file).await,
214 TechReferendaCommands::Cancel { index, from, password, password_file } =>
215 cancel_proposal(&quantus_client, index, &from, password, password_file).await,
216 TechReferendaCommands::Kill { index, from, password, password_file } =>
217 kill_proposal(&quantus_client, index, &from, password, password_file).await,
218 TechReferendaCommands::Nudge { index, from, password, password_file } =>
219 nudge_proposal(&quantus_client, index, &from, password, password_file).await,
220 TechReferendaCommands::RefundSubmissionDeposit { index, from, password, password_file } =>
221 refund_submission_deposit(&quantus_client, index, &from, password, password_file).await,
222 TechReferendaCommands::RefundDecisionDeposit { index, from, password, password_file } =>
223 refund_decision_deposit(&quantus_client, index, &from, password, password_file).await,
224 TechReferendaCommands::Config => get_config(&quantus_client).await,
225 }
226}
227
228async fn submit_runtime_upgrade(
230 quantus_client: &crate::chain::client::QuantusClient,
231 preimage_hash: &str,
232 from: &str,
233 password: Option<String>,
234 password_file: Option<String>,
235) -> crate::error::Result<()> {
236 log_print!("📝 Submitting Runtime Upgrade Proposal to Tech Referenda");
237 log_print!(" 🔗 Preimage hash: {}", preimage_hash.bright_cyan());
238 log_print!(" 🔑 Submitted by: {}", from.bright_yellow());
239
240 let hash_str = preimage_hash.trim_start_matches("0x");
242 let preimage_hash_parsed: sp_core::H256 = sp_core::H256::from_str(hash_str)
243 .map_err(|_| QuantusError::Generic("Invalid preimage hash format".to_string()))?;
244
245 let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?;
247
248 log_print!("🔍 Checking preimage status...");
250 let latest_block_hash = quantus_client.get_latest_block().await?;
251 let storage_at = quantus_client.client().storage().at(latest_block_hash);
252
253 let preimage_status = storage_at
254 .fetch(
255 &quantus_subxt::api::storage()
256 .preimage()
257 .request_status_for(preimage_hash_parsed),
258 )
259 .await
260 .map_err(|e| QuantusError::Generic(format!("Failed to fetch preimage status: {:?}", e)))?
261 .ok_or_else(|| QuantusError::Generic("Preimage not found on chain".to_string()))?;
262
263 let preimage_len = match preimage_status {
264 quantus_subxt::api::runtime_types::pallet_preimage::RequestStatus::Unrequested {
265 ticket: _,
266 len,
267 } => len,
268 quantus_subxt::api::runtime_types::pallet_preimage::RequestStatus::Requested {
269 maybe_ticket: _,
270 count: _,
271 maybe_len,
272 } => match maybe_len {
273 Some(len) => len,
274 None => return Err(QuantusError::Generic("Preimage length not available".to_string())),
275 },
276 };
277
278 log_print!("✅ Preimage found! Length: {} bytes", preimage_len);
279
280 type ProposalBounded =
282 quantus_subxt::api::runtime_types::frame_support::traits::preimages::Bounded<
283 quantus_subxt::api::runtime_types::quantus_runtime::RuntimeCall,
284 quantus_subxt::api::runtime_types::qp_poseidon::PoseidonHasher,
285 >;
286
287 let preimage_hash_subxt: subxt::utils::H256 = preimage_hash_parsed;
288 let proposal: ProposalBounded =
289 ProposalBounded::Lookup { hash: preimage_hash_subxt, len: preimage_len };
290
291 let raw_origin_root =
292 quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::Root;
293 let origin_caller =
294 quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin_root);
295
296 let enactment =
297 quantus_subxt::api::runtime_types::frame_support::traits::schedule::DispatchTime::After(
298 0u32,
299 );
300
301 log_print!("🔧 Creating TechReferenda::submit call...");
302 let submit_call =
303 quantus_subxt::api::tx()
304 .tech_referenda()
305 .submit(origin_caller, proposal, enactment);
306
307 let tx_hash = submit_transaction(quantus_client, &keypair, submit_call, None).await?;
308 log_print!(
309 "✅ {} Runtime upgrade proposal submitted! Hash: {:?}",
310 "SUCCESS".bright_green().bold(),
311 tx_hash
312 );
313
314 let _ = wait_for_tx_confirmation(quantus_client.client(), tx_hash).await?;
315 log_success!("🎉 {} Proposal created!", "FINISHED".bright_green().bold());
316 log_print!("💡 Use 'quantus tech-referenda list' to see active proposals");
317 Ok(())
318}
319
320async fn submit_runtime_upgrade_with_preimage(
322 quantus_client: &crate::chain::client::QuantusClient,
323 wasm_file: &PathBuf,
324 from: &str,
325 password: Option<String>,
326 password_file: Option<String>,
327) -> crate::error::Result<()> {
328 use qp_poseidon::PoseidonHasher;
329
330 log_print!("📝 Submitting Runtime Upgrade Proposal to Tech Referenda");
331 log_print!(" 📂 WASM file: {}", wasm_file.display().to_string().bright_cyan());
332 log_print!(" 🔑 Submitted by: {}", from.bright_yellow());
333
334 if !wasm_file.exists() {
335 return Err(QuantusError::Generic(format!("WASM file not found: {}", wasm_file.display())));
336 }
337
338 if let Some(ext) = wasm_file.extension() {
339 if ext != "wasm" {
340 log_verbose!("⚠️ Warning: File doesn't have .wasm extension");
341 }
342 }
343
344 let wasm_code = std::fs::read(wasm_file)
346 .map_err(|e| QuantusError::Generic(format!("Failed to read WASM file: {}", e)))?;
347
348 log_print!("📊 WASM file size: {} bytes", wasm_code.len());
349
350 let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?;
352
353 let set_code_payload = quantus_subxt::api::tx().system().set_code(wasm_code.clone());
355 let metadata = quantus_client.client().metadata();
356 let encoded_call = <_ as subxt::tx::Payload>::encode_call_data(&set_code_payload, &metadata)
357 .map_err(|e| QuantusError::Generic(format!("Failed to encode call data: {:?}", e)))?;
358
359 log_verbose!("📝 Encoded call size: {} bytes", encoded_call.len());
360
361 let preimage_hash: sp_core::H256 =
363 <PoseidonHasher as sp_runtime::traits::Hash>::hash(&encoded_call);
364
365 log_print!("🔗 Preimage hash: {:?}", preimage_hash);
366
367 type PreimageBytes = quantus_subxt::api::preimage::calls::types::note_preimage::Bytes;
369 let bounded_bytes: PreimageBytes = encoded_call.clone();
370
371 log_print!("📝 Submitting preimage...");
372 let note_preimage_tx = quantus_subxt::api::tx().preimage().note_preimage(bounded_bytes);
373 let preimage_tx_hash =
374 submit_transaction(quantus_client, &keypair, note_preimage_tx, None).await?;
375 log_print!("✅ Preimage transaction submitted: {:?}", preimage_tx_hash);
376
377 log_print!("⏳ Waiting for preimage transaction confirmation...");
379 let _ = wait_for_tx_confirmation(quantus_client.client(), preimage_tx_hash).await?;
380 log_print!("✅ Preimage transaction confirmed!");
381
382 type ProposalBounded =
384 quantus_subxt::api::runtime_types::frame_support::traits::preimages::Bounded<
385 quantus_subxt::api::runtime_types::quantus_runtime::RuntimeCall,
386 quantus_subxt::api::runtime_types::qp_poseidon::PoseidonHasher,
387 >;
388
389 let preimage_hash_subxt: subxt::utils::H256 = preimage_hash;
390 let proposal: ProposalBounded =
391 ProposalBounded::Lookup { hash: preimage_hash_subxt, len: encoded_call.len() as u32 };
392
393 let raw_origin_root =
394 quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::Root;
395 let origin_caller =
396 quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin_root);
397
398 let enactment =
399 quantus_subxt::api::runtime_types::frame_support::traits::schedule::DispatchTime::After(
400 0u32,
401 );
402
403 log_print!("🔧 Creating TechReferenda::submit call...");
404 let submit_call =
405 quantus_subxt::api::tx()
406 .tech_referenda()
407 .submit(origin_caller, proposal, enactment);
408
409 let tx_hash = submit_transaction(quantus_client, &keypair, submit_call, None).await?;
410 log_print!(
411 "✅ {} Runtime upgrade proposal submitted! Hash: {:?}",
412 "SUCCESS".bright_green().bold(),
413 tx_hash
414 );
415
416 let _ = wait_for_tx_confirmation(quantus_client.client(), tx_hash).await?;
417 log_success!("🎉 {} Proposal created!", "FINISHED".bright_green().bold());
418 log_print!("💡 Use 'quantus tech-referenda list' to see active proposals");
419 Ok(())
420}
421
422async fn list_proposals(
424 quantus_client: &crate::chain::client::QuantusClient,
425) -> crate::error::Result<()> {
426 log_print!("📜 Active Tech Referenda Proposals");
427 log_print!("");
428
429 let addr = quantus_subxt::api::storage().tech_referenda().referendum_count();
430
431 let latest_block_hash = quantus_client.get_latest_block().await?;
433 let storage_at = quantus_client.client().storage().at(latest_block_hash);
434
435 let count = storage_at.fetch(&addr).await?;
436
437 if let Some(total) = count {
438 log_print!("📊 Total referenda created: {}", total);
439 if total == 0 {
440 log_print!("📭 No active proposals found");
441 return Ok(());
442 }
443 log_print!("🔍 Fetching recent referenda...");
444 for i in (0..total).rev().take(10) {
445 get_proposal_status(quantus_client, i).await?;
446 log_print!("----------------------------------------");
447 }
448 } else {
449 log_print!("📭 No referenda found - Tech Referenda may be empty");
450 }
451
452 Ok(())
453}
454
455async fn get_proposal_details(
457 quantus_client: &crate::chain::client::QuantusClient,
458 index: u32,
459) -> crate::error::Result<()> {
460 log_print!("📄 Tech Referendum #{} Details", index);
461 log_print!("");
462
463 let addr = quantus_subxt::api::storage().tech_referenda().referendum_info_for(index);
464
465 let latest_block_hash = quantus_client.get_latest_block().await?;
467 let storage_at = quantus_client.client().storage().at(latest_block_hash);
468
469 let info = storage_at.fetch(&addr).await?;
470
471 if let Some(referendum_info) = info {
472 log_print!("📋 Referendum Information (raw):");
473 log_print!("{:#?}", referendum_info);
474 } else {
475 log_print!("📭 Referendum #{} not found", index);
476 }
477 Ok(())
478}
479
480async fn get_proposal_status(
482 quantus_client: &crate::chain::client::QuantusClient,
483 index: u32,
484) -> crate::error::Result<()> {
485 use quantus_subxt::api::runtime_types::pallet_referenda::types::ReferendumInfo;
486
487 log_verbose!("📊 Fetching status for Tech Referendum #{}...", index);
488
489 let addr = quantus_subxt::api::storage().tech_referenda().referendum_info_for(index);
490
491 let latest_block_hash = quantus_client.get_latest_block().await?;
493 let storage_at = quantus_client.client().storage().at(latest_block_hash);
494
495 let info_res = storage_at.fetch(&addr).await;
496
497 match info_res {
498 Ok(Some(info)) => {
499 log_print!("📊 Status for Referendum #{}", index.to_string().bright_yellow());
500 match info {
501 ReferendumInfo::Ongoing(status) => {
502 log_print!(" - Status: {}", "Ongoing".bright_green());
503 log_print!(" - Track: {}", status.track);
504 log_print!(" - Submitted at: block {}", status.submitted);
505 log_print!(
506 " - Tally: Ayes: {}, Nays: {}",
507 status.tally.ayes,
508 status.tally.nays
509 );
510 log_verbose!(" - Full status: {:#?}", status);
511 },
512 ReferendumInfo::Approved(submitted, ..) => {
513 log_print!(" - Status: {}", "Approved".green());
514 log_print!(" - Submitted at block: {}", submitted);
515 },
516 ReferendumInfo::Rejected(submitted, ..) => {
517 log_print!(" - Status: {}", "Rejected".red());
518 log_print!(" - Submitted at block: {}", submitted);
519 },
520 ReferendumInfo::Cancelled(submitted, ..) => {
521 log_print!(" - Status: {}", "Cancelled".yellow());
522 log_print!(" - Submitted at block: {}", submitted);
523 },
524 ReferendumInfo::TimedOut(submitted, ..) => {
525 log_print!(" - Status: {}", "TimedOut".dimmed());
526 log_print!(" - Submitted at block: {}", submitted);
527 },
528 ReferendumInfo::Killed(submitted) => {
529 log_print!(" - Status: {}", "Killed".red().bold());
530 log_print!(" - Killed at block: {}", submitted);
531 },
532 }
533 },
534 Ok(None) => log_print!("📭 Referendum #{} not found", index),
535 Err(e) => log_error!("❌ Failed to fetch referendum #{}: {:?}", index, e),
536 }
537
538 Ok(())
539}
540
541async fn place_decision_deposit(
543 quantus_client: &crate::chain::client::QuantusClient,
544 index: u32,
545 from: &str,
546 password: Option<String>,
547 password_file: Option<String>,
548) -> crate::error::Result<()> {
549 log_print!("📋 Placing decision deposit for Tech Referendum #{}", index);
550 log_print!(" 🔑 Placed by: {}", from.bright_yellow());
551
552 let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?;
553
554 let deposit_call = quantus_subxt::api::tx().tech_referenda().place_decision_deposit(index);
555 let tx_hash = submit_transaction(quantus_client, &keypair, deposit_call, None).await?;
556 log_success!("✅ Decision deposit placed! Hash: {:?}", tx_hash.to_string().bright_yellow());
557 let _ = wait_for_tx_confirmation(quantus_client.client(), tx_hash).await?;
558 Ok(())
559}
560
561async fn cancel_proposal(
563 quantus_client: &crate::chain::client::QuantusClient,
564 index: u32,
565 from: &str,
566 password: Option<String>,
567 password_file: Option<String>,
568) -> crate::error::Result<()> {
569 log_print!("❌ Cancelling Tech Referendum #{}", index);
570 log_print!(" 🔑 Cancelled by: {}", from.bright_yellow());
571
572 let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?;
573
574 let inner =
575 quantus_subxt::api::Call::TechReferenda(quantus_subxt::api::tech_referenda::Call::cancel {
576 index,
577 });
578 let sudo_call = quantus_subxt::api::tx().sudo().sudo(inner);
579
580 let tx_hash = submit_transaction(quantus_client, &keypair, sudo_call, None).await?;
581 log_success!("✅ Referendum cancelled! Hash: {:?}", tx_hash.to_string().bright_yellow());
582 let _ = wait_for_tx_confirmation(quantus_client.client(), tx_hash).await?;
583 Ok(())
584}
585
586async fn kill_proposal(
588 quantus_client: &crate::chain::client::QuantusClient,
589 index: u32,
590 from: &str,
591 password: Option<String>,
592 password_file: Option<String>,
593) -> crate::error::Result<()> {
594 log_print!("💀 Killing Tech Referendum #{}", index);
595 log_print!(" 🔑 Killed by: {}", from.bright_yellow());
596
597 let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?;
598
599 let inner =
600 quantus_subxt::api::Call::TechReferenda(quantus_subxt::api::tech_referenda::Call::kill {
601 index,
602 });
603 let sudo_call = quantus_subxt::api::tx().sudo().sudo(inner);
604
605 let tx_hash = submit_transaction(quantus_client, &keypair, sudo_call, None).await?;
606 log_success!("✅ Referendum killed! Hash: {:?}", tx_hash.to_string().bright_yellow());
607 let _ = wait_for_tx_confirmation(quantus_client.client(), tx_hash).await?;
608 Ok(())
609}
610
611async fn nudge_proposal(
613 quantus_client: &crate::chain::client::QuantusClient,
614 index: u32,
615 from: &str,
616 password: Option<String>,
617 password_file: Option<String>,
618) -> crate::error::Result<()> {
619 log_print!("🔄 Nudging Tech Referendum #{}", index);
620 log_print!(" 🔑 Nudged by: {}", from.bright_yellow());
621
622 let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?;
623
624 let inner = quantus_subxt::api::Call::TechReferenda(
625 quantus_subxt::api::tech_referenda::Call::nudge_referendum { index },
626 );
627 let sudo_call = quantus_subxt::api::tx().sudo().sudo(inner);
628
629 let tx_hash = submit_transaction(quantus_client, &keypair, sudo_call, None).await?;
630 log_success!("✅ Referendum nudged! Hash: {:?}", tx_hash.to_string().bright_yellow());
631 let _ = wait_for_tx_confirmation(quantus_client.client(), tx_hash).await?;
632 Ok(())
633}
634
635async fn get_config(
637 quantus_client: &crate::chain::client::QuantusClient,
638) -> crate::error::Result<()> {
639 log_print!("⚙️ Tech Referenda Configuration");
640 log_print!("");
641
642 let constants = quantus_client.client().constants();
643 let tracks_addr = quantus_subxt::api::constants().tech_referenda().tracks();
644
645 match constants.at(&tracks_addr) {
646 Ok(tracks) => {
647 log_print!("{}", "📊 Track Configuration:".bold());
648 for (id, info) in tracks.iter() {
649 log_print!(" ------------------------------------");
650 log_print!(
651 " • {} #{}: {}",
652 "Track".bold(),
653 id,
654 info.name.to_string().bright_cyan()
655 );
656 log_print!(" • Max Deciding: {}", info.max_deciding);
657 log_print!(" • Decision Deposit: {}", info.decision_deposit);
658 log_print!(" • Prepare Period: {} blocks", info.prepare_period);
659 log_print!(" • Decision Period: {} blocks", info.decision_period);
660 log_print!(" • Confirm Period: {} blocks", info.confirm_period);
661 log_print!(" • Min Enactment Period: {} blocks", info.min_enactment_period);
662 }
663 log_print!(" ------------------------------------");
664 },
665 Err(e) => {
666 log_error!("❌ Failed to decode Tracks constant: {:?}", e);
667 log_print!("💡 It's possible the Tracks constant is not in the expected format.");
668 },
669 }
670
671 Ok(())
672}
673
674async fn refund_submission_deposit(
676 quantus_client: &crate::chain::client::QuantusClient,
677 index: u32,
678 from: &str,
679 password: Option<String>,
680 password_file: Option<String>,
681) -> crate::error::Result<()> {
682 log_print!("💰 Refunding submission deposit for Tech Referendum #{}", index);
683 log_print!(" 🔑 Refund to: {}", from.bright_yellow());
684
685 let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?;
687
688 let refund_call = quantus_subxt::api::tx().tech_referenda().refund_submission_deposit(index);
690
691 let tx_hash = submit_transaction(quantus_client, &keypair, refund_call, None).await?;
692 log_print!(
693 "✅ {} Refund transaction submitted! Hash: {:?}",
694 "SUCCESS".bright_green().bold(),
695 tx_hash
696 );
697
698 let _ = wait_for_tx_confirmation(quantus_client.client(), tx_hash).await?;
699 log_success!("🎉 {} Submission deposit refunded!", "FINISHED".bright_green().bold());
700 log_print!("💡 Check your balance to confirm the refund");
701 Ok(())
702}
703
704async fn refund_decision_deposit(
706 quantus_client: &crate::chain::client::QuantusClient,
707 index: u32,
708 from: &str,
709 password: Option<String>,
710 password_file: Option<String>,
711) -> crate::error::Result<()> {
712 log_print!("💰 Refunding decision deposit for Tech Referendum #{}", index);
713 log_print!(" 🔑 Refund to: {}", from.bright_yellow());
714
715 let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?;
717
718 let refund_call = quantus_subxt::api::tx().tech_referenda().refund_decision_deposit(index);
720
721 let tx_hash = submit_transaction(quantus_client, &keypair, refund_call, None).await?;
722 log_print!(
723 "✅ {} Refund transaction submitted! Hash: {:?}",
724 "SUCCESS".bright_green().bold(),
725 tx_hash
726 );
727
728 let _ = wait_for_tx_confirmation(quantus_client.client(), tx_hash).await?;
729 log_success!("🎉 {} Decision deposit refunded!", "FINISHED".bright_green().bold());
730 log_print!("💡 Check your balance to confirm the refund");
731 Ok(())
732}