diff --git a/scripts/high_security_example.sh b/scripts/high_security_example.sh new file mode 100644 index 0000000..9478328 --- /dev/null +++ b/scripts/high_security_example.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# High Security Example Script +# This script demonstrates the high security features of the Quantus blockchain. +# It sets up a guardian for an account and demonstrates the reversible transfer functionality. +# It also demonstrates the recovery pallet functionality. + +# set this to your binary +alias quantus="./target/release/quantus --node-url ws://127.0.0.1:9944" + +# Alice sets charlie as her guardian with a 1 hour delay +quantus high-security set --from crystal_alice --interceptor crystal_charlie --delay-seconds 3600 + +# Check the status of the high security +quantus high-security status --account crystal_alice + +# fail case 1 Alice sets bob as her interceptor - this should fail because alice already has a guardian +quantus high-security set --from crystal_alice --interceptor crystal_bob --delay-seconds 3600 + +# fail case 2 could also try to send a normal tx - should fail +quantus send --from crystal_alice --to crystal_bob --amount 9999 + +# fail case 3 also send a reversible with a different delay more or less - should fail +quantus reversible schedule-transfer-with-delay --from crystal_alice --to crystal_bob --amount 5556 --delay 90 + +# Check balances of Alice and Charlie +quantus balance --address crystal_alice +quantus balance --address crystal_charlie + +# Alice sends a reversible transfer to bob over 500000 coins of quantus over 1 hour delay +quantus reversible schedule-transfer --from crystal_alice --to crystal_bob --amount 500000 + +quantus reversible list-pending --from crystal_alice + +# Interceptor account charlie reverses transaction +quantus reversible cancel --tx-id 0xb8ee1f940e13fbc171481d1b06967760bf1d39f06dbcdb595c02c420aec6a45e --from crystal_charlie + +# Check balances of Alice, Bob, and Charlie +quantus balance --address crystal_alice +quantus balance --address crystal_bob +quantus balance --address crystal_charlie + +# activate the recovery first vouch then claim. +ququantus recovery initiate --rescuer crystal_charlie --lost crystal_alice +quantus recovery active --rescuer crystal_charlie --lost crystal_alice +quantus recovery vouch --rescuer crystal_charlie --lost crystal_alice --friend crystal_charlie +quantus recovery claim --rescuer crystal_charlie --lost crystal_alice +quantus recovery proxy-of --rescuer crystal_charlie + +# Charlie pulls all money from Alice's account +quantus recovery recover-all --rescuer crystal_charlie --lost crystal_alice --dest crystal_charlie + +# Check balances of Alice, Bob, and Charlie +quantus balance --address crystal_alice +quantus balance --address crystal_bob +quantus balance --address crystal_charlie \ No newline at end of file diff --git a/src/chain/client.rs b/src/chain/client.rs index 910d192..5d85f68 100644 --- a/src/chain/client.rs +++ b/src/chain/client.rs @@ -64,15 +64,6 @@ impl QuantusClient { ))); } - // Provide helpful hints for common URL issues - if node_url.starts_with("ws://") && - (node_url.contains("a.i.res.fm") || node_url.contains("a.t.res.fm")) - { - log_verbose!( - "πŸ’‘ Hint: Remote nodes typically require secure WebSocket connections (wss://)" - ); - } - // Create WS client with custom timeouts let ws_client = WsClientBuilder::default() // TODO: Make these configurable in a separate change @@ -85,11 +76,11 @@ impl QuantusClient { // Provide more helpful error messages for common issues let error_str = format!("{e:?}"); let error_msg = if error_str.contains("TimedOut") || error_str.contains("timed out") { - if node_url.starts_with("ws://") && (node_url.contains("a.i.res.fm") || node_url.contains("a.t.res.fm")) { + if node_url.starts_with("ws://") { format!( - "Connection timed out. This remote node requires secure WebSocket connections (wss://). Try using 'wss://{}' instead of 'ws://{}'", + "Connection timed out. Try using 'wss://{}' instead of '{}'", node_url.strip_prefix("ws://").unwrap_or(node_url), - node_url.strip_prefix("ws://").unwrap_or(node_url) + node_url ) } else { format!("Connection timed out. Please check if the node is running and accessible at: {node_url}") diff --git a/src/cli/batch.rs b/src/cli/batch.rs index 4c7819f..b1b84c8 100644 --- a/src/cli/batch.rs +++ b/src/cli/batch.rs @@ -63,7 +63,7 @@ pub enum BatchCommands { pub async fn handle_batch_command( command: BatchCommands, node_url: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> Result<()> { match command { BatchCommands::Send { @@ -86,7 +86,7 @@ pub async fn handle_batch_command( count, to, amount, - finalized, + execution_mode, ) .await, BatchCommands::Config { limits, info } => @@ -105,7 +105,7 @@ async fn handle_batch_send_command( count: Option, to: Option, amount: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> Result<()> { // Create quantus chain client let quantus_client = QuantusClient::new(node_url).await?; @@ -166,7 +166,7 @@ async fn handle_batch_send_command( // Submit batch transaction let tx_hash = - batch_transfer(&quantus_client, &keypair, transfers, tip_amount, finalized).await?; + batch_transfer(&quantus_client, &keypair, transfers, tip_amount, execution_mode).await?; log_print!( "βœ… {} Batch transaction submitted! Hash: {:?}", diff --git a/src/cli/common.rs b/src/cli/common.rs index 7328737..74fd89f 100644 --- a/src/cli/common.rs +++ b/src/cli/common.rs @@ -7,6 +7,12 @@ use subxt::{ OnlineClient, }; +#[derive(Debug, Clone, Copy, Default)] +pub struct ExecutionMode { + pub finalized: bool, + pub wait_for_transaction: bool, +} + /// Resolve address - if it's a wallet name, return the wallet's address /// If it's already an SS58 address, return it as is pub fn resolve_address(address_or_wallet_name: &str) -> Result { @@ -117,12 +123,13 @@ pub async fn get_incremented_nonce_with_client( /// /// By default (finalized=false), waits until transaction is in the best block (fast) /// With finalized=true, waits until transaction is in a finalized block (slow in PoW chains) +/// With wait_for_transaction=false, returns immediately after submission without waiting pub async fn submit_transaction( quantus_client: &crate::chain::client::QuantusClient, from_keypair: &crate::wallet::QuantumKeyPair, call: Call, tip: Option, - finalized: bool, + execution_mode: ExecutionMode, ) -> crate::error::Result where Call: subxt::tx::Payload, @@ -137,7 +144,6 @@ where loop { attempt += 1; - // Get fresh nonce for each attempt, or increment if we have a previous nonce let nonce = if let Some(prev_nonce) = current_nonce { // After first failure, try with incremented nonce @@ -178,13 +184,13 @@ where } // Try to get chain parameters from the client - let genesis_hash = quantus_client.get_genesis_hash().await?; - let (spec_version, transaction_version) = quantus_client.get_runtime_version().await?; + // let genesis_hash = quantus_client.get_genesis_hash().await?; + // let (spec_version, transaction_version) = quantus_client.get_runtime_version().await?; - log_verbose!("πŸ” Chain parameters:"); - log_verbose!(" Genesis hash: {:?}", genesis_hash); - log_verbose!(" Spec version: {}", spec_version); - log_verbose!(" Transaction version: {}", transaction_version); + // log_verbose!("πŸ” Chain parameters:"); + // log_verbose!(" Genesis hash: {:?}", genesis_hash); + // log_verbose!(" Spec version: {}", spec_version); + // log_verbose!(" Transaction version: {}", transaction_version); // For now, just use the default params let params = params_builder.build(); @@ -204,50 +210,69 @@ where log_verbose!("πŸ” Additional debugging:"); log_verbose!(" Call type: {:?}", std::any::type_name::()); - // Submit the transaction with fresh nonce and optional tip - match quantus_client - .client() - .tx() - .sign_and_submit_then_watch(&call, &signer, params) - .await - { - Ok(mut tx_progress) => { - crate::log_verbose!("πŸ“‹ Transaction submitted: {:?}", tx_progress); + if execution_mode.wait_for_transaction { + match quantus_client + .client() + .tx() + .sign_and_submit_then_watch(&call, &signer, params) + .await + { + Ok(mut tx_progress) => { + crate::log_verbose!("πŸ“‹ Transaction submitted: {:?}", tx_progress); - let tx_hash = tx_progress.extrinsic_hash(); - wait_tx_inclusion(&mut tx_progress, finalized).await?; + let tx_hash = tx_progress.extrinsic_hash(); - return Ok(tx_hash); - }, - Err(e) => { - let error_msg = format!("{e:?}"); - - // Check if it's a retryable error - let is_retryable = error_msg.contains("Priority is too low") || - error_msg.contains("Transaction is outdated") || - error_msg.contains("Transaction is temporarily banned") || - error_msg.contains("Transaction has a bad signature") || - error_msg.contains("Invalid Transaction"); - - if is_retryable && attempt < 5 { - log_verbose!( - "⚠️ Transaction error detected (attempt {}/5): {}", - attempt, - error_msg - ); - - // Exponential backoff: 2s, 4s, 8s, 16s - let delay = std::cmp::min(2u64.pow(attempt as u32), 16); - log_verbose!("⏳ Waiting {} seconds before retry...", delay); - tokio::time::sleep(tokio::time::Duration::from_secs(delay)).await; - continue; - } else { - log_verbose!("❌ Final error after {} attempts: {}", attempt, error_msg); + if !execution_mode.wait_for_transaction { + return Ok(tx_hash); + } + + wait_tx_inclusion(&mut tx_progress, execution_mode.finalized).await?; + + return Ok(tx_hash); + }, + Err(e) => { + let error_msg = format!("{e:?}"); + + // Check if it's a retryable error + let is_retryable = error_msg.contains("Priority is too low") || + error_msg.contains("Transaction is outdated") || + error_msg.contains("Transaction is temporarily banned") || + error_msg.contains("Transaction has a bad signature") || + error_msg.contains("Invalid Transaction"); + + if is_retryable && attempt < 5 { + log_verbose!( + "⚠️ Transaction error detected (attempt {}/5): {}", + attempt, + error_msg + ); + + // Exponential backoff: 2s, 4s, 8s, 16s + let delay = std::cmp::min(2u64.pow(attempt as u32), 16); + log_verbose!("⏳ Waiting {} seconds before retry...", delay); + tokio::time::sleep(tokio::time::Duration::from_secs(delay)).await; + continue; + } else { + log_verbose!("❌ Final error after {} attempts: {}", attempt, error_msg); + return Err(crate::error::QuantusError::NetworkError(format!( + "Failed to submit transaction: {e:?}" + ))); + } + }, + } + } else { + match quantus_client.client().tx().sign_and_submit(&call, &signer, params).await { + Ok(tx_hash) => { + crate::log_print!("βœ… Transaction submitted: {:?}", tx_hash); + return Ok(tx_hash); + }, + Err(e) => { + log_error!("❌ Failed to submit transaction: {e:?}"); return Err(crate::error::QuantusError::NetworkError(format!( "Failed to submit transaction: {e:?}" ))); - } - }, + }, + } } } } @@ -259,7 +284,7 @@ pub async fn submit_transaction_with_nonce( call: Call, tip: Option, nonce: u32, - finalized: bool, + execution_mode: ExecutionMode, ) -> crate::error::Result where Call: subxt::tx::Payload, @@ -291,25 +316,42 @@ where log_verbose!("πŸ”’ Using manual nonce: {}", nonce); log_verbose!("πŸ“€ Submitting transaction with manual nonce..."); + crate::log_print!("submit with wait for transaction: {}", execution_mode.wait_for_transaction); // Submit the transaction with manual nonce - match quantus_client - .client() - .tx() - .sign_and_submit_then_watch(&call, &signer, params) - .await - { - Ok(mut tx_progress) => { - let tx_hash = tx_progress.extrinsic_hash(); - log_verbose!("βœ… Transaction submitted successfully: {:?}", tx_hash); - wait_tx_inclusion(&mut tx_progress, finalized).await?; - Ok(tx_hash) - }, - Err(e) => { - log_error!("❌ Failed to submit transaction with manual nonce {}: {e:?}", nonce); - Err(crate::error::QuantusError::NetworkError(format!( - "Failed to submit transaction with nonce {nonce}: {e:?}" - ))) - }, + + if execution_mode.wait_for_transaction { + match quantus_client + .client() + .tx() + .sign_and_submit_then_watch(&call, &signer, params) + .await + { + Ok(mut tx_progress) => { + let tx_hash = tx_progress.extrinsic_hash(); + crate::log_print!("βœ… Transaction submitted: {:?}", tx_hash); + wait_tx_inclusion(&mut tx_progress, execution_mode.finalized).await?; + Ok(tx_hash) + }, + Err(e) => { + log_error!("❌ Failed to submit transaction with manual nonce {}: {e:?}", nonce); + Err(crate::error::QuantusError::NetworkError(format!( + "Failed to submit transaction with nonce {nonce}: {e:?}" + ))) + }, + } + } else { + match quantus_client.client().tx().sign_and_submit(&call, &signer, params).await { + Ok(tx_hash) => { + crate::log_print!("βœ… Transaction submitted: {:?}", tx_hash); + Ok(tx_hash) + }, + Err(e) => { + log_error!("❌ Failed to submit transaction: {e:?}"); + Err(crate::error::QuantusError::NetworkError(format!( + "Failed to submit transaction: {e:?}" + ))) + }, + } } } @@ -324,46 +366,54 @@ async fn wait_tx_inclusion( ) -> Result<()> { use indicatif::{ProgressBar, ProgressStyle}; - // Create spinner (only in non-verbose mode) + let start_time = std::time::Instant::now(); + let spinner = if !crate::log::is_verbose() { let pb = ProgressBar::new_spinner(); pb.set_style( ProgressStyle::default_spinner() .tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏") - .template("{spinner:.cyan} {msg} {elapsed:.dim}") + .template("{spinner:.cyan} {msg}") .unwrap(), ); if finalized { - pb.set_message("Waiting for finalized block..."); + pb.set_message("Waiting for finalized block... (0s)"); } else { - pb.set_message("Waiting for block inclusion..."); + pb.set_message("Waiting for block inclusion... (0s)"); } - pb.enable_steady_tick(std::time::Duration::from_millis(100)); + pb.enable_steady_tick(std::time::Duration::from_millis(500)); Some(pb) } else { None }; while let Some(Ok(status)) = tx_progress.next().await { - crate::log_verbose!(" Transaction status: {:?}", status); + let elapsed_secs = start_time.elapsed().as_secs(); + crate::log_verbose!(" Transaction status: {:?} (elapsed: {}s)", status, elapsed_secs); match status { TxStatus::Validated => if let Some(ref pb) = spinner { - pb.set_message("Transaction validated βœ“"); + pb.set_message(format!("Transaction validated βœ“ ({}s)", elapsed_secs)); }, TxStatus::InBestBlock(block_hash) => { crate::log_verbose!(" Transaction included in block: {:?}", block_hash); if finalized { if let Some(ref pb) = spinner { - pb.set_message("In best block, waiting for finalization..."); + pb.set_message(format!( + "In best block, waiting for finalization... ({}s)", + elapsed_secs + )); } continue; } else { if let Some(pb) = spinner { - pb.finish_with_message("βœ… Transaction included in block!"); + pb.finish_with_message(format!( + "βœ… Transaction included in block! ({}s)", + elapsed_secs + )); } break; }; @@ -371,18 +421,36 @@ async fn wait_tx_inclusion( TxStatus::InFinalizedBlock(block_hash) => { crate::log_verbose!(" Transaction finalized in block: {:?}", block_hash); if let Some(pb) = spinner { - pb.finish_with_message("βœ… Transaction finalized!"); + pb.finish_with_message(format!( + "βœ… Transaction finalized! ({}s)", + elapsed_secs + )); } break; }, TxStatus::Error { message } | TxStatus::Invalid { message } => { - crate::log_error!(" Transaction error: {}", message); + crate::log_error!(" Transaction error: {} (elapsed: {}s)", message, elapsed_secs); if let Some(pb) = spinner { - pb.finish_with_message("❌ Transaction error!"); + pb.finish_with_message(format!("❌ Transaction error! ({}s)", elapsed_secs)); } break; }, - _ => continue, + _ => { + if let Some(ref pb) = spinner { + if finalized { + pb.set_message(format!( + "Waiting for finalized block... ({}s)", + elapsed_secs + )); + } else { + pb.set_message(format!( + "Waiting for block inclusion... ({}s)", + elapsed_secs + )); + } + } + continue; + }, } } diff --git a/src/cli/generic_call.rs b/src/cli/generic_call.rs index 242341f..fe2049a 100644 --- a/src/cli/generic_call.rs +++ b/src/cli/generic_call.rs @@ -15,7 +15,7 @@ pub async fn execute_generic_call( args: Vec, from_keypair: &QuantumKeyPair, tip: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result { log_print!("πŸš€ Executing generic call"); log_print!("Pallet: {}", pallet.bright_green()); @@ -60,7 +60,7 @@ pub async fn execute_generic_call( &args, false, tip_amount, - finalized, + execution_mode, ) .await?, ("Balances", "transfer_keep_alive") => @@ -70,30 +70,36 @@ pub async fn execute_generic_call( &args, true, tip_amount, - finalized, + execution_mode, ) .await?, // System pallet calls ("System", "remark") => - submit_system_remark(quantus_client, from_keypair, &args, tip_amount, finalized).await?, + submit_system_remark(quantus_client, from_keypair, &args, tip_amount, execution_mode) + .await?, // Sudo pallet calls ("Sudo", "sudo") => submit_sudo_call(quantus_client, from_keypair, &args).await?, // TechCollective pallet calls ("TechCollective", "add_member") => - submit_tech_collective_add_member(quantus_client, from_keypair, &args, finalized) + submit_tech_collective_add_member(quantus_client, from_keypair, &args, execution_mode) .await?, ("TechCollective", "remove_member") => - submit_tech_collective_remove_member(quantus_client, from_keypair, &args, finalized) - .await?, + submit_tech_collective_remove_member( + quantus_client, + from_keypair, + &args, + execution_mode, + ) + .await?, ("TechCollective", "vote") => - submit_tech_collective_vote(quantus_client, from_keypair, &args, finalized).await?, + submit_tech_collective_vote(quantus_client, from_keypair, &args, execution_mode).await?, // ReversibleTransfers pallet calls ("ReversibleTransfers", "schedule_transfer") => - submit_reversible_transfer(quantus_client, from_keypair, &args, finalized).await?, + submit_reversible_transfer(quantus_client, from_keypair, &args, execution_mode).await?, // Scheduler pallet calls ("Scheduler", "schedule") => @@ -135,7 +141,7 @@ async fn submit_balance_transfer( args: &[Value], keep_alive: bool, tip: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result { if args.len() != 2 { return Err(QuantusError::Generic( @@ -170,7 +176,7 @@ async fn submit_balance_transfer( from_keypair, transfer_call, tip, - finalized, + execution_mode, ) .await } else { @@ -183,7 +189,7 @@ async fn submit_balance_transfer( from_keypair, transfer_call, tip, - finalized, + execution_mode, ) .await } @@ -195,7 +201,7 @@ async fn submit_system_remark( from_keypair: &QuantumKeyPair, args: &[Value], tip: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result { if args.len() != 1 { return Err(QuantusError::Generic( @@ -214,7 +220,7 @@ async fn submit_system_remark( from_keypair, remark_call, tip, - finalized, + execution_mode, ) .await } @@ -238,7 +244,7 @@ async fn submit_tech_collective_add_member( quantus_client: &crate::chain::client::QuantusClient, from_keypair: &QuantumKeyPair, args: &[Value], - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result { if args.len() != 1 { return Err(QuantusError::Generic( @@ -265,8 +271,14 @@ async fn submit_tech_collective_add_member( }, )); - crate::cli::common::submit_transaction(quantus_client, from_keypair, sudo_call, None, finalized) - .await + crate::cli::common::submit_transaction( + quantus_client, + from_keypair, + sudo_call, + None, + execution_mode, + ) + .await } /// Submit tech collective remove member @@ -274,7 +286,7 @@ async fn submit_tech_collective_remove_member( quantus_client: &crate::chain::client::QuantusClient, from_keypair: &QuantumKeyPair, args: &[Value], - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result { if args.len() != 1 { return Err(QuantusError::Generic( @@ -302,8 +314,14 @@ async fn submit_tech_collective_remove_member( }, )); - crate::cli::common::submit_transaction(quantus_client, from_keypair, sudo_call, None, finalized) - .await + crate::cli::common::submit_transaction( + quantus_client, + from_keypair, + sudo_call, + None, + execution_mode, + ) + .await } /// Submit tech collective vote @@ -311,7 +329,7 @@ async fn submit_tech_collective_vote( quantus_client: &crate::chain::client::QuantusClient, from_keypair: &QuantumKeyPair, args: &[Value], - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result { if args.len() != 2 { return Err(QuantusError::Generic( @@ -324,8 +342,14 @@ async fn submit_tech_collective_vote( let vote_call = quantus_subxt::api::tx().tech_collective().vote(referendum_index, aye); - crate::cli::common::submit_transaction(quantus_client, from_keypair, vote_call, None, finalized) - .await + crate::cli::common::submit_transaction( + quantus_client, + from_keypair, + vote_call, + None, + execution_mode, + ) + .await } /// Submit reversible transfer @@ -333,7 +357,7 @@ async fn submit_reversible_transfer( quantus_client: &crate::chain::client::QuantusClient, from_keypair: &QuantumKeyPair, args: &[Value], - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result { if args.len() != 2 { return Err(QuantusError::Generic( @@ -367,7 +391,7 @@ async fn submit_reversible_transfer( from_keypair, schedule_call, None, - finalized, + execution_mode, ) .await } @@ -406,13 +430,13 @@ pub async fn handle_generic_call( keypair: &QuantumKeyPair, tip: Option, node_url: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸš€ Generic Call"); let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?; - execute_generic_call(&quantus_client, pallet, call, args, keypair, tip, finalized).await?; + execute_generic_call(&quantus_client, pallet, call, args, keypair, tip, execution_mode).await?; Ok(()) } diff --git a/src/cli/high_security.rs b/src/cli/high_security.rs index ed2ae18..ac971d2 100644 --- a/src/cli/high_security.rs +++ b/src/cli/high_security.rs @@ -48,7 +48,7 @@ pub enum HighSecurityCommands { pub async fn handle_high_security_command( command: HighSecurityCommands, node_url: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?; @@ -165,7 +165,7 @@ pub async fn handle_high_security_command( &keypair, tx_call, None, - finalized, + execution_mode, ) .await?; diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 5232cf3..a5c768e 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -244,7 +244,7 @@ pub async fn execute_command( command: Commands, node_url: &str, verbose: bool, - finalized: bool, + execution_mode: common::ExecutionMode, ) -> crate::error::Result<()> { match command { Commands::Wallet(wallet_cmd) => wallet::handle_wallet_command(wallet_cmd, node_url).await, @@ -258,39 +258,43 @@ pub async fn execute_command( password_file, tip, nonce, - finalized, + execution_mode, ) .await, Commands::Batch(batch_cmd) => - batch::handle_batch_command(batch_cmd, node_url, finalized).await, + batch::handle_batch_command(batch_cmd, node_url, execution_mode).await, Commands::Reversible(reversible_cmd) => - reversible::handle_reversible_command(reversible_cmd, node_url, finalized).await, + reversible::handle_reversible_command(reversible_cmd, node_url, execution_mode).await, Commands::HighSecurity(hs_cmd) => - high_security::handle_high_security_command(hs_cmd, node_url, finalized).await, + high_security::handle_high_security_command(hs_cmd, node_url, execution_mode).await, Commands::Recovery(recovery_cmd) => - recovery::handle_recovery_command(recovery_cmd, node_url, finalized).await, + recovery::handle_recovery_command(recovery_cmd, node_url, execution_mode).await, Commands::Scheduler(scheduler_cmd) => - scheduler::handle_scheduler_command(scheduler_cmd, node_url, finalized).await, + scheduler::handle_scheduler_command(scheduler_cmd, node_url, execution_mode).await, Commands::Storage(storage_cmd) => - storage::handle_storage_command(storage_cmd, node_url, finalized).await, + storage::handle_storage_command(storage_cmd, node_url, execution_mode).await, Commands::TechCollective(tech_collective_cmd) => tech_collective::handle_tech_collective_command( tech_collective_cmd, node_url, - finalized, + execution_mode, ) .await, Commands::Preimage(preimage_cmd) => - preimage::handle_preimage_command(preimage_cmd, node_url, finalized).await, + preimage::handle_preimage_command(preimage_cmd, node_url, execution_mode).await, Commands::TechReferenda(tech_referenda_cmd) => - tech_referenda::handle_tech_referenda_command(tech_referenda_cmd, node_url, finalized) - .await, + tech_referenda::handle_tech_referenda_command( + tech_referenda_cmd, + node_url, + execution_mode, + ) + .await, Commands::Referenda(referenda_cmd) => - referenda::handle_referenda_command(referenda_cmd, node_url, finalized).await, + referenda::handle_referenda_command(referenda_cmd, node_url, execution_mode).await, Commands::Treasury(treasury_cmd) => - treasury::handle_treasury_command(treasury_cmd, node_url, finalized).await, + treasury::handle_treasury_command(treasury_cmd, node_url, execution_mode).await, Commands::Runtime(runtime_cmd) => - runtime::handle_runtime_command(runtime_cmd, node_url, finalized).await, + runtime::handle_runtime_command(runtime_cmd, node_url, execution_mode).await, Commands::Call { pallet, call, @@ -313,7 +317,7 @@ pub async fn execute_command( offline, call_data_only, node_url, - finalized, + execution_mode, ) .await, Commands::Balance { address } => { @@ -378,7 +382,7 @@ async fn handle_generic_call_command( offline: bool, call_data_only: bool, node_url: &str, - finalized: bool, + execution_mode: common::ExecutionMode, ) -> crate::error::Result<()> { // For now, we only support live submission (not offline or call-data-only) if offline { @@ -403,8 +407,16 @@ async fn handle_generic_call_command( vec![] }; - generic_call::handle_generic_call(&pallet, &call, args_vec, &keypair, tip, node_url, finalized) - .await + generic_call::handle_generic_call( + &pallet, + &call, + args_vec, + &keypair, + tip, + node_url, + execution_mode, + ) + .await } /// Handle developer subcommands diff --git a/src/cli/preimage.rs b/src/cli/preimage.rs index 267f91a..1a5206e 100644 --- a/src/cli/preimage.rs +++ b/src/cli/preimage.rs @@ -70,7 +70,7 @@ pub enum PreimageCommands { pub async fn handle_preimage_command( command: PreimageCommands, node_url: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?; @@ -85,14 +85,21 @@ pub async fn handle_preimage_command( list_preimages(&quantus_client).await?; }, PreimageCommands::Request { hash, from } => { - request_preimage(&quantus_client, &hash, &from, finalized).await?; + request_preimage(&quantus_client, &hash, &from, execution_mode).await?; }, PreimageCommands::Note { content, from } => { - note_preimage(&quantus_client, &content, &from, finalized).await?; + note_preimage(&quantus_client, &content, &from, execution_mode).await?; }, PreimageCommands::Create { wasm_file, from, password, password_file } => { - create_preimage(&quantus_client, wasm_file, &from, password, password_file, finalized) - .await?; + create_preimage( + &quantus_client, + wasm_file, + &from, + password, + password_file, + execution_mode, + ) + .await?; }, } @@ -295,7 +302,7 @@ async fn request_preimage( quantus_client: &crate::chain::client::QuantusClient, hash_str: &str, from_str: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { let preimage_hash = parse_hash(hash_str)?; @@ -314,7 +321,7 @@ async fn request_preimage( &keypair, request_call, None, - finalized, + execution_mode, ) .await?; log_print!("βœ… Preimage request transaction submitted: {:?}", tx_hash); @@ -331,7 +338,7 @@ async fn note_preimage( quantus_client: &crate::chain::client::QuantusClient, content_str: &str, from_str: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { let content = hex::decode(content_str.trim_start_matches("0x")) .map_err(|e| QuantusError::Generic(format!("Invalid hex content: {}", e)))?; @@ -351,7 +358,7 @@ async fn note_preimage( &keypair, note_call, None, - finalized, + execution_mode, ) .await?; log_print!("βœ… Preimage note transaction submitted: {:?}", tx_hash); @@ -370,7 +377,7 @@ async fn create_preimage( from_str: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { use qp_poseidon::PoseidonHasher; @@ -415,7 +422,7 @@ async fn create_preimage( &keypair, note_preimage_tx, None, - finalized, + execution_mode, ) .await?; log_print!("βœ… Preimage transaction submitted: {:?}", preimage_tx_hash); diff --git a/src/cli/recovery.rs b/src/cli/recovery.rs index 57f7792..6b04467 100644 --- a/src/cli/recovery.rs +++ b/src/cli/recovery.rs @@ -169,7 +169,7 @@ pub enum RecoveryCommands { pub async fn handle_recovery_command( command: RecoveryCommands, node_url: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?; @@ -195,7 +195,7 @@ pub async fn handle_recovery_command( &rescuer_key, call, None, - finalized, + execution_mode, ) .await .map_err(|e| { @@ -230,7 +230,7 @@ pub async fn handle_recovery_command( &friend_key, call, None, - finalized, + execution_mode, ) .await .map_err(|e| { @@ -258,7 +258,7 @@ pub async fn handle_recovery_command( &rescuer_key, call, None, - finalized, + execution_mode, ) .await .map_err(|e| { @@ -318,7 +318,9 @@ pub async fn handle_recovery_command( quantus_client.client().storage().at(latest).fetch(&proxy_storage).await; let proxy_of = match proxy_result { Ok(Some(proxy)) => { - log_print!("🧩 Proxy mapping: rescuer proxies -> {}", format!("{}", proxy)); + let proxy_bytes: &[u8; 32] = proxy.as_ref(); + let proxy_sp = SpAccountId32::from(*proxy_bytes); + log_print!("🧩 Proxy mapping: rescuer proxies -> {}", proxy_sp.to_ss58check()); Some(proxy) }, Ok(None) => { @@ -326,7 +328,8 @@ pub async fn handle_recovery_command( "❌ No proxy mapping found for rescuer - recovery not set up properly" ); return Err(crate::error::QuantusError::Generic( - "Rescuer has no proxy mapping. Recovery process may not be properly set up.".to_string() + "Rescuer has no proxy mapping. Recovery process may not be properly set up." + .to_string(), )); }, Err(e) => { @@ -339,7 +342,9 @@ pub async fn handle_recovery_command( // Validate that the proxy points to the correct lost account if let Some(proxy) = proxy_of { - let proxy_addr = format!("{proxy}"); + let proxy_bytes: &[u8; 32] = proxy.as_ref(); + let proxy_sp = SpAccountId32::from(*proxy_bytes); + let proxy_addr = proxy_sp.to_ss58check(); if proxy_addr != lost_resolved { log_error!( "❌ Proxy mismatch! Rescuer proxies {} but we're trying to recover {}", @@ -368,7 +373,7 @@ pub async fn handle_recovery_command( &rescuer_key, call, None, - finalized, + execution_mode, ) .await { @@ -479,7 +484,7 @@ pub async fn handle_recovery_command( &rescuer_key, call, None, - finalized, + execution_mode, ) .await { @@ -508,7 +513,7 @@ pub async fn handle_recovery_command( &lost_key, call, None, - finalized, + execution_mode, ) .await .map_err(|e| { @@ -538,7 +543,7 @@ pub async fn handle_recovery_command( &rescuer_key, call, None, - finalized, + execution_mode, ) .await .map_err(|e| { diff --git a/src/cli/referenda.rs b/src/cli/referenda.rs index 75f7be5..04f4416 100644 --- a/src/cli/referenda.rs +++ b/src/cli/referenda.rs @@ -173,7 +173,7 @@ pub enum ReferendaCommands { pub async fn handle_referenda_command( command: ReferendaCommands, node_url: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?; @@ -186,7 +186,7 @@ pub async fn handle_referenda_command( password, password_file, &origin, - finalized, + execution_mode, ) .await, ReferendaCommands::Submit { preimage_hash, from, password, password_file, origin } => @@ -197,7 +197,7 @@ pub async fn handle_referenda_command( password, password_file, &origin, - finalized, + execution_mode, ) .await, ReferendaCommands::List => list_proposals(&quantus_client).await, @@ -211,7 +211,7 @@ pub async fn handle_referenda_command( &from, password, password_file, - finalized, + execution_mode, ) .await, ReferendaCommands::Vote { @@ -232,7 +232,7 @@ pub async fn handle_referenda_command( &from, password, password_file, - finalized, + execution_mode, ) .await, ReferendaCommands::RefundSubmissionDeposit { index, from, password, password_file } => @@ -242,7 +242,7 @@ pub async fn handle_referenda_command( &from, password, password_file, - finalized, + execution_mode, ) .await, ReferendaCommands::RefundDecisionDeposit { index, from, password, password_file } => @@ -252,7 +252,7 @@ pub async fn handle_referenda_command( &from, password, password_file, - finalized, + execution_mode, ) .await, ReferendaCommands::Config => get_config(&quantus_client).await, @@ -267,7 +267,7 @@ async fn submit_remark_proposal( password: Option, password_file: Option, origin_type: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { use qp_poseidon::PoseidonHasher; @@ -301,7 +301,8 @@ async fn submit_remark_proposal( log_print!("πŸ“ Submitting preimage..."); let note_preimage_tx = quantus_subxt::api::tx().preimage().note_preimage(bounded_bytes); let preimage_tx_hash = - submit_transaction(quantus_client, &keypair, note_preimage_tx, None, finalized).await?; + submit_transaction(quantus_client, &keypair, note_preimage_tx, None, execution_mode) + .await?; log_print!("βœ… Preimage transaction submitted: {:?}", preimage_tx_hash); // Wait for preimage transaction confirmation @@ -358,7 +359,7 @@ async fn submit_remark_proposal( quantus_subxt::api::tx().referenda().submit(origin_caller, proposal, enactment); let tx_hash = - submit_transaction(quantus_client, &keypair, submit_call, None, finalized).await?; + submit_transaction(quantus_client, &keypair, submit_call, None, execution_mode).await?; log_print!( "βœ… {} Referendum proposal submitted! Hash: {:?}", "SUCCESS".bright_green().bold(), @@ -377,7 +378,7 @@ async fn submit_proposal( password: Option, password_file: Option, origin_type: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ“ Submitting Proposal to Referenda"); log_print!(" πŸ”— Preimage hash: {}", preimage_hash.bright_cyan()); @@ -475,7 +476,7 @@ async fn submit_proposal( quantus_subxt::api::tx().referenda().submit(origin_caller, proposal, enactment); let tx_hash = - submit_transaction(quantus_client, &keypair, submit_call, None, finalized).await?; + submit_transaction(quantus_client, &keypair, submit_call, None, execution_mode).await?; log_print!( "βœ… {} Referendum proposal submitted! Hash: {:?}", "SUCCESS".bright_green().bold(), @@ -685,7 +686,7 @@ async fn place_decision_deposit( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ“‹ Placing decision deposit for Referendum #{}", index); log_print!(" πŸ”‘ Placed by: {}", from.bright_yellow()); @@ -694,7 +695,7 @@ async fn place_decision_deposit( let deposit_call = quantus_subxt::api::tx().referenda().place_decision_deposit(index); let tx_hash = - submit_transaction(quantus_client, &keypair, deposit_call, None, finalized).await?; + submit_transaction(quantus_client, &keypair, deposit_call, None, execution_mode).await?; log_success!("βœ… Decision deposit placed! Hash: {:?}", tx_hash.to_string().bright_yellow()); Ok(()) } @@ -709,7 +710,7 @@ async fn vote_on_referendum( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ—³οΈ Voting on Referendum #{}", index); log_print!(" πŸ“Š Vote: {}", if aye { "AYE βœ…".bright_green() } else { "NAY ❌".bright_red() }); @@ -741,7 +742,8 @@ async fn vote_on_referendum( }; let vote_call = quantus_subxt::api::tx().conviction_voting().vote(index, vote); - let tx_hash = submit_transaction(quantus_client, &keypair, vote_call, None, finalized).await?; + let tx_hash = + submit_transaction(quantus_client, &keypair, vote_call, None, execution_mode).await?; log_print!( "βœ… {} Vote transaction submitted! Hash: {:?}", @@ -799,7 +801,7 @@ async fn refund_submission_deposit( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ’° Refunding submission deposit for Referendum #{}", index); log_print!(" πŸ”‘ Refund to: {}", from.bright_yellow()); @@ -811,7 +813,7 @@ async fn refund_submission_deposit( let refund_call = quantus_subxt::api::tx().referenda().refund_submission_deposit(index); let tx_hash = - submit_transaction(quantus_client, &keypair, refund_call, None, finalized).await?; + submit_transaction(quantus_client, &keypair, refund_call, None, execution_mode).await?; log_print!( "βœ… {} Refund transaction submitted! Hash: {:?}", "SUCCESS".bright_green().bold(), @@ -829,7 +831,7 @@ async fn refund_decision_deposit( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ’° Refunding decision deposit for Referendum #{}", index); log_print!(" πŸ”‘ Refund to: {}", from.bright_yellow()); @@ -841,7 +843,7 @@ async fn refund_decision_deposit( let refund_call = quantus_subxt::api::tx().referenda().refund_decision_deposit(index); let tx_hash = - submit_transaction(quantus_client, &keypair, refund_call, None, finalized).await?; + submit_transaction(quantus_client, &keypair, refund_call, None, execution_mode).await?; log_print!( "βœ… {} Refund transaction submitted! Hash: {:?}", "SUCCESS".bright_green().bold(), diff --git a/src/cli/reversible.rs b/src/cli/reversible.rs index 29b6dd8..63d5ed0 100644 --- a/src/cli/reversible.rs +++ b/src/cli/reversible.rs @@ -111,7 +111,7 @@ pub async fn schedule_transfer( from_keypair: &crate::wallet::QuantumKeyPair, to_address: &str, amount: u128, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> Result { log_verbose!("πŸ”„ Creating reversible transfer..."); log_verbose!(" From: {}", from_keypair.to_account_id_ss58check().bright_cyan()); @@ -141,7 +141,7 @@ pub async fn schedule_transfer( from_keypair, transfer_call, None, - finalized, + execution_mode, ) .await?; @@ -155,7 +155,7 @@ pub async fn cancel_transaction( quantus_client: &crate::chain::client::QuantusClient, from_keypair: &crate::wallet::QuantumKeyPair, tx_id: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> Result { log_verbose!("❌ Cancelling reversible transfer..."); log_verbose!(" Transaction ID: {}", tx_id.bright_yellow()); @@ -176,7 +176,7 @@ pub async fn cancel_transaction( from_keypair, cancel_call, None, - finalized, + execution_mode, ) .await?; @@ -193,7 +193,7 @@ pub async fn schedule_transfer_with_delay( amount: u128, delay: u64, unit_blocks: bool, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> Result { let unit_str = if unit_blocks { "blocks" } else { "seconds" }; log_verbose!("πŸ”„ Creating reversible transfer with custom delay ..."); @@ -233,7 +233,7 @@ pub async fn schedule_transfer_with_delay( from_keypair, transfer_call, None, - finalized, + execution_mode, ) .await?; @@ -246,7 +246,7 @@ pub async fn schedule_transfer_with_delay( pub async fn handle_reversible_command( command: ReversibleCommands, node_url: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> Result<()> { log_print!("πŸ”„ Reversible Transfers"); @@ -286,7 +286,7 @@ pub async fn handle_reversible_command( &keypair, &resolved_address, raw_amount, - finalized, + execution_mode, ) .await?; @@ -310,7 +310,8 @@ pub async fn handle_reversible_command( let keypair = crate::wallet::load_keypair_from_wallet(&from, password, password_file)?; // Submit cancel transaction - let tx_hash = cancel_transaction(&quantus_client, &keypair, &tx_id, finalized).await?; + let tx_hash = + cancel_transaction(&quantus_client, &keypair, &tx_id, execution_mode).await?; log_print!( "βœ… {} Cancel transaction submitted! Hash: {:?}", @@ -360,7 +361,7 @@ pub async fn handle_reversible_command( raw_amount, delay, unit_blocks, - finalized, + execution_mode, ) .await?; diff --git a/src/cli/runtime.rs b/src/cli/runtime.rs index 39db259..08ed810 100644 --- a/src/cli/runtime.rs +++ b/src/cli/runtime.rs @@ -49,7 +49,7 @@ pub async fn update_runtime( wasm_code: Vec, from_keypair: &QuantumKeyPair, force: bool, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result { log_verbose!("πŸ”„ Updating runtime..."); @@ -96,7 +96,7 @@ pub async fn update_runtime( log_print!("πŸ“‘ Submitting runtime update transaction..."); log_print!("⏳ This may take longer than usual due to WASM size..."); - if !finalized { + if !execution_mode.finalized { log_print!( "πŸ’‘ Note: Waiting for best block (not finalized) due to PoW chain characteristics" ); @@ -107,7 +107,7 @@ pub async fn update_runtime( from_keypair, sudo_call, None, - finalized, + execution_mode, ) .await?; @@ -158,7 +158,7 @@ pub async fn calculate_wasm_hash(wasm_code: &[u8]) -> crate::error::Result crate::error::Result<()> { let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?; @@ -195,7 +195,7 @@ pub async fn handle_runtime_command( log_print!("πŸ“Š WASM file size: {} bytes", wasm_code.len()); // Update runtime - update_runtime(&quantus_client, wasm_code, &keypair, force, finalized).await?; + update_runtime(&quantus_client, wasm_code, &keypair, force, execution_mode).await?; log_success!("πŸŽ‰ Runtime update completed!"); log_print!( diff --git a/src/cli/scheduler.rs b/src/cli/scheduler.rs index c1777a9..e89a1cd 100644 --- a/src/cli/scheduler.rs +++ b/src/cli/scheduler.rs @@ -106,7 +106,7 @@ async fn schedule_remark( quantus_client: &crate::chain::client::QuantusClient, after: u32, from: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> Result<()> { use quantus_subxt::api; @@ -133,7 +133,7 @@ async fn schedule_remark( &keypair, schedule_tx, None, - finalized, + execution_mode, ) .await?; log_success!("πŸ“© Schedule extrinsic submitted: {:?}", tx_hash); @@ -145,7 +145,7 @@ async fn schedule_remark( pub async fn handle_scheduler_command( command: SchedulerCommands, node_url: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> Result<()> { log_print!("πŸ—“οΈ Scheduler"); @@ -167,6 +167,6 @@ pub async fn handle_scheduler_command( }, SchedulerCommands::Agenda { range } => list_agenda_range(&quantus_client, &range).await, SchedulerCommands::ScheduleRemark { after, from } => - schedule_remark(&quantus_client, after, &from, finalized).await, + schedule_remark(&quantus_client, after, &from, execution_mode).await, } } diff --git a/src/cli/send.rs b/src/cli/send.rs index 05a9d95..55317c0 100644 --- a/src/cli/send.rs +++ b/src/cli/send.rs @@ -156,9 +156,9 @@ pub async fn transfer( to_address: &str, amount: u128, tip: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> Result { - transfer_with_nonce(quantus_client, from_keypair, to_address, amount, tip, None, finalized) + transfer_with_nonce(quantus_client, from_keypair, to_address, amount, tip, None, execution_mode) .await } @@ -170,7 +170,7 @@ pub async fn transfer_with_nonce( amount: u128, tip: Option, nonce: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> Result { log_verbose!("πŸš€ Creating transfer transaction..."); log_verbose!(" From: {}", from_keypair.to_account_id_ss58check().bright_cyan()); @@ -212,7 +212,7 @@ pub async fn transfer_with_nonce( transfer_call, Some(tip_to_use), manual_nonce, - finalized, + execution_mode, ) .await? } else { @@ -221,7 +221,7 @@ pub async fn transfer_with_nonce( from_keypair, transfer_call, Some(tip_to_use), - finalized, + execution_mode, ) .await? }; @@ -237,7 +237,7 @@ pub async fn batch_transfer( from_keypair: &crate::wallet::QuantumKeyPair, transfers: Vec<(String, u128)>, // (to_address, amount) pairs tip: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> Result { log_verbose!("πŸš€ Creating batch transfer transaction with {} transfers...", transfers.len()); log_verbose!(" From: {}", from_keypair.to_account_id_ss58check().bright_cyan()); @@ -317,7 +317,7 @@ pub async fn batch_transfer( from_keypair, batch_call, Some(tip_to_use), - finalized, + execution_mode, ) .await?; @@ -338,7 +338,7 @@ pub async fn handle_send_command( password_file: Option, tip: Option, nonce: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> Result<()> { // Create quantus chain client let quantus_client = QuantusClient::new(node_url).await?; @@ -397,7 +397,7 @@ pub async fn handle_send_command( amount, tip_amount, nonce, - finalized, + execution_mode, ) .await?; diff --git a/src/cli/storage.rs b/src/cli/storage.rs index 9cf7a62..2ad0ce0 100644 --- a/src/cli/storage.rs +++ b/src/cli/storage.rs @@ -257,7 +257,7 @@ pub async fn set_storage_value( from_keypair: &crate::wallet::QuantumKeyPair, storage_key: Vec, value_bytes: Vec, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result { log_verbose!("✍️ Creating set_storage transaction..."); @@ -275,7 +275,7 @@ pub async fn set_storage_value( from_keypair, sudo_call, None, - finalized, + execution_mode, ) .await?; @@ -805,7 +805,7 @@ async fn get_storage_by_parts( pub async fn handle_storage_command( command: StorageCommands, node_url: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ—„οΈ Storage"); @@ -906,9 +906,14 @@ pub async fn handle_storage_command( }; // 4. Submit the set storage transaction - let tx_hash = - set_storage_value(&quantus_client, &keypair, storage_key, value_bytes, finalized) - .await?; + let tx_hash = set_storage_value( + &quantus_client, + &keypair, + storage_key, + value_bytes, + execution_mode, + ) + .await?; log_print!( "βœ… {} Set storage transaction submitted! Hash: {:?}", diff --git a/src/cli/tech_collective.rs b/src/cli/tech_collective.rs index 9568106..6234b6f 100644 --- a/src/cli/tech_collective.rs +++ b/src/cli/tech_collective.rs @@ -106,7 +106,7 @@ pub async fn add_member( quantus_client: &crate::chain::client::QuantusClient, from_keypair: &crate::wallet::QuantumKeyPair, who_address: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result { log_verbose!("πŸ›οΈ Adding member to Tech Collective..."); log_verbose!(" Member: {}", who_address.bright_cyan()); @@ -136,7 +136,7 @@ pub async fn add_member( from_keypair, sudo_call, None, - finalized, + execution_mode, ) .await?; @@ -150,7 +150,7 @@ pub async fn remove_member( quantus_client: &crate::chain::client::QuantusClient, from_keypair: &crate::wallet::QuantumKeyPair, who_address: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result { log_verbose!("πŸ›οΈ Removing member from Tech Collective..."); log_verbose!(" Member: {}", who_address.bright_cyan()); @@ -181,7 +181,7 @@ pub async fn remove_member( from_keypair, sudo_call, None, - finalized, + execution_mode, ) .await?; @@ -196,7 +196,7 @@ pub async fn vote_on_referendum( from_keypair: &crate::wallet::QuantumKeyPair, referendum_index: u32, aye: bool, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result { log_verbose!("πŸ—³οΈ Voting on referendum..."); log_verbose!(" Referendum: {}", referendum_index); @@ -212,7 +212,7 @@ pub async fn vote_on_referendum( from_keypair, vote_call, None, - finalized, + execution_mode, ) .await?; @@ -352,7 +352,7 @@ pub async fn get_sudo_account( pub async fn handle_tech_collective_command( command: TechCollectiveCommands, node_url: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ›οΈ Tech Collective"); @@ -368,7 +368,7 @@ pub async fn handle_tech_collective_command( let keypair = crate::wallet::load_keypair_from_wallet(&from, password, password_file)?; // Submit transaction - let tx_hash = add_member(&quantus_client, &keypair, &who, finalized).await?; + let tx_hash = add_member(&quantus_client, &keypair, &who, execution_mode).await?; log_print!( "βœ… {} Add member transaction submitted! Hash: {:?}", @@ -386,7 +386,7 @@ pub async fn handle_tech_collective_command( let keypair = crate::wallet::load_keypair_from_wallet(&from, password, password_file)?; // Submit transaction - let tx_hash = remove_member(&quantus_client, &keypair, &who, finalized).await?; + let tx_hash = remove_member(&quantus_client, &keypair, &who, execution_mode).await?; log_print!( "βœ… {} Remove member transaction submitted! Hash: {:?}", @@ -407,9 +407,14 @@ pub async fn handle_tech_collective_command( let keypair = crate::wallet::load_keypair_from_wallet(&from, password, password_file)?; // Submit transaction - let tx_hash = - vote_on_referendum(&quantus_client, &keypair, referendum_index, aye, finalized) - .await?; + let tx_hash = vote_on_referendum( + &quantus_client, + &keypair, + referendum_index, + aye, + execution_mode, + ) + .await?; log_print!( "βœ… {} Vote transaction submitted! Hash: {:?}", diff --git a/src/cli/tech_referenda.rs b/src/cli/tech_referenda.rs index 682bc2d..6fc8860 100644 --- a/src/cli/tech_referenda.rs +++ b/src/cli/tech_referenda.rs @@ -187,7 +187,7 @@ pub enum TechReferendaCommands { pub async fn handle_tech_referenda_command( command: TechReferendaCommands, node_url: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?; @@ -199,7 +199,7 @@ pub async fn handle_tech_referenda_command( &from, password, password_file, - finalized, + execution_mode, ) .await, TechReferendaCommands::SubmitWithPreimage { wasm_file, from, password, password_file } => @@ -209,7 +209,7 @@ pub async fn handle_tech_referenda_command( &from, password, password_file, - finalized, + execution_mode, ) .await, TechReferendaCommands::List => list_proposals(&quantus_client).await, @@ -223,15 +223,18 @@ pub async fn handle_tech_referenda_command( &from, password, password_file, - finalized, + execution_mode, ) .await, TechReferendaCommands::Cancel { index, from, password, password_file } => - cancel_proposal(&quantus_client, index, &from, password, password_file, finalized).await, + cancel_proposal(&quantus_client, index, &from, password, password_file, execution_mode) + .await, TechReferendaCommands::Kill { index, from, password, password_file } => - kill_proposal(&quantus_client, index, &from, password, password_file, finalized).await, + kill_proposal(&quantus_client, index, &from, password, password_file, execution_mode) + .await, TechReferendaCommands::Nudge { index, from, password, password_file } => - nudge_proposal(&quantus_client, index, &from, password, password_file, finalized).await, + nudge_proposal(&quantus_client, index, &from, password, password_file, execution_mode) + .await, TechReferendaCommands::RefundSubmissionDeposit { index, from, password, password_file } => refund_submission_deposit( &quantus_client, @@ -239,7 +242,7 @@ pub async fn handle_tech_referenda_command( &from, password, password_file, - finalized, + execution_mode, ) .await, TechReferendaCommands::RefundDecisionDeposit { index, from, password, password_file } => @@ -249,7 +252,7 @@ pub async fn handle_tech_referenda_command( &from, password, password_file, - finalized, + execution_mode, ) .await, TechReferendaCommands::Config => get_config(&quantus_client).await, @@ -263,7 +266,7 @@ async fn submit_runtime_upgrade( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ“ Submitting Runtime Upgrade Proposal to Tech Referenda"); log_print!(" πŸ”— Preimage hash: {}", preimage_hash.bright_cyan()); @@ -337,7 +340,7 @@ async fn submit_runtime_upgrade( .submit(origin_caller, proposal, enactment); let tx_hash = - submit_transaction(quantus_client, &keypair, submit_call, None, finalized).await?; + submit_transaction(quantus_client, &keypair, submit_call, None, execution_mode).await?; log_print!( "βœ… {} Runtime upgrade proposal submitted! Hash: {:?}", "SUCCESS".bright_green().bold(), @@ -355,7 +358,7 @@ async fn submit_runtime_upgrade_with_preimage( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { use qp_poseidon::PoseidonHasher; @@ -403,7 +406,8 @@ async fn submit_runtime_upgrade_with_preimage( log_print!("πŸ“ Submitting preimage..."); let note_preimage_tx = quantus_subxt::api::tx().preimage().note_preimage(bounded_bytes); let preimage_tx_hash = - submit_transaction(quantus_client, &keypair, note_preimage_tx, None, finalized).await?; + submit_transaction(quantus_client, &keypair, note_preimage_tx, None, execution_mode) + .await?; log_print!("βœ… Preimage transaction submitted: {:?}", preimage_tx_hash); // Wait for preimage transaction confirmation @@ -437,7 +441,7 @@ async fn submit_runtime_upgrade_with_preimage( .submit(origin_caller, proposal, enactment); let tx_hash = - submit_transaction(quantus_client, &keypair, submit_call, None, finalized).await?; + submit_transaction(quantus_client, &keypair, submit_call, None, execution_mode).await?; log_print!( "βœ… {} Runtime upgrade proposal submitted! Hash: {:?}", "SUCCESS".bright_green().bold(), @@ -574,7 +578,7 @@ async fn place_decision_deposit( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ“‹ Placing decision deposit for Tech Referendum #{}", index); log_print!(" πŸ”‘ Placed by: {}", from.bright_yellow()); @@ -583,7 +587,7 @@ async fn place_decision_deposit( let deposit_call = quantus_subxt::api::tx().tech_referenda().place_decision_deposit(index); let tx_hash = - submit_transaction(quantus_client, &keypair, deposit_call, None, finalized).await?; + submit_transaction(quantus_client, &keypair, deposit_call, None, execution_mode).await?; log_success!("βœ… Decision deposit placed! Hash: {:?}", tx_hash.to_string().bright_yellow()); Ok(()) } @@ -595,7 +599,7 @@ async fn cancel_proposal( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("❌ Cancelling Tech Referendum #{}", index); log_print!(" πŸ”‘ Cancelled by: {}", from.bright_yellow()); @@ -608,7 +612,8 @@ async fn cancel_proposal( }); let sudo_call = quantus_subxt::api::tx().sudo().sudo(inner); - let tx_hash = submit_transaction(quantus_client, &keypair, sudo_call, None, finalized).await?; + let tx_hash = + submit_transaction(quantus_client, &keypair, sudo_call, None, execution_mode).await?; log_success!("βœ… Referendum cancelled! Hash: {:?}", tx_hash.to_string().bright_yellow()); Ok(()) } @@ -620,7 +625,7 @@ async fn kill_proposal( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ’€ Killing Tech Referendum #{}", index); log_print!(" πŸ”‘ Killed by: {}", from.bright_yellow()); @@ -633,7 +638,8 @@ async fn kill_proposal( }); let sudo_call = quantus_subxt::api::tx().sudo().sudo(inner); - let tx_hash = submit_transaction(quantus_client, &keypair, sudo_call, None, finalized).await?; + let tx_hash = + submit_transaction(quantus_client, &keypair, sudo_call, None, execution_mode).await?; log_success!("βœ… Referendum killed! Hash: {:?}", tx_hash.to_string().bright_yellow()); Ok(()) } @@ -645,7 +651,7 @@ async fn nudge_proposal( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ”„ Nudging Tech Referendum #{}", index); log_print!(" πŸ”‘ Nudged by: {}", from.bright_yellow()); @@ -657,7 +663,8 @@ async fn nudge_proposal( ); let sudo_call = quantus_subxt::api::tx().sudo().sudo(inner); - let tx_hash = submit_transaction(quantus_client, &keypair, sudo_call, None, finalized).await?; + let tx_hash = + submit_transaction(quantus_client, &keypair, sudo_call, None, execution_mode).await?; log_success!("βœ… Referendum nudged! Hash: {:?}", tx_hash.to_string().bright_yellow()); Ok(()) } @@ -708,7 +715,7 @@ async fn refund_submission_deposit( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ’° Refunding submission deposit for Tech Referendum #{}", index); log_print!(" πŸ”‘ Refund to: {}", from.bright_yellow()); @@ -720,7 +727,7 @@ async fn refund_submission_deposit( let refund_call = quantus_subxt::api::tx().tech_referenda().refund_submission_deposit(index); let tx_hash = - submit_transaction(quantus_client, &keypair, refund_call, None, finalized).await?; + submit_transaction(quantus_client, &keypair, refund_call, None, execution_mode).await?; log_print!( "βœ… {} Refund transaction submitted! Hash: {:?}", "SUCCESS".bright_green().bold(), @@ -739,7 +746,7 @@ async fn refund_decision_deposit( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ’° Refunding decision deposit for Tech Referendum #{}", index); log_print!(" πŸ”‘ Refund to: {}", from.bright_yellow()); @@ -751,7 +758,7 @@ async fn refund_decision_deposit( let refund_call = quantus_subxt::api::tx().tech_referenda().refund_decision_deposit(index); let tx_hash = - submit_transaction(quantus_client, &keypair, refund_call, None, finalized).await?; + submit_transaction(quantus_client, &keypair, refund_call, None, execution_mode).await?; log_print!( "βœ… {} Refund transaction submitted! Hash: {:?}", "SUCCESS".bright_green().bold(), diff --git a/src/cli/treasury.rs b/src/cli/treasury.rs index 5306148..e910bea 100644 --- a/src/cli/treasury.rs +++ b/src/cli/treasury.rs @@ -117,7 +117,7 @@ pub enum TreasuryCommands { pub async fn handle_treasury_command( command: TreasuryCommands, node_url: &str, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?; @@ -141,14 +141,22 @@ pub async fn handle_treasury_command( &from, password, password_file, - finalized, + execution_mode, ) .await, TreasuryCommands::Payout { index, from, password, password_file } => - payout_spend(&quantus_client, index, &from, password, password_file, finalized).await, - TreasuryCommands::CheckStatus { index, from, password, password_file } => - check_spend_status(&quantus_client, index, &from, password, password_file, finalized) + payout_spend(&quantus_client, index, &from, password, password_file, execution_mode) .await, + TreasuryCommands::CheckStatus { index, from, password, password_file } => + check_spend_status( + &quantus_client, + index, + &from, + password, + password_file, + execution_mode, + ) + .await, TreasuryCommands::ListSpends => list_spends(&quantus_client).await, TreasuryCommands::SpendSudo { beneficiary, amount, from, password, password_file } => spend_sudo( @@ -158,7 +166,7 @@ pub async fn handle_treasury_command( &from, password, password_file, - finalized, + execution_mode, ) .await, } @@ -303,7 +311,7 @@ async fn submit_spend_referendum( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { use qp_poseidon::PoseidonHasher; use sp_core::crypto::{AccountId32 as SpAccountId32, Ss58Codec}; @@ -358,7 +366,7 @@ async fn submit_spend_referendum( // Submit preimage let preimage_call = quantus_subxt::api::tx().preimage().note_preimage(encoded_call.clone()); let preimage_tx_hash = - submit_transaction(quantus_client, &keypair, preimage_call, None, finalized).await?; + submit_transaction(quantus_client, &keypair, preimage_call, None, execution_mode).await?; log_print!("βœ… Preimage created {:?}", preimage_tx_hash); @@ -401,7 +409,7 @@ async fn submit_spend_referendum( let submit_call = quantus_subxt::api::tx().referenda().submit(origin_caller, proposal, enactment); let submit_tx_hash = - submit_transaction(quantus_client, &keypair, submit_call, None, finalized).await?; + submit_transaction(quantus_client, &keypair, submit_call, None, execution_mode).await?; log_print!( "βœ… {} Treasury spend referendum submitted! {:?}", @@ -428,7 +436,7 @@ async fn payout_spend( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ’Έ Paying out Treasury Spend #{}", index); @@ -439,7 +447,7 @@ async fn payout_spend( let payout_call = quantus_subxt::api::tx().treasury_pallet().payout(index); let tx_hash = - submit_transaction(quantus_client, &keypair, payout_call, None, finalized).await?; + submit_transaction(quantus_client, &keypair, payout_call, None, execution_mode).await?; log_print!( "βœ… {} Payout transaction submitted! Hash: {:?}", "SUCCESS".bright_green().bold(), @@ -459,7 +467,7 @@ async fn check_spend_status( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("πŸ” Checking Treasury Spend #{} status", index); @@ -469,7 +477,8 @@ async fn check_spend_status( // Create check_status call let check_call = quantus_subxt::api::tx().treasury_pallet().check_status(index); - let tx_hash = submit_transaction(quantus_client, &keypair, check_call, None, finalized).await?; + let tx_hash = + submit_transaction(quantus_client, &keypair, check_call, None, execution_mode).await?; log_print!( "βœ… {} Check status transaction submitted! Hash: {:?}", "SUCCESS".bright_green().bold(), @@ -538,7 +547,7 @@ async fn spend_sudo( from: &str, password: Option, password_file: Option, - finalized: bool, + execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { use sp_core::crypto::{AccountId32 as SpAccountId32, Ss58Codec}; @@ -580,7 +589,8 @@ async fn spend_sudo( // Submit transaction log_print!("πŸ“‘ Submitting sudo transaction..."); - let tx_hash = submit_transaction(quantus_client, &keypair, sudo_call, None, finalized).await?; + let tx_hash = + submit_transaction(quantus_client, &keypair, sudo_call, None, execution_mode).await?; log_print!( "βœ… {} Sudo transaction submitted! Hash: {:?}", "SUCCESS".bright_green().bold(), diff --git a/src/main.rs b/src/main.rs index 7367aca..2bf667a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -40,6 +40,11 @@ struct Cli { /// NOTE: waiting for finalized transaction may take a while in PoW chain #[arg(long, global = true, default_value = "false")] finalized_tx: bool, + + /// Wait for transaction validation/inclusion before returning + /// Default: false + #[arg(long, global = true, default_value = "false")] + wait_for_transaction: bool, } #[tokio::main] @@ -60,8 +65,14 @@ async fn main() -> Result<(), QuantusError> { log_print!("⚠️ Warning: Waiting for finalized block may take a while in PoW chain."); } + // Create execution mode from CLI args + let execution_mode = cli::common::ExecutionMode { + finalized: cli.finalized_tx, + wait_for_transaction: cli.wait_for_transaction, + }; + // Execute the command - match cli::execute_command(cli.command, &cli.node_url, cli.verbose, cli.finalized_tx).await { + match cli::execute_command(cli.command, &cli.node_url, cli.verbose, execution_mode).await { Ok(_) => { log_verbose!(""); log_verbose!("Command executed successfully!");