From c0220688eb2054645ee9460848eb4db8f78dd4dc Mon Sep 17 00:00:00 2001 From: Cezary Olborski Date: Tue, 3 Mar 2026 09:56:26 +0800 Subject: [PATCH 1/8] feat: Referenda commands restored --- src/cli/mod.rs | 22 +- src/cli/referenda.rs | 855 ++++++++++++++++++++++++++++++++++++ src/cli/referenda_decode.rs | 243 ++++++++++ src/cli/tech_referenda.rs | 771 ++++++++++++++++++++++++++++++++ src/config/mod.rs | 2 +- src/quantus_metadata.scale | Bin 163412 -> 163412 bytes 6 files changed, 1891 insertions(+), 2 deletions(-) create mode 100644 src/cli/referenda.rs create mode 100644 src/cli/referenda_decode.rs create mode 100644 src/cli/tech_referenda.rs diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 2d3e436..68bbdbb 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -14,6 +14,8 @@ pub mod multisend; pub mod multisig; pub mod preimage; pub mod recovery; +pub mod referenda; +pub mod referenda_decode; pub mod reversible; pub mod runtime; pub mod scheduler; @@ -21,6 +23,7 @@ pub mod send; pub mod storage; pub mod system; pub mod tech_collective; +pub mod tech_referenda; pub mod transfers; pub mod treasury; pub mod wallet; @@ -96,10 +99,18 @@ pub enum Commands { #[command(subcommand)] TechCollective(tech_collective::TechCollectiveCommands), - /// Tech Referenda management commands (for runtime upgrade proposals) + /// Preimage management commands #[command(subcommand)] Preimage(preimage::PreimageCommands), + /// Tech Referenda management commands (for runtime upgrade proposals) + #[command(subcommand)] + TechReferenda(tech_referenda::TechReferendaCommands), + + /// Standard Referenda management commands (public governance) + #[command(subcommand)] + Referenda(referenda::ReferendaCommands), + /// Treasury account info #[command(subcommand)] Treasury(treasury::TreasuryCommands), @@ -353,6 +364,15 @@ pub async fn execute_command( .await, Commands::Preimage(preimage_cmd) => 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, + execution_mode, + ) + .await, + Commands::Referenda(referenda_cmd) => + referenda::handle_referenda_command(referenda_cmd, node_url, execution_mode).await, Commands::Treasury(treasury_cmd) => treasury::handle_treasury_command(treasury_cmd, node_url, execution_mode).await, Commands::Transfers(transfers_cmd) => diff --git a/src/cli/referenda.rs b/src/cli/referenda.rs new file mode 100644 index 0000000..04f4416 --- /dev/null +++ b/src/cli/referenda.rs @@ -0,0 +1,855 @@ +//! `quantus referenda` subcommand - manage standard Referenda proposals +use crate::{ + chain::quantus_subxt, cli::common::submit_transaction, error::QuantusError, log_error, + log_print, log_success, log_verbose, +}; +use clap::Subcommand; +use colored::Colorize; +use std::str::FromStr; + +/// Standard Referenda management commands +#[derive(Subcommand, Debug)] +pub enum ReferendaCommands { + /// Submit a simple proposal (System::remark) to test Referenda + SubmitRemark { + /// Message to include in the remark + #[arg(long)] + message: String, + + /// Wallet name to sign with + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + + /// Origin type: signed (default), none (for signaling track), root + #[arg(long, default_value = "signed")] + origin: String, + }, + + /// Submit a proposal using existing preimage hash + Submit { + /// Preimage hash (must already exist on chain) + #[arg(long)] + preimage_hash: String, + + /// Wallet name to sign with + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + + /// Origin type: signed (default), none (for signaling track), root + #[arg(long, default_value = "signed")] + origin: String, + }, + + /// List all active Referenda proposals + List, + + /// Get details of a specific Referendum + Get { + /// Referendum index + #[arg(short, long)] + index: u32, + + /// Decode and display the proposal call in human-readable format + #[arg(long)] + decode: bool, + }, + + /// Check the status of a Referendum + Status { + /// Referendum index + #[arg(short, long)] + index: u32, + }, + + /// Place a decision deposit for a Referendum + PlaceDecisionDeposit { + /// Referendum index + #[arg(short, long)] + index: u32, + + /// Wallet name to sign with + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + }, + + /// Vote on a Referendum (uses conviction voting) + Vote { + /// Referendum index + #[arg(short, long)] + index: u32, + + /// Vote aye (true) or nay (false) + #[arg(long)] + aye: bool, + + /// Conviction (0=None, 1=Locked1x, 2=Locked2x, up to 6=Locked6x) + #[arg(long, default_value = "0")] + conviction: u8, + + /// Amount to vote with + #[arg(long)] + amount: String, + + /// Wallet name to sign with + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + }, + + /// Refund submission deposit for a completed Referendum + RefundSubmissionDeposit { + /// Referendum index + #[arg(short, long)] + index: u32, + + /// Wallet name that submitted the referendum + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + }, + + /// Refund decision deposit for a completed Referendum + RefundDecisionDeposit { + /// Referendum index + #[arg(short, long)] + index: u32, + + /// Wallet name that placed the decision deposit + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + }, + + /// Get Referenda configuration + Config, +} + +/// Handle referenda commands +pub async fn handle_referenda_command( + command: ReferendaCommands, + node_url: &str, + execution_mode: crate::cli::common::ExecutionMode, +) -> crate::error::Result<()> { + let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?; + + match command { + ReferendaCommands::SubmitRemark { message, from, password, password_file, origin } => + submit_remark_proposal( + &quantus_client, + &message, + &from, + password, + password_file, + &origin, + execution_mode, + ) + .await, + ReferendaCommands::Submit { preimage_hash, from, password, password_file, origin } => + submit_proposal( + &quantus_client, + &preimage_hash, + &from, + password, + password_file, + &origin, + execution_mode, + ) + .await, + ReferendaCommands::List => list_proposals(&quantus_client).await, + ReferendaCommands::Get { index, decode } => + get_proposal_details(&quantus_client, index, decode).await, + ReferendaCommands::Status { index } => get_proposal_status(&quantus_client, index).await, + ReferendaCommands::PlaceDecisionDeposit { index, from, password, password_file } => + place_decision_deposit( + &quantus_client, + index, + &from, + password, + password_file, + execution_mode, + ) + .await, + ReferendaCommands::Vote { + index, + aye, + conviction, + amount, + from, + password, + password_file, + } => + vote_on_referendum( + &quantus_client, + index, + aye, + conviction, + &amount, + &from, + password, + password_file, + execution_mode, + ) + .await, + ReferendaCommands::RefundSubmissionDeposit { index, from, password, password_file } => + refund_submission_deposit( + &quantus_client, + index, + &from, + password, + password_file, + execution_mode, + ) + .await, + ReferendaCommands::RefundDecisionDeposit { index, from, password, password_file } => + refund_decision_deposit( + &quantus_client, + index, + &from, + password, + password_file, + execution_mode, + ) + .await, + ReferendaCommands::Config => get_config(&quantus_client).await, + } +} + +/// Submit a simple System::remark proposal +async fn submit_remark_proposal( + quantus_client: &crate::chain::client::QuantusClient, + message: &str, + from: &str, + password: Option, + password_file: Option, + origin_type: &str, + execution_mode: crate::cli::common::ExecutionMode, +) -> crate::error::Result<()> { + use qp_poseidon::PoseidonHasher; + + log_print!("📝 Submitting System::remark Proposal to Referenda"); + log_print!(" đŸ’Ŧ Message: {}", message.bright_cyan()); + log_print!(" 🔑 Submitted by: {}", from.bright_yellow()); + log_print!(" đŸŽ¯ Origin type: {}", origin_type.bright_magenta()); + + // Load wallet keypair + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + // Build System::remark call and encode it + let remark_bytes = message.as_bytes().to_vec(); + let remark_payload = quantus_subxt::api::tx().system().remark(remark_bytes.clone()); + let metadata = quantus_client.client().metadata(); + let encoded_call = <_ as subxt::tx::Payload>::encode_call_data(&remark_payload, &metadata) + .map_err(|e| QuantusError::Generic(format!("Failed to encode call data: {:?}", e)))?; + + log_verbose!("📝 Encoded call size: {} bytes", encoded_call.len()); + + // Compute preimage hash using Poseidon + let preimage_hash: sp_core::H256 = + ::hash(&encoded_call); + + log_print!("🔗 Preimage hash: {:?}", preimage_hash); + + // Submit Preimage::note_preimage + type PreimageBytes = quantus_subxt::api::preimage::calls::types::note_preimage::Bytes; + let bounded_bytes: PreimageBytes = encoded_call.clone(); + + 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, execution_mode) + .await?; + log_print!("✅ Preimage transaction submitted: {:?}", preimage_tx_hash); + + // Wait for preimage transaction confirmation + log_print!("âŗ Waiting for preimage transaction confirmation..."); + + // Build Referenda::submit call using Lookup preimage reference + type ProposalBounded = + quantus_subxt::api::runtime_types::frame_support::traits::preimages::Bounded< + quantus_subxt::api::runtime_types::quantus_runtime::RuntimeCall, + quantus_subxt::api::runtime_types::qp_poseidon::PoseidonHasher, + >; + + let preimage_hash_subxt: subxt::utils::H256 = preimage_hash; + let proposal: ProposalBounded = + ProposalBounded::Lookup { hash: preimage_hash_subxt, len: encoded_call.len() as u32 }; + + // Create origin based on origin_type parameter + let account_id_sp = keypair.to_account_id_32(); + let account_id_subxt: subxt::ext::subxt_core::utils::AccountId32 = + subxt::ext::subxt_core::utils::AccountId32(*account_id_sp.as_ref()); + + let origin_caller = match origin_type.to_lowercase().as_str() { + "signed" => { + let raw_origin = + quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::Signed( + account_id_subxt, + ); + quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin) + }, + "none" => { + let raw_origin = + quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::None; + quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin) + }, + "root" => { + let raw_origin = + quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::Root; + quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin) + }, + _ => + return Err(QuantusError::Generic(format!( + "Invalid origin type: {}. Must be 'signed', 'none', or 'root'", + origin_type + ))), + }; + + let enactment = + quantus_subxt::api::runtime_types::frame_support::traits::schedule::DispatchTime::After( + 10u32, // Execute 10 blocks after approval + ); + + log_print!("🔧 Creating Referenda::submit call..."); + let submit_call = + quantus_subxt::api::tx().referenda().submit(origin_caller, proposal, enactment); + + let tx_hash = + submit_transaction(quantus_client, &keypair, submit_call, None, execution_mode).await?; + log_print!( + "✅ {} Referendum proposal submitted! Hash: {:?}", + "SUCCESS".bright_green().bold(), + tx_hash + ); + + log_print!("💡 Use 'quantus referenda list' to see active proposals"); + Ok(()) +} + +/// Submit a proposal using existing preimage hash +async fn submit_proposal( + quantus_client: &crate::chain::client::QuantusClient, + preimage_hash: &str, + from: &str, + password: Option, + password_file: Option, + origin_type: &str, + execution_mode: crate::cli::common::ExecutionMode, +) -> crate::error::Result<()> { + log_print!("📝 Submitting Proposal to Referenda"); + log_print!(" 🔗 Preimage hash: {}", preimage_hash.bright_cyan()); + log_print!(" 🔑 Submitted by: {}", from.bright_yellow()); + log_print!(" đŸŽ¯ Origin type: {}", origin_type.bright_magenta()); + + // Parse preimage hash + let hash_str = preimage_hash.trim_start_matches("0x"); + let preimage_hash_parsed: sp_core::H256 = sp_core::H256::from_str(hash_str) + .map_err(|_| QuantusError::Generic("Invalid preimage hash format".to_string()))?; + + // Load wallet keypair + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + // Check if preimage exists and get its length + log_print!("🔍 Checking preimage status..."); + let latest_block_hash = quantus_client.get_latest_block().await?; + let storage_at = quantus_client.client().storage().at(latest_block_hash); + + let preimage_status = storage_at + .fetch( + &quantus_subxt::api::storage() + .preimage() + .request_status_for(preimage_hash_parsed), + ) + .await + .map_err(|e| QuantusError::Generic(format!("Failed to fetch preimage status: {:?}", e)))? + .ok_or_else(|| QuantusError::Generic("Preimage not found on chain".to_string()))?; + + let preimage_len = match preimage_status { + quantus_subxt::api::runtime_types::pallet_preimage::RequestStatus::Unrequested { + ticket: _, + len, + } => len, + quantus_subxt::api::runtime_types::pallet_preimage::RequestStatus::Requested { + maybe_ticket: _, + count: _, + maybe_len, + } => match maybe_len { + Some(len) => len, + None => return Err(QuantusError::Generic("Preimage length not available".to_string())), + }, + }; + + log_print!("✅ Preimage found! Length: {} bytes", preimage_len); + + // Build Referenda::submit call + type ProposalBounded = + quantus_subxt::api::runtime_types::frame_support::traits::preimages::Bounded< + quantus_subxt::api::runtime_types::quantus_runtime::RuntimeCall, + quantus_subxt::api::runtime_types::qp_poseidon::PoseidonHasher, + >; + + let preimage_hash_subxt: subxt::utils::H256 = preimage_hash_parsed; + let proposal: ProposalBounded = + ProposalBounded::Lookup { hash: preimage_hash_subxt, len: preimage_len }; + + // Create origin based on origin_type parameter + let account_id_sp = keypair.to_account_id_32(); + let account_id_subxt: subxt::ext::subxt_core::utils::AccountId32 = + subxt::ext::subxt_core::utils::AccountId32(*account_id_sp.as_ref()); + + let origin_caller = match origin_type.to_lowercase().as_str() { + "signed" => { + let raw_origin = + quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::Signed( + account_id_subxt, + ); + quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin) + }, + "none" => { + let raw_origin = + quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::None; + quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin) + }, + "root" => { + let raw_origin = + quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::Root; + quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin) + }, + _ => + return Err(QuantusError::Generic(format!( + "Invalid origin type: {}. Must be 'signed', 'none', or 'root'", + origin_type + ))), + }; + + let enactment = + quantus_subxt::api::runtime_types::frame_support::traits::schedule::DispatchTime::After( + 10u32, + ); + + log_print!("🔧 Creating Referenda::submit call..."); + let submit_call = + quantus_subxt::api::tx().referenda().submit(origin_caller, proposal, enactment); + + let tx_hash = + submit_transaction(quantus_client, &keypair, submit_call, None, execution_mode).await?; + log_print!( + "✅ {} Referendum proposal submitted! Hash: {:?}", + "SUCCESS".bright_green().bold(), + tx_hash + ); + + log_print!("💡 Use 'quantus referenda list' to see active proposals"); + Ok(()) +} + +/// List recent Referenda proposals +async fn list_proposals( + quantus_client: &crate::chain::client::QuantusClient, +) -> crate::error::Result<()> { + log_print!("📜 Active Referenda Proposals"); + log_print!(""); + + let addr = quantus_subxt::api::storage().referenda().referendum_count(); + + let latest_block_hash = quantus_client.get_latest_block().await?; + let storage_at = quantus_client.client().storage().at(latest_block_hash); + + let count = storage_at.fetch(&addr).await?; + + if let Some(total) = count { + log_print!("📊 Total referenda created: {}", total); + if total == 0 { + log_print!("📭 No active proposals found"); + return Ok(()); + } + log_print!("🔍 Fetching recent referenda..."); + for i in (0..total).rev().take(10) { + get_proposal_status(quantus_client, i).await?; + log_print!("----------------------------------------"); + } + } else { + log_print!("📭 No referenda found - Referenda may be empty"); + } + + Ok(()) +} + +/// Get details of a specific Referendum +async fn get_proposal_details( + quantus_client: &crate::chain::client::QuantusClient, + index: u32, + decode: bool, +) -> crate::error::Result<()> { + use quantus_subxt::api::runtime_types::pallet_referenda::types::ReferendumInfo; + + log_print!("📄 Referendum #{} Details", index); + log_print!(""); + + let addr = quantus_subxt::api::storage().referenda().referendum_info_for(index); + + let latest_block_hash = quantus_client.get_latest_block().await?; + let storage_at = quantus_client.client().storage().at(latest_block_hash); + + let info = storage_at.fetch(&addr).await?; + + if let Some(referendum_info) = info { + if decode { + // Try to decode the proposal + match &referendum_info { + ReferendumInfo::Ongoing(status) => { + log_print!("📊 {} Referendum #{}", "Ongoing".bright_green(), index); + log_print!(" đŸ›¤ī¸ Track: {}", status.track); + log_print!(" 📅 Submitted: Block #{}", status.submitted); + log_print!( + " đŸ—ŗī¸ Tally: Ayes: {}, Nays: {}, Support: {}", + status.tally.ayes, + status.tally.nays, + status.tally.support + ); + log_print!(""); + + // Extract preimage hash and length from proposal + if let quantus_subxt::api::runtime_types::frame_support::traits::preimages::Bounded::Lookup { + hash, + len, + } = &status.proposal + { + log_print!("📝 Proposal Details:"); + log_print!(" 🔗 Preimage Hash: {:?}", hash); + log_print!(" 📏 Length: {} bytes", len); + log_print!(""); + + // Fetch and decode the preimage + match crate::cli::referenda_decode::decode_preimage(quantus_client, hash, *len).await { + Ok(decoded) => { + log_print!("✅ Decoded Proposal:"); + log_print!("{}", decoded); + }, + Err(e) => { + log_print!("âš ī¸ Could not decode proposal: {}", e); + log_print!(" Run 'quantus preimage get --hash {:?} --len {}' to see raw data", hash, len); + }, + } + } else { + log_print!("âš ī¸ Proposal is inline (not a preimage lookup)"); + } + }, + ReferendumInfo::Approved(..) => { + log_print!("📊 {} Referendum #{}", "Approved".green(), index); + log_print!( + " â„šī¸ Proposal details no longer available (referendum finalized)" + ); + }, + ReferendumInfo::Rejected(..) => { + log_print!("📊 {} Referendum #{}", "Rejected".red(), index); + log_print!( + " â„šī¸ Proposal details no longer available (referendum finalized)" + ); + }, + ReferendumInfo::Cancelled(..) => { + log_print!("📊 {} Referendum #{}", "Cancelled".yellow(), index); + log_print!( + " â„šī¸ Proposal details no longer available (referendum finalized)" + ); + }, + ReferendumInfo::TimedOut(..) => { + log_print!("📊 {} Referendum #{}", "TimedOut".dimmed(), index); + log_print!( + " â„šī¸ Proposal details no longer available (referendum finalized)" + ); + }, + ReferendumInfo::Killed(..) => { + log_print!("📊 {} Referendum #{}", "Killed".red().bold(), index); + log_print!(" â„šī¸ Proposal details no longer available (referendum killed)"); + }, + } + } else { + // Raw output (original behavior) + log_print!("📋 Referendum Information (raw):"); + log_print!("{:#?}", referendum_info); + } + } else { + log_print!("📭 Referendum #{} not found", index); + } + Ok(()) +} + +/// Get the status of a Referendum +async fn get_proposal_status( + quantus_client: &crate::chain::client::QuantusClient, + index: u32, +) -> crate::error::Result<()> { + use quantus_subxt::api::runtime_types::pallet_referenda::types::ReferendumInfo; + + log_verbose!("📊 Fetching status for Referendum #{}...", index); + + let addr = quantus_subxt::api::storage().referenda().referendum_info_for(index); + + let latest_block_hash = quantus_client.get_latest_block().await?; + let storage_at = quantus_client.client().storage().at(latest_block_hash); + + let info_res = storage_at.fetch(&addr).await; + + match info_res { + Ok(Some(info)) => { + log_print!("📊 Status for Referendum #{}", index.to_string().bright_yellow()); + match info { + ReferendumInfo::Ongoing(status) => { + log_print!(" - Status: {}", "Ongoing".bright_green()); + log_print!(" - Track: {}", status.track); + log_print!(" - Submitted at: block {}", status.submitted); + log_print!( + " - Tally: Ayes: {}, Nays: {}", + status.tally.ayes, + status.tally.nays + ); + log_verbose!(" - Full status: {:#?}", status); + }, + ReferendumInfo::Approved(submitted, ..) => { + log_print!(" - Status: {}", "Approved".green()); + log_print!(" - Submitted at block: {}", submitted); + }, + ReferendumInfo::Rejected(submitted, ..) => { + log_print!(" - Status: {}", "Rejected".red()); + log_print!(" - Submitted at block: {}", submitted); + }, + ReferendumInfo::Cancelled(submitted, ..) => { + log_print!(" - Status: {}", "Cancelled".yellow()); + log_print!(" - Submitted at block: {}", submitted); + }, + ReferendumInfo::TimedOut(submitted, ..) => { + log_print!(" - Status: {}", "TimedOut".dimmed()); + log_print!(" - Submitted at block: {}", submitted); + }, + ReferendumInfo::Killed(submitted) => { + log_print!(" - Status: {}", "Killed".red().bold()); + log_print!(" - Killed at block: {}", submitted); + }, + } + }, + Ok(None) => log_print!("📭 Referendum #{} not found", index), + Err(e) => log_error!("❌ Failed to fetch referendum #{}: {:?}", index, e), + } + + Ok(()) +} + +/// Place a decision deposit for a Referendum +async fn place_decision_deposit( + quantus_client: &crate::chain::client::QuantusClient, + index: u32, + from: &str, + password: Option, + password_file: Option, + execution_mode: crate::cli::common::ExecutionMode, +) -> crate::error::Result<()> { + log_print!("📋 Placing decision deposit for Referendum #{}", index); + log_print!(" 🔑 Placed by: {}", from.bright_yellow()); + + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + let deposit_call = quantus_subxt::api::tx().referenda().place_decision_deposit(index); + let tx_hash = + submit_transaction(quantus_client, &keypair, deposit_call, None, execution_mode).await?; + log_success!("✅ Decision deposit placed! Hash: {:?}", tx_hash.to_string().bright_yellow()); + Ok(()) +} + +/// Vote on a Referendum +async fn vote_on_referendum( + quantus_client: &crate::chain::client::QuantusClient, + index: u32, + aye: bool, + conviction: u8, + amount: &str, + from: &str, + password: Option, + password_file: Option, + 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() }); + log_print!(" 💰 Amount: {}", amount.bright_cyan()); + log_print!(" 🔒 Conviction: {}", conviction); + log_print!(" 🔑 Signed by: {}", from.bright_yellow()); + + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + // Parse amount + let amount_value: u128 = (amount + .parse::() + .map_err(|_| QuantusError::Generic("Invalid amount format".to_string()))? + .max(0.0) * + 1_000_000_000_000_000_000.0) as u128; + + // Validate conviction + if conviction > 6 { + return Err(QuantusError::Generic("Invalid conviction (must be 0-6)".to_string())); + } + + // Build vote + let vote = + quantus_subxt::api::runtime_types::pallet_conviction_voting::vote::AccountVote::Standard { + vote: quantus_subxt::api::runtime_types::pallet_conviction_voting::vote::Vote( + if aye { 128 } else { 0 } | conviction, + ), + balance: amount_value, + }; + + let vote_call = quantus_subxt::api::tx().conviction_voting().vote(index, vote); + let tx_hash = + submit_transaction(quantus_client, &keypair, vote_call, None, execution_mode).await?; + + log_print!( + "✅ {} Vote transaction submitted! Hash: {:?}", + "SUCCESS".bright_green().bold(), + tx_hash + ); + + log_success!("🎉 {} Vote submitted!", "FINISHED".bright_green().bold()); + Ok(()) +} + +/// Get Referenda configuration +async fn get_config( + quantus_client: &crate::chain::client::QuantusClient, +) -> crate::error::Result<()> { + log_print!("âš™ī¸ Referenda Configuration"); + log_print!(""); + + let constants = quantus_client.client().constants(); + let tracks_addr = quantus_subxt::api::constants().referenda().tracks(); + + match constants.at(&tracks_addr) { + Ok(tracks) => { + log_print!("{}", "📊 Track Configuration:".bold()); + for (id, info) in tracks.iter() { + log_print!(" ------------------------------------"); + log_print!( + " â€ĸ {} #{}: {}", + "Track".bold(), + id, + info.name.to_string().bright_cyan() + ); + log_print!(" â€ĸ Max Deciding: {}", info.max_deciding); + log_print!(" â€ĸ Decision Deposit: {}", info.decision_deposit); + log_print!(" â€ĸ Prepare Period: {} blocks", info.prepare_period); + log_print!(" â€ĸ Decision Period: {} blocks", info.decision_period); + log_print!(" â€ĸ Confirm Period: {} blocks", info.confirm_period); + log_print!(" â€ĸ Min Enactment Period: {} blocks", info.min_enactment_period); + } + log_print!(" ------------------------------------"); + }, + Err(e) => { + log_error!("❌ Failed to decode Tracks constant: {:?}", e); + log_print!("💡 It's possible the Tracks constant is not in the expected format."); + }, + } + + Ok(()) +} + +/// Refund submission deposit for a completed Referendum +async fn refund_submission_deposit( + quantus_client: &crate::chain::client::QuantusClient, + index: u32, + from: &str, + password: Option, + password_file: Option, + execution_mode: crate::cli::common::ExecutionMode, +) -> crate::error::Result<()> { + log_print!("💰 Refunding submission deposit for Referendum #{}", index); + log_print!(" 🔑 Refund to: {}", from.bright_yellow()); + + // Load wallet keypair + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + // Create refund_submission_deposit call + let refund_call = quantus_subxt::api::tx().referenda().refund_submission_deposit(index); + + let tx_hash = + submit_transaction(quantus_client, &keypair, refund_call, None, execution_mode).await?; + log_print!( + "✅ {} Refund transaction submitted! Hash: {:?}", + "SUCCESS".bright_green().bold(), + tx_hash + ); + + log_print!("💡 Check your balance to confirm the refund"); + Ok(()) +} + +/// Refund decision deposit for a completed Referendum +async fn refund_decision_deposit( + quantus_client: &crate::chain::client::QuantusClient, + index: u32, + from: &str, + password: Option, + password_file: Option, + execution_mode: crate::cli::common::ExecutionMode, +) -> crate::error::Result<()> { + log_print!("💰 Refunding decision deposit for Referendum #{}", index); + log_print!(" 🔑 Refund to: {}", from.bright_yellow()); + + // Load wallet keypair + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + // Create refund_decision_deposit call + let refund_call = quantus_subxt::api::tx().referenda().refund_decision_deposit(index); + + let tx_hash = + submit_transaction(quantus_client, &keypair, refund_call, None, execution_mode).await?; + log_print!( + "✅ {} Refund transaction submitted! Hash: {:?}", + "SUCCESS".bright_green().bold(), + tx_hash + ); + + log_print!("💡 Check your balance to confirm the refund"); + Ok(()) +} diff --git a/src/cli/referenda_decode.rs b/src/cli/referenda_decode.rs new file mode 100644 index 0000000..7140fa7 --- /dev/null +++ b/src/cli/referenda_decode.rs @@ -0,0 +1,243 @@ +//! Decoding utilities for referendum proposals + +use crate::error::QuantusError; +use codec::Decode; +use colored::Colorize; + +/// Decode preimage call data into human-readable format +pub async fn decode_preimage( + quantus_client: &crate::chain::client::QuantusClient, + hash: &subxt::utils::H256, + len: u32, +) -> crate::error::Result { + // Fetch preimage from storage + let latest_block_hash = quantus_client.get_latest_block().await?; + let storage_at = quantus_client.client().storage().at(latest_block_hash); + + let preimage_addr = crate::chain::quantus_subxt::api::storage() + .preimage() + .preimage_for((*hash, len)); + + let preimage_result = storage_at.fetch(&preimage_addr).await; + + let content = match preimage_result { + Ok(Some(bounded_vec)) => bounded_vec.0, + Ok(None) => + return Err(QuantusError::Generic(format!("Preimage not found for hash {:?}", hash))), + Err(e) => return Err(QuantusError::Generic(format!("Error fetching preimage: {:?}", e))), + }; + + // Decode using direct Decode trait (RuntimeCall implements it via DecodeAsType derive) + decode_runtime_call_direct(&content) +} + +/// Decode RuntimeCall directly using Decode trait +fn decode_runtime_call_direct(data: &[u8]) -> crate::error::Result { + // First, let's try to understand the call structure by reading indices + if data.len() < 3 { + return Err(QuantusError::Generic("Call data too short".to_string())); + } + + let pallet_index = data[0]; + let inner_index = data[1]; + let call_index = data[2]; + + match (pallet_index, inner_index, call_index) { + // System pallet (0, 0, X) + // Special case: if call_index looks like Compact (high value like 0xe8), + // it might be remark (call 0) where the call index byte is omitted + (0, 0, idx) if idx > 100 => { + // Likely remark (call 0) with Compact-encoded Vec starting at byte 2 + decode_system_remark_no_index(&data[2..]) + }, + (0, 0, _) => decode_system_call(&data[2..]), + + // TreasuryPallet (18, 5, X) where X is any spend variant (11, 15, 19, etc.) + // Different indices represent different value ranges/encodings + (18, 5, _) => decode_treasury_spend_call(&data[3..]), + + // Unknown + _ => Ok(format!( + " {} {} {} {}\n {} {} bytes\n {}:\n {}", + "Call Indices:".dimmed(), + pallet_index, + inner_index, + call_index, + "Args:".dimmed(), + data.len() - 3, + "Raw Hex".dimmed(), + hex::encode(&data[3..]).bright_green() + )), + } +} + +/// Decode System::remark when call index byte is omitted (call 0) +fn decode_system_remark_no_index(args: &[u8]) -> crate::error::Result { + // args starts directly with Compact-encoded Vec + let mut cursor = args; + let remark_bytes: Vec = Vec::decode(&mut cursor) + .map_err(|e| QuantusError::Generic(format!("Failed to decode remark: {:?}", e)))?; + let remark_str = String::from_utf8_lossy(&remark_bytes); + + Ok(format!( + " {} {}\n {} {}\n {}:\n {} \"{}\"", + "Pallet:".dimmed(), + "System".bright_cyan(), + "Call:".dimmed(), + "remark".bright_yellow(), + "Parameters".dimmed(), + "message:".dimmed(), + remark_str.bright_green() + )) +} + +/// Decode System pallet calls +fn decode_system_call(data_from_call: &[u8]) -> crate::error::Result { + if data_from_call.is_empty() { + return Err(QuantusError::Generic("Empty system call data".to_string())); + } + + let call_index = data_from_call[0]; + let args = &data_from_call[1..]; + + match call_index { + 0 => { + // remark - standard Vec + let mut cursor = args; + let remark_bytes: Vec = Vec::decode(&mut cursor) + .map_err(|e| QuantusError::Generic(format!("Failed to decode remark: {:?}", e)))?; + let remark_str = String::from_utf8_lossy(&remark_bytes); + + Ok(format!( + " {} {}\n {} {}\n {}:\n {} \"{}\"", + "Pallet:".dimmed(), + "System".bright_cyan(), + "Call:".dimmed(), + "remark".bright_yellow(), + "Parameters".dimmed(), + "message:".dimmed(), + remark_str.bright_green() + )) + }, + 1 => { + // remark_with_event - has different encoding, try decoding from byte 1 + let remark_str = if args.len() > 1 { + String::from_utf8_lossy(&args[1..]) + } else { + String::from_utf8_lossy(args) + }; + + Ok(format!( + " {} {}\n {} {}\n {}:\n {} \"{}\"", + "Pallet:".dimmed(), + "System".bright_cyan(), + "Call:".dimmed(), + "remark_with_event".bright_yellow(), + "Parameters".dimmed(), + "message:".dimmed(), + remark_str.bright_green() + )) + }, + 7 => { + // set_code + Ok(format!( + " {} {}\n {} {} {}\n {} {}", + "Pallet:".dimmed(), + "System".bright_cyan(), + "Call:".dimmed(), + "set_code".bright_yellow(), + "(Runtime Upgrade)".dimmed(), + "Parameters:".dimmed(), + "".bright_green() + )) + }, + _ => Ok(format!( + " {} {}\n {} {} (index {})", + "Pallet:".dimmed(), + "System".bright_cyan(), + "Call:".dimmed(), + "unknown".yellow(), + call_index + )), + } +} + +/// Decode TreasuryPallet::spend call arguments +/// The amount is stored as variable-length u128 in little-endian +fn decode_treasury_spend_call(args: &[u8]) -> crate::error::Result { + use sp_core::crypto::Ss58Codec; + + crate::log_verbose!("Decoding treasury spend, args length: {} bytes", args.len()); + crate::log_verbose!("Args hex: {}", hex::encode(args)); + + if args.len() < 34 { + return Err(QuantusError::Generic(format!( + "Args too short for treasury spend: {} bytes (expected 40-42)", + args.len() + ))); + } + + // Structure (discovered through empirical analysis): + // - asset_kind: Box<()> = 0 bytes (unit type has no encoding) + // - amount: u128 = variable bytes (7-8 bytes typically) as little-endian + // - beneficiary: Box = 32 bytes (no variant byte!) + // - valid_from: Option = 1 byte (0x00 for None) + + // The amount length varies based on the value: + // - Small values (< 256TB): 7 bytes + // - Larger values: 8+ bytes + // Total length is typically 40 bytes (7+32+1) or 42 bytes (8+32+1) or similar + + // Calculate amount bytes length: total - 32 (beneficiary) - 1 (valid_from) + let amount_bytes_len = args.len() - 32 - 1; + if !(1..=16).contains(&amount_bytes_len) { + return Err(QuantusError::Generic(format!( + "Invalid amount bytes length: {}", + amount_bytes_len + ))); + } + + // Decode amount: first N bytes as little-endian u128 + let mut amount_bytes_extended = [0u8; 16]; + amount_bytes_extended[..amount_bytes_len].copy_from_slice(&args[..amount_bytes_len]); + let amount = u128::from_le_bytes(amount_bytes_extended); + + // Decode beneficiary: starts after amount bytes, 32 bytes + let beneficiary_start = amount_bytes_len; + let account_bytes: [u8; 32] = args[beneficiary_start..beneficiary_start + 32] + .try_into() + .map_err(|_| QuantusError::Generic("Failed to extract beneficiary bytes".to_string()))?; + let sp_account = sp_core::crypto::AccountId32::from(account_bytes); + let ss58 = sp_account.to_ss58check_with_version(sp_core::crypto::Ss58AddressFormat::custom(42)); + let beneficiary_str = format!("{} ({}...{})", ss58, &ss58[..8], &ss58[ss58.len() - 6..]); + + // Decode valid_from: last byte + let valid_from_byte = args[args.len() - 1]; + let valid_from_str = if valid_from_byte == 0 { + "None (immediate)".to_string() + } else { + format!("Some (byte: 0x{:02x})", valid_from_byte) + }; + + // Format amount in QUAN (1 QUAN = 10^12) + let quan = amount as f64 / 1_000_000_000_000.0; + + Ok(format!( + " {} {}\n {} {}\n {}:\n {} {} {} ({} raw)\n {} {}\n {} {}\n\n {} {}", + "Pallet:".dimmed(), + "TreasuryPallet".bright_cyan(), + "Call:".dimmed(), + "spend".bright_yellow(), + "Parameters".dimmed(), + "amount:".dimmed(), + quan.to_string().bright_green().bold(), + "QUAN".bright_green(), + amount, + "beneficiary:".dimmed(), + beneficiary_str.bright_green(), + "valid_from:".dimmed(), + valid_from_str.bright_green(), + "💡 Info:".cyan(), + "Vote YES if you approve this Treasury spend, NO to reject.".cyan() + )) +} diff --git a/src/cli/tech_referenda.rs b/src/cli/tech_referenda.rs new file mode 100644 index 0000000..6fc8860 --- /dev/null +++ b/src/cli/tech_referenda.rs @@ -0,0 +1,771 @@ +//! `quantus tech-referenda` subcommand - manage Tech Referenda proposals +use crate::{ + chain::quantus_subxt, cli::common::submit_transaction, error::QuantusError, log_error, + log_print, log_success, log_verbose, +}; +use clap::Subcommand; +use colored::Colorize; +use std::{path::PathBuf, str::FromStr}; + +/// Tech Referenda management commands +#[derive(Subcommand, Debug)] +pub enum TechReferendaCommands { + /// Submit a runtime upgrade proposal to Tech Referenda (requires existing preimage) + Submit { + /// Preimage hash (must already exist on chain) + #[arg(long)] + preimage_hash: String, + + /// Wallet name to sign with (must be a Tech Collective member or root) + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + }, + + /// Submit a runtime upgrade proposal to Tech Referenda (creates preimage first) + SubmitWithPreimage { + /// Path to the runtime WASM file + #[arg(short, long)] + wasm_file: PathBuf, + + /// Wallet name to sign with (must be a Tech Collective member or root) + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + }, + + /// List all active Tech Referenda proposals + List, + + /// Get details of a specific Tech Referendum + Get { + /// Referendum index + #[arg(short, long)] + index: u32, + }, + + /// Check the status of a Tech Referendum + Status { + /// Referendum index + #[arg(short, long)] + index: u32, + }, + + /// Place a decision deposit for a Tech Referendum + PlaceDecisionDeposit { + /// Referendum index + #[arg(short, long)] + index: u32, + + /// Wallet name to sign with + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + }, + + /// Cancel a Tech Referendum (requires root permissions) + Cancel { + /// Referendum index to cancel + #[arg(short, long)] + index: u32, + + /// Wallet name to sign with (must have root permissions) + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + }, + + /// Kill a Tech Referendum (requires root permissions) + Kill { + /// Referendum index to kill + #[arg(short, long)] + index: u32, + + /// Wallet name to sign with (must have root permissions) + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + }, + + /// Nudge a Tech Referendum to next phase (sudo origin) + Nudge { + /// Referendum index to nudge + #[arg(short, long)] + index: u32, + + /// Wallet name to sign with + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + }, + + /// Refund submission deposit for a completed Tech Referendum + RefundSubmissionDeposit { + /// Referendum index + #[arg(short, long)] + index: u32, + + /// Wallet name that submitted the referendum + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + }, + + /// Refund decision deposit for a completed Tech Referendum + RefundDecisionDeposit { + /// Referendum index + #[arg(short, long)] + index: u32, + + /// Wallet name that placed the decision deposit + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + }, + + /// Get Tech Referenda configuration + Config, +} + +/// Handle tech referenda commands +pub async fn handle_tech_referenda_command( + command: TechReferendaCommands, + node_url: &str, + execution_mode: crate::cli::common::ExecutionMode, +) -> crate::error::Result<()> { + let quantus_client = crate::chain::client::QuantusClient::new(node_url).await?; + + match command { + TechReferendaCommands::Submit { preimage_hash, from, password, password_file } => + submit_runtime_upgrade( + &quantus_client, + &preimage_hash, + &from, + password, + password_file, + execution_mode, + ) + .await, + TechReferendaCommands::SubmitWithPreimage { wasm_file, from, password, password_file } => + submit_runtime_upgrade_with_preimage( + &quantus_client, + &wasm_file, + &from, + password, + password_file, + execution_mode, + ) + .await, + TechReferendaCommands::List => list_proposals(&quantus_client).await, + TechReferendaCommands::Get { index } => get_proposal_details(&quantus_client, index).await, + TechReferendaCommands::Status { index } => + get_proposal_status(&quantus_client, index).await, + TechReferendaCommands::PlaceDecisionDeposit { index, from, password, password_file } => + place_decision_deposit( + &quantus_client, + index, + &from, + password, + password_file, + execution_mode, + ) + .await, + TechReferendaCommands::Cancel { index, from, password, password_file } => + 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, execution_mode) + .await, + TechReferendaCommands::Nudge { index, from, password, password_file } => + nudge_proposal(&quantus_client, index, &from, password, password_file, execution_mode) + .await, + TechReferendaCommands::RefundSubmissionDeposit { index, from, password, password_file } => + refund_submission_deposit( + &quantus_client, + index, + &from, + password, + password_file, + execution_mode, + ) + .await, + TechReferendaCommands::RefundDecisionDeposit { index, from, password, password_file } => + refund_decision_deposit( + &quantus_client, + index, + &from, + password, + password_file, + execution_mode, + ) + .await, + TechReferendaCommands::Config => get_config(&quantus_client).await, + } +} + +/// Submit a runtime upgrade proposal to Tech Referenda (uses existing preimage) +async fn submit_runtime_upgrade( + quantus_client: &crate::chain::client::QuantusClient, + preimage_hash: &str, + from: &str, + password: Option, + password_file: Option, + 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()); + log_print!(" 🔑 Submitted by: {}", from.bright_yellow()); + + // Parse preimage hash (trim 0x) + let hash_str = preimage_hash.trim_start_matches("0x"); + let preimage_hash_parsed: sp_core::H256 = sp_core::H256::from_str(hash_str) + .map_err(|_| QuantusError::Generic("Invalid preimage hash format".to_string()))?; + + // Load wallet keypair + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + // Check if preimage exists and get its length + log_print!("🔍 Checking preimage status..."); + let latest_block_hash = quantus_client.get_latest_block().await?; + let storage_at = quantus_client.client().storage().at(latest_block_hash); + + let preimage_status = storage_at + .fetch( + &quantus_subxt::api::storage() + .preimage() + .request_status_for(preimage_hash_parsed), + ) + .await + .map_err(|e| QuantusError::Generic(format!("Failed to fetch preimage status: {:?}", e)))? + .ok_or_else(|| QuantusError::Generic("Preimage not found on chain".to_string()))?; + + let preimage_len = match preimage_status { + quantus_subxt::api::runtime_types::pallet_preimage::RequestStatus::Unrequested { + ticket: _, + len, + } => len, + quantus_subxt::api::runtime_types::pallet_preimage::RequestStatus::Requested { + maybe_ticket: _, + count: _, + maybe_len, + } => match maybe_len { + Some(len) => len, + None => return Err(QuantusError::Generic("Preimage length not available".to_string())), + }, + }; + + log_print!("✅ Preimage found! Length: {} bytes", preimage_len); + + // Build TechReferenda::submit call using Lookup preimage reference + type ProposalBounded = + quantus_subxt::api::runtime_types::frame_support::traits::preimages::Bounded< + quantus_subxt::api::runtime_types::quantus_runtime::RuntimeCall, + quantus_subxt::api::runtime_types::qp_poseidon::PoseidonHasher, + >; + + let preimage_hash_subxt: subxt::utils::H256 = preimage_hash_parsed; + let proposal: ProposalBounded = + ProposalBounded::Lookup { hash: preimage_hash_subxt, len: preimage_len }; + + let raw_origin_root = + quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::Root; + let origin_caller = + quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin_root); + + let enactment = + quantus_subxt::api::runtime_types::frame_support::traits::schedule::DispatchTime::After( + 0u32, + ); + + log_print!("🔧 Creating TechReferenda::submit call..."); + let submit_call = + quantus_subxt::api::tx() + .tech_referenda() + .submit(origin_caller, proposal, enactment); + + let tx_hash = + submit_transaction(quantus_client, &keypair, submit_call, None, execution_mode).await?; + log_print!( + "✅ {} Runtime upgrade proposal submitted! Hash: {:?}", + "SUCCESS".bright_green().bold(), + tx_hash + ); + + log_print!("💡 Use 'quantus tech-referenda list' to see active proposals"); + Ok(()) +} + +/// Submit a runtime upgrade proposal to Tech Referenda (creates preimage first) +async fn submit_runtime_upgrade_with_preimage( + quantus_client: &crate::chain::client::QuantusClient, + wasm_file: &PathBuf, + from: &str, + password: Option, + password_file: Option, + execution_mode: crate::cli::common::ExecutionMode, +) -> crate::error::Result<()> { + use qp_poseidon::PoseidonHasher; + + log_print!("📝 Submitting Runtime Upgrade Proposal to Tech Referenda"); + log_print!(" 📂 WASM file: {}", wasm_file.display().to_string().bright_cyan()); + log_print!(" 🔑 Submitted by: {}", from.bright_yellow()); + + if !wasm_file.exists() { + return Err(QuantusError::Generic(format!("WASM file not found: {}", wasm_file.display()))); + } + + if let Some(ext) = wasm_file.extension() { + if ext != "wasm" { + log_verbose!("âš ī¸ Warning: File doesn't have .wasm extension"); + } + } + + // Read WASM file + let wasm_code = std::fs::read(wasm_file) + .map_err(|e| QuantusError::Generic(format!("Failed to read WASM file: {}", e)))?; + + log_print!("📊 WASM file size: {} bytes", wasm_code.len()); + + // Load wallet keypair + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + // Build a static payload for System::set_code and encode full call data (pallet + call + args) + let set_code_payload = quantus_subxt::api::tx().system().set_code(wasm_code.clone()); + let metadata = quantus_client.client().metadata(); + let encoded_call = <_ as subxt::tx::Payload>::encode_call_data(&set_code_payload, &metadata) + .map_err(|e| QuantusError::Generic(format!("Failed to encode call data: {:?}", e)))?; + + log_verbose!("📝 Encoded call size: {} bytes", encoded_call.len()); + + // Compute preimage hash using Poseidon (runtime uses PoseidonHasher) + let preimage_hash: sp_core::H256 = + ::hash(&encoded_call); + + log_print!("🔗 Preimage hash: {:?}", preimage_hash); + + // Submit Preimage::note_preimage with bounded bytes + type PreimageBytes = quantus_subxt::api::preimage::calls::types::note_preimage::Bytes; + let bounded_bytes: PreimageBytes = encoded_call.clone(); + + 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, execution_mode) + .await?; + log_print!("✅ Preimage transaction submitted: {:?}", preimage_tx_hash); + + // Wait for preimage transaction confirmation + log_print!("âŗ Waiting for preimage transaction confirmation..."); + + // Build TechReferenda::submit call using Lookup preimage reference + type ProposalBounded = + quantus_subxt::api::runtime_types::frame_support::traits::preimages::Bounded< + quantus_subxt::api::runtime_types::quantus_runtime::RuntimeCall, + quantus_subxt::api::runtime_types::qp_poseidon::PoseidonHasher, + >; + + let preimage_hash_subxt: subxt::utils::H256 = preimage_hash; + let proposal: ProposalBounded = + ProposalBounded::Lookup { hash: preimage_hash_subxt, len: encoded_call.len() as u32 }; + + let raw_origin_root = + quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::Root; + let origin_caller = + quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin_root); + + let enactment = + quantus_subxt::api::runtime_types::frame_support::traits::schedule::DispatchTime::After( + 0u32, + ); + + log_print!("🔧 Creating TechReferenda::submit call..."); + let submit_call = + quantus_subxt::api::tx() + .tech_referenda() + .submit(origin_caller, proposal, enactment); + + let tx_hash = + submit_transaction(quantus_client, &keypair, submit_call, None, execution_mode).await?; + log_print!( + "✅ {} Runtime upgrade proposal submitted! Hash: {:?}", + "SUCCESS".bright_green().bold(), + tx_hash + ); + + log_print!("💡 Use 'quantus tech-referenda list' to see active proposals"); + Ok(()) +} + +/// List recent Tech Referenda proposals +async fn list_proposals( + quantus_client: &crate::chain::client::QuantusClient, +) -> crate::error::Result<()> { + log_print!("📜 Active Tech Referenda Proposals"); + log_print!(""); + + let addr = quantus_subxt::api::storage().tech_referenda().referendum_count(); + + // Get the latest block hash to read from the latest state (not finalized) + let latest_block_hash = quantus_client.get_latest_block().await?; + let storage_at = quantus_client.client().storage().at(latest_block_hash); + + let count = storage_at.fetch(&addr).await?; + + if let Some(total) = count { + log_print!("📊 Total referenda created: {}", total); + if total == 0 { + log_print!("📭 No active proposals found"); + return Ok(()); + } + log_print!("🔍 Fetching recent referenda..."); + for i in (0..total).rev().take(10) { + get_proposal_status(quantus_client, i).await?; + log_print!("----------------------------------------"); + } + } else { + log_print!("📭 No referenda found - Tech Referenda may be empty"); + } + + Ok(()) +} + +/// Get details of a specific Tech Referendum +async fn get_proposal_details( + quantus_client: &crate::chain::client::QuantusClient, + index: u32, +) -> crate::error::Result<()> { + log_print!("📄 Tech Referendum #{} Details", index); + log_print!(""); + + let addr = quantus_subxt::api::storage().tech_referenda().referendum_info_for(index); + + // Get the latest block hash to read from the latest state (not finalized) + let latest_block_hash = quantus_client.get_latest_block().await?; + let storage_at = quantus_client.client().storage().at(latest_block_hash); + + let info = storage_at.fetch(&addr).await?; + + if let Some(referendum_info) = info { + log_print!("📋 Referendum Information (raw):"); + log_print!("{:#?}", referendum_info); + } else { + log_print!("📭 Referendum #{} not found", index); + } + Ok(()) +} + +/// Get the status of a Tech Referendum +async fn get_proposal_status( + quantus_client: &crate::chain::client::QuantusClient, + index: u32, +) -> crate::error::Result<()> { + use quantus_subxt::api::runtime_types::pallet_referenda::types::ReferendumInfo; + + log_verbose!("📊 Fetching status for Tech Referendum #{}...", index); + + let addr = quantus_subxt::api::storage().tech_referenda().referendum_info_for(index); + + // Get the latest block hash to read from the latest state (not finalized) + let latest_block_hash = quantus_client.get_latest_block().await?; + let storage_at = quantus_client.client().storage().at(latest_block_hash); + + let info_res = storage_at.fetch(&addr).await; + + match info_res { + Ok(Some(info)) => { + log_print!("📊 Status for Referendum #{}", index.to_string().bright_yellow()); + match info { + ReferendumInfo::Ongoing(status) => { + log_print!(" - Status: {}", "Ongoing".bright_green()); + log_print!(" - Track: {}", status.track); + log_print!(" - Submitted at: block {}", status.submitted); + log_print!( + " - Tally: Ayes: {}, Nays: {}", + status.tally.ayes, + status.tally.nays + ); + log_verbose!(" - Full status: {:#?}", status); + }, + ReferendumInfo::Approved(submitted, ..) => { + log_print!(" - Status: {}", "Approved".green()); + log_print!(" - Submitted at block: {}", submitted); + }, + ReferendumInfo::Rejected(submitted, ..) => { + log_print!(" - Status: {}", "Rejected".red()); + log_print!(" - Submitted at block: {}", submitted); + }, + ReferendumInfo::Cancelled(submitted, ..) => { + log_print!(" - Status: {}", "Cancelled".yellow()); + log_print!(" - Submitted at block: {}", submitted); + }, + ReferendumInfo::TimedOut(submitted, ..) => { + log_print!(" - Status: {}", "TimedOut".dimmed()); + log_print!(" - Submitted at block: {}", submitted); + }, + ReferendumInfo::Killed(submitted) => { + log_print!(" - Status: {}", "Killed".red().bold()); + log_print!(" - Killed at block: {}", submitted); + }, + } + }, + Ok(None) => log_print!("📭 Referendum #{} not found", index), + Err(e) => log_error!("❌ Failed to fetch referendum #{}: {:?}", index, e), + } + + Ok(()) +} + +/// Place a decision deposit for a Tech Referendum +async fn place_decision_deposit( + quantus_client: &crate::chain::client::QuantusClient, + index: u32, + from: &str, + password: Option, + password_file: Option, + 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()); + + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + let deposit_call = quantus_subxt::api::tx().tech_referenda().place_decision_deposit(index); + let tx_hash = + submit_transaction(quantus_client, &keypair, deposit_call, None, execution_mode).await?; + log_success!("✅ Decision deposit placed! Hash: {:?}", tx_hash.to_string().bright_yellow()); + Ok(()) +} + +/// Cancel a Tech Referendum (sudo) +async fn cancel_proposal( + quantus_client: &crate::chain::client::QuantusClient, + index: u32, + from: &str, + password: Option, + password_file: Option, + execution_mode: crate::cli::common::ExecutionMode, +) -> crate::error::Result<()> { + log_print!("❌ Cancelling Tech Referendum #{}", index); + log_print!(" 🔑 Cancelled by: {}", from.bright_yellow()); + + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + let inner = + quantus_subxt::api::Call::TechReferenda(quantus_subxt::api::tech_referenda::Call::cancel { + index, + }); + let sudo_call = quantus_subxt::api::tx().sudo().sudo(inner); + + 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(()) +} + +/// Kill a Tech Referendum (sudo) +async fn kill_proposal( + quantus_client: &crate::chain::client::QuantusClient, + index: u32, + from: &str, + password: Option, + password_file: Option, + execution_mode: crate::cli::common::ExecutionMode, +) -> crate::error::Result<()> { + log_print!("💀 Killing Tech Referendum #{}", index); + log_print!(" 🔑 Killed by: {}", from.bright_yellow()); + + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + let inner = + quantus_subxt::api::Call::TechReferenda(quantus_subxt::api::tech_referenda::Call::kill { + index, + }); + let sudo_call = quantus_subxt::api::tx().sudo().sudo(inner); + + 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(()) +} + +/// Nudge a Tech Referendum to next phase (sudo) +async fn nudge_proposal( + quantus_client: &crate::chain::client::QuantusClient, + index: u32, + from: &str, + password: Option, + password_file: Option, + execution_mode: crate::cli::common::ExecutionMode, +) -> crate::error::Result<()> { + log_print!("🔄 Nudging Tech Referendum #{}", index); + log_print!(" 🔑 Nudged by: {}", from.bright_yellow()); + + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + let inner = quantus_subxt::api::Call::TechReferenda( + quantus_subxt::api::tech_referenda::Call::nudge_referendum { index }, + ); + let sudo_call = quantus_subxt::api::tx().sudo().sudo(inner); + + 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(()) +} + +/// Get Tech Referenda configuration +async fn get_config( + quantus_client: &crate::chain::client::QuantusClient, +) -> crate::error::Result<()> { + log_print!("âš™ī¸ Tech Referenda Configuration"); + log_print!(""); + + let constants = quantus_client.client().constants(); + let tracks_addr = quantus_subxt::api::constants().tech_referenda().tracks(); + + match constants.at(&tracks_addr) { + Ok(tracks) => { + log_print!("{}", "📊 Track Configuration:".bold()); + for (id, info) in tracks.iter() { + log_print!(" ------------------------------------"); + log_print!( + " â€ĸ {} #{}: {}", + "Track".bold(), + id, + info.name.to_string().bright_cyan() + ); + log_print!(" â€ĸ Max Deciding: {}", info.max_deciding); + log_print!(" â€ĸ Decision Deposit: {}", info.decision_deposit); + log_print!(" â€ĸ Prepare Period: {} blocks", info.prepare_period); + log_print!(" â€ĸ Decision Period: {} blocks", info.decision_period); + log_print!(" â€ĸ Confirm Period: {} blocks", info.confirm_period); + log_print!(" â€ĸ Min Enactment Period: {} blocks", info.min_enactment_period); + } + log_print!(" ------------------------------------"); + }, + Err(e) => { + log_error!("❌ Failed to decode Tracks constant: {:?}", e); + log_print!("💡 It's possible the Tracks constant is not in the expected format."); + }, + } + + Ok(()) +} + +/// Refund submission deposit for a completed Tech Referendum +async fn refund_submission_deposit( + quantus_client: &crate::chain::client::QuantusClient, + index: u32, + from: &str, + password: Option, + password_file: Option, + 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()); + + // Load wallet keypair + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + // Create refund_submission_deposit call for TechReferenda instance + let refund_call = quantus_subxt::api::tx().tech_referenda().refund_submission_deposit(index); + + let tx_hash = + submit_transaction(quantus_client, &keypair, refund_call, None, execution_mode).await?; + log_print!( + "✅ {} Refund transaction submitted! Hash: {:?}", + "SUCCESS".bright_green().bold(), + tx_hash + ); + + log_success!("🎉 {} Submission deposit refunded!", "FINISHED".bright_green().bold()); + log_print!("💡 Check your balance to confirm the refund"); + Ok(()) +} + +/// Refund decision deposit for a completed Tech Referendum +async fn refund_decision_deposit( + quantus_client: &crate::chain::client::QuantusClient, + index: u32, + from: &str, + password: Option, + password_file: Option, + 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()); + + // Load wallet keypair + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + // Create refund_decision_deposit call for TechReferenda instance + let refund_call = quantus_subxt::api::tx().tech_referenda().refund_decision_deposit(index); + + let tx_hash = + submit_transaction(quantus_client, &keypair, refund_call, None, execution_mode).await?; + log_print!( + "✅ {} Refund transaction submitted! Hash: {:?}", + "SUCCESS".bright_green().bold(), + tx_hash + ); + + log_success!("🎉 {} Decision deposit refunded!", "FINISHED".bright_green().bold()); + log_print!("💡 Check your balance to confirm the refund"); + Ok(()) +} diff --git a/src/config/mod.rs b/src/config/mod.rs index c6d7ac8..a8f3074 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -3,7 +3,7 @@ //! This module handles runtime compatibility information. /// List of runtime spec versions that this CLI is compatible with -pub const COMPATIBLE_RUNTIME_VERSIONS: &[u32] = &[115, 116]; +pub const COMPATIBLE_RUNTIME_VERSIONS: &[u32] = &[118]; /// Check if a runtime version is compatible with this CLI pub fn is_runtime_compatible(spec_version: u32) -> bool { diff --git a/src/quantus_metadata.scale b/src/quantus_metadata.scale index a26ebd3d6596c6fd980bbc9313a32f6e0c8a4b30..d77a70b0b04abf18c938614aa8f726adf6c82203 100644 GIT binary patch delta 21 ccmccehx5uG&W0AoElf-tjAh%IIhX>=0A`2>dH?_b delta 21 ccmccehx5uG&W0AoElf-tjHTO|IhX>=0A_&)c>n+a From 8438930ffbfc5ef8109ad09dbd95dea21ed66974 Mon Sep 17 00:00:00 2001 From: Cezary Olborski Date: Fri, 13 Mar 2026 09:20:06 +0800 Subject: [PATCH 2/8] feat: Chain after refactor --- Cargo.lock | 10 +- Cargo.toml | 4 +- src/chain/quantus_subxt.rs | 673 ++++++++++--------------------------- src/cli/referenda.rs | 34 +- src/cli/reversible.rs | 148 +++----- src/cli/scheduler.rs | 4 +- src/cli/wallet.rs | 49 ++- src/config/mod.rs | 2 +- src/quantus_metadata.scale | Bin 163412 -> 161878 bytes src/wallet/mod.rs | 6 +- 10 files changed, 294 insertions(+), 636 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e73b717..dac1782 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3582,9 +3582,9 @@ dependencies = [ [[package]] name = "qp-dilithium-crypto" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c3fbdb9557a22cb876fc17c483d090e9556cbfdfc52beb0696143d4313d9" +checksum = "476cab75a58360464ef58fe3bfaa01b4a450a0895d32f028a1e17a0b9031657c" dependencies = [ "log", "parity-scale-codec", @@ -3754,17 +3754,15 @@ dependencies = [ [[package]] name = "qp-rusty-crystals-hdwallet" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91781bc0b96238c7e038a2d3157410388cb0458b05d42483851e79684e92f1a8" +checksum = "113fdac36387a857ab4e09fdc050098bc7b55bcd6e5a8ab755e7f44ef10741e6" dependencies = [ "bip39", - "bs58", "getrandom 0.2.17", "hex", "hex-literal", "hmac 0.12.1", - "k256", "qp-poseidon-core", "qp-rusty-crystals-dilithium", "serde", diff --git a/Cargo.toml b/Cargo.toml index c08da6e..af5f24a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,9 +50,9 @@ aes-gcm = "0.10" # AES-256-GCM (quantum-safe with 256-bit keys) # Quantus crypto dependencies (aligned with chain) qp-rusty-crystals-dilithium = { version = "2.1.0" } -qp-rusty-crystals-hdwallet = { version = "2.0.0" } +qp-rusty-crystals-hdwallet = { version = "2.1.0" } # Chain primitive (same branch as node); Cargo finds crate by name in repo -qp-dilithium-crypto = { version = "0.2.2", features = ["serde"] } +qp-dilithium-crypto = { version = "0.2.3", features = ["serde"] } qp-poseidon = { version = "1.1.0" } # HTTP client for Subsquid queries diff --git a/src/chain/quantus_subxt.rs b/src/chain/quantus_subxt.rs index a78d52d..12c1c58 100644 --- a/src/chain/quantus_subxt.rs +++ b/src/chain/quantus_subxt.rs @@ -782,26 +782,6 @@ pub mod api { use super::{root_mod, runtime_types}; pub struct QPoWApi; impl QPoWApi { - #[doc = " calculate hash of header with nonce using Bitcoin-style double Poseidon2"] - pub fn get_nonce_distance( - &self, - block_hash: types::get_nonce_distance::BlockHash, - nonce: types::get_nonce_distance::Nonce, - ) -> ::subxt::ext::subxt_core::runtime_api::payload::StaticPayload< - types::GetNonceDistance, - types::get_nonce_distance::output::Output, - > { - ::subxt::ext::subxt_core::runtime_api::payload::StaticPayload::new_static( - "QPoWApi", - "get_nonce_distance", - types::GetNonceDistance { block_hash, nonce }, - [ - 129u8, 114u8, 220u8, 23u8, 229u8, 124u8, 105u8, 65u8, 77u8, 91u8, 9u8, - 2u8, 2u8, 177u8, 124u8, 108u8, 143u8, 100u8, 174u8, 61u8, 29u8, 55u8, - 166u8, 162u8, 16u8, 61u8, 75u8, 213u8, 182u8, 125u8, 7u8, 120u8, - ], - ) - } #[doc = " Get the max possible reorg depth"] pub fn get_max_reorg_depth( &self, @@ -859,24 +839,6 @@ pub mod api { ], ) } - #[doc = " Get total work"] - pub fn get_total_work( - &self, - ) -> ::subxt::ext::subxt_core::runtime_api::payload::StaticPayload< - types::GetTotalWork, - types::get_total_work::output::Output, - > { - ::subxt::ext::subxt_core::runtime_api::payload::StaticPayload::new_static( - "QPoWApi", - "get_total_work", - types::GetTotalWork {}, - [ - 1u8, 91u8, 59u8, 140u8, 203u8, 250u8, 8u8, 65u8, 208u8, 35u8, 187u8, - 190u8, 255u8, 125u8, 190u8, 111u8, 216u8, 168u8, 83u8, 32u8, 37u8, - 203u8, 102u8, 226u8, 88u8, 207u8, 253u8, 59u8, 86u8, 72u8, 30u8, 171u8, - ], - ) - } #[doc = " Get block ema"] pub fn get_block_time_ema( &self, @@ -986,33 +948,28 @@ pub mod api { ], ) } + pub fn verify_and_get_achieved_difficulty( + &self, + block_hash: types::verify_and_get_achieved_difficulty::BlockHash, + nonce: types::verify_and_get_achieved_difficulty::Nonce, + ) -> ::subxt::ext::subxt_core::runtime_api::payload::StaticPayload< + types::VerifyAndGetAchievedDifficulty, + types::verify_and_get_achieved_difficulty::output::Output, + > { + ::subxt::ext::subxt_core::runtime_api::payload::StaticPayload::new_static( + "QPoWApi", + "verify_and_get_achieved_difficulty", + types::VerifyAndGetAchievedDifficulty { block_hash, nonce }, + [ + 200u8, 115u8, 180u8, 31u8, 14u8, 76u8, 235u8, 83u8, 133u8, 52u8, 192u8, + 59u8, 52u8, 48u8, 224u8, 34u8, 33u8, 53u8, 218u8, 132u8, 191u8, 10u8, + 17u8, 243u8, 227u8, 162u8, 171u8, 240u8, 49u8, 217u8, 172u8, 240u8, + ], + ) + } } pub mod types { use super::runtime_types; - pub mod get_nonce_distance { - use super::runtime_types; - pub type BlockHash = [::core::primitive::u8; 32usize]; - pub type Nonce = [::core::primitive::u8; 64usize]; - pub mod output { - use super::runtime_types; - pub type Output = runtime_types::primitive_types::U512; - } - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - pub struct GetNonceDistance { - pub block_hash: get_nonce_distance::BlockHash, - pub nonce: get_nonce_distance::Nonce, - } pub mod get_max_reorg_depth { use super::runtime_types; pub mod output { @@ -1070,25 +1027,6 @@ pub mod api { crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] pub struct GetDifficulty {} - pub mod get_total_work { - use super::runtime_types; - pub mod output { - use super::runtime_types; - pub type Output = runtime_types::primitive_types::U512; - } - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - pub struct GetTotalWork {} pub mod get_block_time_ema { use super::runtime_types; pub mod output { @@ -1213,6 +1151,31 @@ pub mod api { pub block_hash: verify_nonce_local_mining::BlockHash, pub nonce: verify_nonce_local_mining::Nonce, } + pub mod verify_and_get_achieved_difficulty { + use super::runtime_types; + pub type BlockHash = [::core::primitive::u8; 32usize]; + pub type Nonce = [::core::primitive::u8; 64usize]; + pub mod output { + use super::runtime_types; + pub type Output = + (::core::primitive::bool, runtime_types::primitive_types::U512); + } + } + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + pub struct VerifyAndGetAchievedDifficulty { + pub block_hash: verify_and_get_achieved_difficulty::BlockHash, + pub nonce: verify_and_get_achieved_difficulty::Nonce, + } } } pub mod account_nonce_api { @@ -1469,9 +1432,9 @@ pub mod api { "query_call_info", types::QueryCallInfo { call, len }, [ - 198u8, 65u8, 204u8, 71u8, 28u8, 170u8, 188u8, 123u8, 4u8, 169u8, 112u8, - 140u8, 13u8, 71u8, 97u8, 37u8, 125u8, 168u8, 73u8, 123u8, 116u8, 53u8, - 236u8, 206u8, 173u8, 112u8, 141u8, 87u8, 177u8, 37u8, 238u8, 57u8, + 59u8, 44u8, 99u8, 66u8, 11u8, 94u8, 211u8, 6u8, 243u8, 46u8, 231u8, + 78u8, 147u8, 43u8, 186u8, 119u8, 84u8, 5u8, 35u8, 154u8, 58u8, 175u8, + 180u8, 197u8, 176u8, 160u8, 53u8, 155u8, 145u8, 42u8, 23u8, 102u8, ], ) } @@ -1489,10 +1452,9 @@ pub mod api { "query_call_fee_details", types::QueryCallFeeDetails { call, len }, [ - 181u8, 192u8, 142u8, 93u8, 47u8, 223u8, 252u8, 28u8, 253u8, 247u8, - 255u8, 49u8, 206u8, 94u8, 24u8, 227u8, 178u8, 147u8, 3u8, 138u8, 204u8, - 67u8, 221u8, 34u8, 21u8, 249u8, 185u8, 109u8, 195u8, 213u8, 165u8, - 162u8, + 135u8, 58u8, 229u8, 112u8, 19u8, 128u8, 2u8, 114u8, 132u8, 7u8, 98u8, + 170u8, 14u8, 148u8, 33u8, 57u8, 125u8, 107u8, 77u8, 66u8, 33u8, 10u8, + 65u8, 28u8, 121u8, 233u8, 63u8, 109u8, 189u8, 9u8, 189u8, 122u8, ], ) } @@ -1995,9 +1957,9 @@ pub mod api { .hash(); runtime_metadata_hash == [ - 241u8, 104u8, 181u8, 101u8, 78u8, 126u8, 146u8, 140u8, 82u8, 117u8, 79u8, 128u8, - 3u8, 33u8, 86u8, 223u8, 167u8, 80u8, 94u8, 196u8, 191u8, 207u8, 240u8, 239u8, - 186u8, 203u8, 0u8, 147u8, 140u8, 8u8, 140u8, 64u8, + 235u8, 241u8, 231u8, 143u8, 238u8, 18u8, 134u8, 210u8, 142u8, 123u8, 23u8, 238u8, + 7u8, 116u8, 199u8, 36u8, 101u8, 103u8, 107u8, 11u8, 141u8, 9u8, 176u8, 251u8, + 185u8, 220u8, 173u8, 198u8, 201u8, 167u8, 78u8, 188u8, ] } pub mod system { @@ -3096,10 +3058,9 @@ pub mod api { "Events", (), [ - 129u8, 117u8, 78u8, 200u8, 45u8, 177u8, 108u8, 250u8, 68u8, 196u8, - 35u8, 140u8, 114u8, 113u8, 44u8, 193u8, 216u8, 27u8, 164u8, 117u8, - 173u8, 170u8, 119u8, 26u8, 55u8, 150u8, 155u8, 226u8, 61u8, 102u8, - 162u8, 127u8, + 16u8, 202u8, 95u8, 126u8, 59u8, 71u8, 99u8, 58u8, 52u8, 83u8, 147u8, + 29u8, 27u8, 91u8, 11u8, 178u8, 100u8, 183u8, 107u8, 163u8, 243u8, + 160u8, 155u8, 46u8, 55u8, 109u8, 210u8, 242u8, 84u8, 21u8, 0u8, 174u8, ], ) } @@ -5580,9 +5541,9 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 24u8, 141u8, 2u8, 72u8, 96u8, 108u8, 188u8, 185u8, 194u8, 189u8, 85u8, - 38u8, 202u8, 47u8, 99u8, 163u8, 41u8, 150u8, 193u8, 31u8, 229u8, 218u8, - 124u8, 107u8, 188u8, 18u8, 24u8, 48u8, 88u8, 224u8, 139u8, 146u8, + 224u8, 201u8, 98u8, 222u8, 12u8, 81u8, 22u8, 130u8, 86u8, 67u8, 141u8, + 83u8, 170u8, 107u8, 209u8, 158u8, 237u8, 186u8, 132u8, 61u8, 103u8, + 153u8, 37u8, 72u8, 59u8, 69u8, 181u8, 245u8, 166u8, 244u8, 62u8, 119u8, ], ) } @@ -5605,9 +5566,9 @@ pub mod api { weight, }, [ - 46u8, 22u8, 24u8, 76u8, 164u8, 139u8, 82u8, 44u8, 160u8, 220u8, 119u8, - 122u8, 176u8, 4u8, 184u8, 55u8, 219u8, 75u8, 226u8, 43u8, 51u8, 153u8, - 189u8, 146u8, 245u8, 96u8, 161u8, 218u8, 243u8, 35u8, 70u8, 249u8, + 171u8, 105u8, 36u8, 170u8, 167u8, 130u8, 207u8, 182u8, 35u8, 146u8, + 100u8, 18u8, 244u8, 232u8, 92u8, 75u8, 128u8, 183u8, 56u8, 211u8, 8u8, + 44u8, 56u8, 99u8, 239u8, 143u8, 82u8, 65u8, 6u8, 26u8, 231u8, 216u8, ], ) } @@ -5645,10 +5606,10 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 58u8, 78u8, 164u8, 136u8, 199u8, 77u8, 215u8, 140u8, 160u8, 177u8, - 127u8, 208u8, 164u8, 155u8, 35u8, 130u8, 92u8, 143u8, 46u8, 82u8, - 232u8, 4u8, 61u8, 213u8, 74u8, 103u8, 128u8, 81u8, 26u8, 137u8, 39u8, - 71u8, + 225u8, 229u8, 154u8, 137u8, 127u8, 113u8, 207u8, 149u8, 115u8, 222u8, + 119u8, 97u8, 241u8, 115u8, 146u8, 82u8, 97u8, 105u8, 97u8, 45u8, 237u8, + 82u8, 84u8, 145u8, 235u8, 153u8, 200u8, 108u8, 222u8, 27u8, 149u8, + 202u8, ], ) } @@ -5853,10 +5814,6 @@ pub mod api { use super::runtime_types; pub type CurrentDifficulty = runtime_types::primitive_types::U512; } - pub mod total_work { - use super::runtime_types; - pub type TotalWork = runtime_types::primitive_types::U512; - } pub mod block_time_ema { use super::runtime_types; pub type BlockTimeEma = ::core::primitive::u64; @@ -5925,26 +5882,6 @@ pub mod api { ], ) } - pub fn total_work( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::total_work::TotalWork, - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "QPoW", - "TotalWork", - (), - [ - 184u8, 29u8, 54u8, 146u8, 220u8, 155u8, 103u8, 67u8, 21u8, 188u8, 53u8, - 160u8, 171u8, 107u8, 52u8, 211u8, 251u8, 52u8, 192u8, 227u8, 150u8, - 156u8, 172u8, 1u8, 233u8, 37u8, 49u8, 13u8, 213u8, 104u8, 10u8, 134u8, - ], - ) - } pub fn block_time_ema( &self, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< @@ -6753,23 +6690,14 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Anonymously schedule a task."] pub struct Schedule { pub when: schedule::When, - pub maybe_periodic: schedule::MaybePeriodic, pub priority: schedule::Priority, pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, } pub mod schedule { use super::runtime_types; pub type When = ::core::primitive::u32; - pub type MaybePeriodic = ::core::option::Option<( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - )>; pub type Priority = ::core::primitive::u8; pub type Call = runtime_types::quantus_runtime::RuntimeCall; } @@ -6816,11 +6744,9 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Schedule a named task."] pub struct ScheduleNamed { pub id: schedule_named::Id, pub when: schedule_named::When, - pub maybe_periodic: schedule_named::MaybePeriodic, pub priority: schedule_named::Priority, pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, } @@ -6828,13 +6754,6 @@ pub mod api { use super::runtime_types; pub type Id = [::core::primitive::u8; 32usize]; pub type When = ::core::primitive::u32; - pub type MaybePeriodic = ::core::option::Option<( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - )>; pub type Priority = ::core::primitive::u8; pub type Call = runtime_types::quantus_runtime::RuntimeCall; } @@ -6876,10 +6795,8 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Anonymously schedule a task after a delay."] pub struct ScheduleAfter { pub after: schedule_after::After, - pub maybe_periodic: schedule_after::MaybePeriodic, pub priority: schedule_after::Priority, pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, } @@ -6889,13 +6806,6 @@ pub mod api { ::core::primitive::u32, ::core::primitive::u64, >; - pub type MaybePeriodic = ::core::option::Option<( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - )>; pub type Priority = ::core::primitive::u8; pub type Call = runtime_types::quantus_runtime::RuntimeCall; } @@ -6914,11 +6824,9 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Schedule a named task after a delay."] pub struct ScheduleNamedAfter { pub id: schedule_named_after::Id, pub after: schedule_named_after::After, - pub maybe_periodic: schedule_named_after::MaybePeriodic, pub priority: schedule_named_after::Priority, pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, @@ -6930,13 +6838,6 @@ pub mod api { ::core::primitive::u32, ::core::primitive::u64, >; - pub type MaybePeriodic = ::core::option::Option<( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - )>; pub type Priority = ::core::primitive::u8; pub type Call = runtime_types::quantus_runtime::RuntimeCall; } @@ -6960,10 +6861,9 @@ pub mod api { #[doc = "succeeds."] #[doc = ""] #[doc = "Tasks which need to be scheduled for a retry are still subject to weight metering and"] - #[doc = "agenda space, same as a regular task. If a periodic task fails, it will be scheduled"] - #[doc = "normally while the task is retrying."] + #[doc = "agenda space, same as a regular task."] #[doc = ""] - #[doc = "Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic"] + #[doc = "Tasks scheduled as a result of a retry are unnamed"] #[doc = "clones of the original task. Their retry configuration will be derived from the"] #[doc = "original task's configuration, but will have a lower value for `remaining` than the"] #[doc = "original `total_retries`."] @@ -7007,10 +6907,9 @@ pub mod api { #[doc = "it succeeds."] #[doc = ""] #[doc = "Tasks which need to be scheduled for a retry are still subject to weight metering and"] - #[doc = "agenda space, same as a regular task. If a periodic task fails, it will be scheduled"] - #[doc = "normally while the task is retrying."] + #[doc = "agenda space, same as a regular task."] #[doc = ""] - #[doc = "Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic"] + #[doc = "Tasks scheduled as a result of a retry are unnamed"] #[doc = "clones of the original task. Their retry configuration will be derived from the"] #[doc = "original task's configuration, but will have a lower value for `remaining` than the"] #[doc = "original `total_retries`."] @@ -7087,11 +6986,9 @@ pub mod api { } pub struct TransactionApi; impl TransactionApi { - #[doc = "Anonymously schedule a task."] pub fn schedule( &self, when: types::schedule::When, - maybe_periodic: types::schedule::MaybePeriodic, priority: types::schedule::Priority, call: types::schedule::Call, ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { @@ -7100,14 +6997,13 @@ pub mod api { "schedule", types::Schedule { when, - maybe_periodic, priority, call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 232u8, 174u8, 107u8, 181u8, 152u8, 133u8, 51u8, 35u8, 111u8, 19u8, - 66u8, 80u8, 0u8, 148u8, 65u8, 239u8, 162u8, 250u8, 28u8, 124u8, 20u8, - 250u8, 177u8, 112u8, 35u8, 19u8, 32u8, 9u8, 166u8, 48u8, 69u8, 206u8, + 59u8, 142u8, 42u8, 82u8, 31u8, 67u8, 95u8, 118u8, 24u8, 55u8, 82u8, + 141u8, 2u8, 133u8, 213u8, 81u8, 84u8, 109u8, 6u8, 239u8, 46u8, 233u8, + 125u8, 136u8, 15u8, 160u8, 240u8, 29u8, 238u8, 12u8, 114u8, 8u8, ], ) } @@ -7128,12 +7024,10 @@ pub mod api { ], ) } - #[doc = "Schedule a named task."] pub fn schedule_named( &self, id: types::schedule_named::Id, when: types::schedule_named::When, - maybe_periodic: types::schedule_named::MaybePeriodic, priority: types::schedule_named::Priority, call: types::schedule_named::Call, ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload @@ -7144,14 +7038,13 @@ pub mod api { types::ScheduleNamed { id, when, - maybe_periodic, priority, call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 13u8, 254u8, 63u8, 126u8, 76u8, 11u8, 93u8, 141u8, 57u8, 125u8, 141u8, - 225u8, 225u8, 5u8, 181u8, 28u8, 1u8, 94u8, 156u8, 234u8, 29u8, 214u8, - 124u8, 169u8, 128u8, 135u8, 70u8, 217u8, 50u8, 249u8, 178u8, 84u8, + 132u8, 98u8, 238u8, 26u8, 202u8, 171u8, 103u8, 75u8, 126u8, 49u8, 0u8, + 201u8, 239u8, 60u8, 78u8, 218u8, 23u8, 147u8, 136u8, 131u8, 252u8, + 205u8, 89u8, 30u8, 83u8, 236u8, 25u8, 10u8, 149u8, 147u8, 56u8, 207u8, ], ) } @@ -7171,11 +7064,9 @@ pub mod api { ], ) } - #[doc = "Anonymously schedule a task after a delay."] pub fn schedule_after( &self, after: types::schedule_after::After, - maybe_periodic: types::schedule_after::MaybePeriodic, priority: types::schedule_after::Priority, call: types::schedule_after::Call, ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload @@ -7185,23 +7076,21 @@ pub mod api { "schedule_after", types::ScheduleAfter { after, - maybe_periodic, priority, call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 162u8, 125u8, 219u8, 73u8, 158u8, 117u8, 43u8, 87u8, 203u8, 66u8, 70u8, - 2u8, 216u8, 81u8, 36u8, 114u8, 236u8, 161u8, 11u8, 154u8, 173u8, 97u8, - 75u8, 215u8, 178u8, 154u8, 37u8, 132u8, 100u8, 230u8, 188u8, 208u8, + 123u8, 115u8, 44u8, 60u8, 131u8, 182u8, 245u8, 36u8, 29u8, 238u8, + 226u8, 239u8, 76u8, 4u8, 170u8, 52u8, 245u8, 83u8, 217u8, 193u8, 100u8, + 58u8, 144u8, 126u8, 232u8, 17u8, 219u8, 120u8, 99u8, 154u8, 255u8, + 116u8, ], ) } - #[doc = "Schedule a named task after a delay."] pub fn schedule_named_after( &self, id: types::schedule_named_after::Id, after: types::schedule_named_after::After, - maybe_periodic: types::schedule_named_after::MaybePeriodic, priority: types::schedule_named_after::Priority, call: types::schedule_named_after::Call, ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload @@ -7212,15 +7101,13 @@ pub mod api { types::ScheduleNamedAfter { id, after, - maybe_periodic, priority, call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 139u8, 221u8, 152u8, 183u8, 20u8, 207u8, 141u8, 46u8, 8u8, 172u8, - 154u8, 85u8, 106u8, 139u8, 217u8, 12u8, 190u8, 12u8, 4u8, 225u8, 103u8, - 127u8, 84u8, 158u8, 131u8, 218u8, 175u8, 114u8, 135u8, 111u8, 154u8, - 173u8, + 51u8, 123u8, 141u8, 168u8, 243u8, 27u8, 146u8, 86u8, 92u8, 47u8, 205u8, + 24u8, 66u8, 124u8, 97u8, 95u8, 171u8, 35u8, 140u8, 188u8, 58u8, 138u8, + 115u8, 200u8, 132u8, 253u8, 68u8, 16u8, 112u8, 132u8, 121u8, 68u8, ], ) } @@ -7229,10 +7116,9 @@ pub mod api { #[doc = "succeeds."] #[doc = ""] #[doc = "Tasks which need to be scheduled for a retry are still subject to weight metering and"] - #[doc = "agenda space, same as a regular task. If a periodic task fails, it will be scheduled"] - #[doc = "normally while the task is retrying."] + #[doc = "agenda space, same as a regular task."] #[doc = ""] - #[doc = "Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic"] + #[doc = "Tasks scheduled as a result of a retry are unnamed"] #[doc = "clones of the original task. Their retry configuration will be derived from the"] #[doc = "original task's configuration, but will have a lower value for `remaining` than the"] #[doc = "original `total_retries`."] @@ -7258,10 +7144,9 @@ pub mod api { #[doc = "it succeeds."] #[doc = ""] #[doc = "Tasks which need to be scheduled for a retry are still subject to weight metering and"] - #[doc = "agenda space, same as a regular task. If a periodic task fails, it will be scheduled"] - #[doc = "normally while the task is retrying."] + #[doc = "agenda space, same as a regular task."] #[doc = ""] - #[doc = "Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic"] + #[doc = "Tasks scheduled as a result of a retry are unnamed"] #[doc = "clones of the original task. Their retry configuration will be derived from the"] #[doc = "original task's configuration, but will have a lower value for `remaining` than the"] #[doc = "original `total_retries`."] @@ -7497,33 +7382,6 @@ pub mod api { )] #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "The given task was unable to be renewed since the agenda is full at that block."] - pub struct PeriodicFailed { - pub task: periodic_failed::Task, - pub id: periodic_failed::Id, - } - pub mod periodic_failed { - use super::runtime_types; - pub type Task = ( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - ); - pub type Id = ::core::option::Option<[::core::primitive::u8; 32usize]>; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for PeriodicFailed { - const PALLET: &'static str = "Scheduler"; - const EVENT: &'static str = "PeriodicFailed"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] #[doc = "The given task was unable to be retried since the agenda is full at that block or there"] #[doc = "was not enough weight to reschedule it."] pub struct RetryFailed { @@ -7721,9 +7579,10 @@ pub mod api { "Agenda", (), [ - 167u8, 175u8, 28u8, 224u8, 44u8, 149u8, 114u8, 12u8, 119u8, 107u8, - 50u8, 64u8, 173u8, 39u8, 48u8, 85u8, 151u8, 68u8, 15u8, 145u8, 182u8, - 105u8, 30u8, 18u8, 132u8, 11u8, 249u8, 54u8, 47u8, 73u8, 51u8, 49u8, + 30u8, 205u8, 116u8, 231u8, 62u8, 200u8, 225u8, 69u8, 50u8, 106u8, + 175u8, 47u8, 182u8, 175u8, 231u8, 114u8, 176u8, 58u8, 24u8, 230u8, + 81u8, 228u8, 217u8, 72u8, 171u8, 222u8, 251u8, 218u8, 73u8, 28u8, + 239u8, 137u8, ], ) } @@ -7745,9 +7604,10 @@ pub mod api { "Agenda", ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), [ - 167u8, 175u8, 28u8, 224u8, 44u8, 149u8, 114u8, 12u8, 119u8, 107u8, - 50u8, 64u8, 173u8, 39u8, 48u8, 85u8, 151u8, 68u8, 15u8, 145u8, 182u8, - 105u8, 30u8, 18u8, 132u8, 11u8, 249u8, 54u8, 47u8, 73u8, 51u8, 49u8, + 30u8, 205u8, 116u8, 231u8, 62u8, 200u8, 225u8, 69u8, 50u8, 106u8, + 175u8, 47u8, 182u8, 175u8, 231u8, 114u8, 176u8, 58u8, 24u8, 230u8, + 81u8, 228u8, 217u8, 72u8, 171u8, 222u8, 251u8, 218u8, 73u8, 28u8, + 239u8, 137u8, ], ) } @@ -7799,9 +7659,6 @@ pub mod api { ) } #[doc = " Lookup from a name to the block number and index of the task."] - #[doc = ""] - #[doc = " For v3 -> v4 the previously unbounded identities are Blake2-256 hashed to form the v4"] - #[doc = " identities."] pub fn lookup_iter( &self, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< @@ -7823,9 +7680,6 @@ pub mod api { ) } #[doc = " Lookup from a name to the block number and index of the task."] - #[doc = ""] - #[doc = " For v3 -> v4 the previously unbounded identities are Blake2-256 hashed to form the v4"] - #[doc = " identities."] pub fn lookup( &self, _0: types::lookup::Param0, @@ -8248,9 +8102,9 @@ pub mod api { "batch", types::Batch { calls }, [ - 218u8, 227u8, 88u8, 252u8, 144u8, 164u8, 107u8, 191u8, 4u8, 6u8, 242u8, - 220u8, 160u8, 117u8, 131u8, 23u8, 30u8, 44u8, 210u8, 225u8, 129u8, - 119u8, 42u8, 236u8, 42u8, 77u8, 133u8, 77u8, 167u8, 238u8, 189u8, 18u8, + 175u8, 251u8, 47u8, 139u8, 42u8, 213u8, 29u8, 121u8, 126u8, 160u8, + 31u8, 182u8, 18u8, 35u8, 57u8, 165u8, 44u8, 5u8, 237u8, 46u8, 120u8, + 177u8, 32u8, 135u8, 177u8, 20u8, 87u8, 229u8, 64u8, 13u8, 127u8, 38u8, ], ) } @@ -8280,10 +8134,10 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 61u8, 204u8, 36u8, 196u8, 16u8, 224u8, 252u8, 119u8, 160u8, 206u8, - 178u8, 6u8, 162u8, 252u8, 50u8, 119u8, 243u8, 74u8, 88u8, 93u8, 168u8, - 135u8, 247u8, 31u8, 113u8, 228u8, 106u8, 61u8, 76u8, 137u8, 49u8, - 152u8, + 163u8, 103u8, 246u8, 62u8, 75u8, 102u8, 59u8, 101u8, 118u8, 106u8, + 209u8, 68u8, 186u8, 60u8, 209u8, 233u8, 79u8, 179u8, 41u8, 65u8, 154u8, + 146u8, 145u8, 126u8, 183u8, 212u8, 239u8, 26u8, 76u8, 22u8, 239u8, + 228u8, ], ) } @@ -8309,9 +8163,9 @@ pub mod api { "batch_all", types::BatchAll { calls }, [ - 95u8, 55u8, 212u8, 217u8, 21u8, 7u8, 172u8, 181u8, 131u8, 146u8, 194u8, - 179u8, 219u8, 165u8, 223u8, 70u8, 125u8, 117u8, 103u8, 207u8, 97u8, - 4u8, 2u8, 153u8, 7u8, 107u8, 218u8, 218u8, 238u8, 159u8, 132u8, 169u8, + 150u8, 227u8, 254u8, 10u8, 63u8, 29u8, 209u8, 16u8, 78u8, 200u8, 2u8, + 1u8, 45u8, 134u8, 126u8, 227u8, 213u8, 206u8, 28u8, 11u8, 248u8, 34u8, + 208u8, 245u8, 115u8, 226u8, 51u8, 80u8, 157u8, 19u8, 214u8, 7u8, ], ) } @@ -8334,9 +8188,10 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 45u8, 253u8, 46u8, 68u8, 166u8, 17u8, 170u8, 35u8, 107u8, 183u8, 69u8, - 167u8, 62u8, 147u8, 100u8, 67u8, 144u8, 182u8, 141u8, 227u8, 20u8, - 175u8, 1u8, 229u8, 103u8, 16u8, 162u8, 14u8, 144u8, 57u8, 62u8, 154u8, + 26u8, 167u8, 149u8, 52u8, 49u8, 181u8, 232u8, 189u8, 214u8, 103u8, + 142u8, 80u8, 167u8, 149u8, 40u8, 66u8, 198u8, 220u8, 22u8, 169u8, + 249u8, 194u8, 40u8, 241u8, 212u8, 216u8, 96u8, 42u8, 107u8, 229u8, + 250u8, 169u8, ], ) } @@ -8362,9 +8217,9 @@ pub mod api { "force_batch", types::ForceBatch { calls }, [ - 143u8, 1u8, 248u8, 160u8, 18u8, 153u8, 38u8, 72u8, 212u8, 148u8, 146u8, - 7u8, 79u8, 129u8, 146u8, 207u8, 173u8, 174u8, 48u8, 237u8, 195u8, 6u8, - 40u8, 26u8, 146u8, 94u8, 85u8, 89u8, 187u8, 161u8, 10u8, 186u8, + 214u8, 226u8, 85u8, 46u8, 75u8, 28u8, 254u8, 199u8, 162u8, 194u8, + 192u8, 69u8, 103u8, 7u8, 126u8, 201u8, 242u8, 24u8, 85u8, 53u8, 69u8, + 91u8, 182u8, 111u8, 205u8, 250u8, 109u8, 233u8, 52u8, 9u8, 171u8, 11u8, ], ) } @@ -8387,9 +8242,9 @@ pub mod api { weight, }, [ - 45u8, 178u8, 212u8, 106u8, 190u8, 63u8, 70u8, 5u8, 15u8, 114u8, 128u8, - 212u8, 20u8, 232u8, 8u8, 28u8, 100u8, 12u8, 94u8, 250u8, 250u8, 221u8, - 169u8, 206u8, 52u8, 75u8, 152u8, 194u8, 133u8, 223u8, 85u8, 213u8, + 164u8, 25u8, 18u8, 51u8, 125u8, 4u8, 172u8, 80u8, 236u8, 99u8, 192u8, + 159u8, 103u8, 231u8, 83u8, 188u8, 32u8, 54u8, 11u8, 101u8, 127u8, 14u8, + 78u8, 134u8, 146u8, 112u8, 165u8, 108u8, 89u8, 10u8, 184u8, 131u8, ], ) } @@ -8429,9 +8284,10 @@ pub mod api { fallback: ::subxt::ext::subxt_core::alloc::boxed::Box::new(fallback), }, [ - 182u8, 227u8, 213u8, 214u8, 220u8, 74u8, 1u8, 211u8, 42u8, 249u8, - 237u8, 97u8, 126u8, 112u8, 93u8, 63u8, 5u8, 120u8, 216u8, 157u8, 132u8, - 123u8, 231u8, 38u8, 7u8, 139u8, 15u8, 126u8, 104u8, 63u8, 54u8, 76u8, + 92u8, 81u8, 197u8, 222u8, 38u8, 170u8, 79u8, 51u8, 116u8, 62u8, 50u8, + 58u8, 150u8, 250u8, 110u8, 71u8, 27u8, 159u8, 43u8, 203u8, 156u8, + 187u8, 239u8, 196u8, 87u8, 161u8, 156u8, 23u8, 146u8, 234u8, 101u8, + 3u8, ], ) } @@ -8454,9 +8310,9 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 209u8, 114u8, 253u8, 16u8, 26u8, 99u8, 196u8, 135u8, 161u8, 52u8, 48u8, - 224u8, 235u8, 129u8, 247u8, 215u8, 88u8, 253u8, 178u8, 0u8, 82u8, - 173u8, 148u8, 199u8, 98u8, 250u8, 50u8, 6u8, 106u8, 190u8, 52u8, 214u8, + 130u8, 99u8, 92u8, 78u8, 42u8, 115u8, 255u8, 247u8, 224u8, 97u8, 137u8, + 129u8, 227u8, 245u8, 204u8, 255u8, 128u8, 231u8, 43u8, 191u8, 72u8, + 241u8, 154u8, 16u8, 23u8, 72u8, 130u8, 40u8, 219u8, 191u8, 118u8, 34u8, ], ) } @@ -10123,6 +9979,8 @@ pub mod api { #[doc = "account by transferring the entire balance to themselves."] #[doc = ""] #[doc = "This is an emergency function for when the high security account may be compromised."] + #[doc = "It cancels all pending transfers first (applying volume fees), then transfers"] + #[doc = "the remaining free balance to the guardian."] pub struct RecoverFunds { pub account: recover_funds::Account, } @@ -10297,6 +10155,8 @@ pub mod api { #[doc = "account by transferring the entire balance to themselves."] #[doc = ""] #[doc = "This is an emergency function for when the high security account may be compromised."] + #[doc = "It cancels all pending transfers first (applying volume fees), then transfers"] + #[doc = "the remaining free balance to the guardian."] pub fn recover_funds( &self, account: types::recover_funds::Account, @@ -10479,11 +10339,6 @@ pub mod api { >; pub type Param0 = ::subxt::ext::subxt_core::utils::H256; } - pub mod account_pending_index { - use super::runtime_types; - pub type AccountPendingIndex = ::core::primitive::u32; - pub type Param0 = ::subxt::ext::subxt_core::utils::AccountId32; - } pub mod pending_transfers_by_sender { use super::runtime_types; pub type PendingTransfersBySender = @@ -10492,14 +10347,6 @@ pub mod api { >; pub type Param0 = ::subxt::ext::subxt_core::utils::AccountId32; } - pub mod pending_transfers_by_recipient { - use super::runtime_types; - pub type PendingTransfersByRecipient = - runtime_types::bounded_collections::bounded_vec::BoundedVec< - ::subxt::ext::subxt_core::utils::H256, - >; - pub type Param0 = ::subxt::ext::subxt_core::utils::AccountId32; - } pub mod interceptor_index { use super::runtime_types; pub type InterceptorIndex = @@ -10611,57 +10458,7 @@ pub mod api { ], ) } - #[doc = " Indexes pending transaction IDs per account for efficient lookup and cancellation."] - #[doc = " Also enforces the maximum pending transactions limit per account."] - pub fn account_pending_index_iter( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::account_pending_index::AccountPendingIndex, - (), - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "ReversibleTransfers", - "AccountPendingIndex", - (), - [ - 142u8, 255u8, 15u8, 41u8, 210u8, 84u8, 93u8, 230u8, 194u8, 31u8, 164u8, - 88u8, 155u8, 106u8, 130u8, 110u8, 199u8, 137u8, 153u8, 99u8, 154u8, - 210u8, 108u8, 136u8, 70u8, 141u8, 242u8, 255u8, 246u8, 19u8, 247u8, - 136u8, - ], - ) - } - #[doc = " Indexes pending transaction IDs per account for efficient lookup and cancellation."] - #[doc = " Also enforces the maximum pending transactions limit per account."] - pub fn account_pending_index( - &self, - _0: types::account_pending_index::Param0, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::account_pending_index::Param0, - >, - types::account_pending_index::AccountPendingIndex, - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "ReversibleTransfers", - "AccountPendingIndex", - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - [ - 142u8, 255u8, 15u8, 41u8, 210u8, 84u8, 93u8, 230u8, 194u8, 31u8, 164u8, - 88u8, 155u8, 106u8, 130u8, 110u8, 199u8, 137u8, 153u8, 99u8, 154u8, - 210u8, 108u8, 136u8, 70u8, 141u8, 242u8, 255u8, 246u8, 19u8, 247u8, - 136u8, - ], - ) - } #[doc = " Maps sender accounts to their list of pending transaction IDs."] - #[doc = " This allows users to query all their outgoing pending transfers."] pub fn pending_transfers_by_sender_iter( &self, ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< @@ -10683,7 +10480,6 @@ pub mod api { ) } #[doc = " Maps sender accounts to their list of pending transaction IDs."] - #[doc = " This allows users to query all their outgoing pending transfers."] pub fn pending_transfers_by_sender( &self, _0: types::pending_transfers_by_sender::Param0, @@ -10707,55 +10503,6 @@ pub mod api { ], ) } - #[doc = " Maps recipient accounts to their list of pending incoming transaction IDs."] - #[doc = " This allows users to query all their incoming pending transfers."] - pub fn pending_transfers_by_recipient_iter( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::pending_transfers_by_recipient::PendingTransfersByRecipient, - (), - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "ReversibleTransfers", - "PendingTransfersByRecipient", - (), - [ - 63u8, 141u8, 24u8, 239u8, 201u8, 143u8, 36u8, 152u8, 35u8, 110u8, - 112u8, 157u8, 29u8, 61u8, 221u8, 79u8, 209u8, 192u8, 183u8, 29u8, - 145u8, 166u8, 238u8, 156u8, 131u8, 203u8, 124u8, 233u8, 210u8, 201u8, - 91u8, 212u8, - ], - ) - } - #[doc = " Maps recipient accounts to their list of pending incoming transaction IDs."] - #[doc = " This allows users to query all their incoming pending transfers."] - pub fn pending_transfers_by_recipient( - &self, - _0: types::pending_transfers_by_recipient::Param0, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - ::subxt::ext::subxt_core::storage::address::StaticStorageKey< - types::pending_transfers_by_recipient::Param0, - >, - types::pending_transfers_by_recipient::PendingTransfersByRecipient, - ::subxt::ext::subxt_core::utils::Yes, - ::subxt::ext::subxt_core::utils::Yes, - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "ReversibleTransfers", - "PendingTransfersByRecipient", - ::subxt::ext::subxt_core::storage::address::StaticStorageKey::new(_0), - [ - 63u8, 141u8, 24u8, 239u8, 201u8, 143u8, 36u8, 152u8, 35u8, 110u8, - 112u8, 157u8, 29u8, 61u8, 221u8, 79u8, 209u8, 192u8, 183u8, 29u8, - 145u8, 166u8, 238u8, 156u8, 131u8, 203u8, 124u8, 233u8, 210u8, 201u8, - 91u8, 212u8, - ], - ) - } #[doc = " Maps interceptor accounts to the list of accounts they can intercept for."] #[doc = " This allows the UI to efficiently query all accounts for which a given account is an"] #[doc = " interceptor."] @@ -10834,15 +10581,15 @@ pub mod api { use super::runtime_types; pub struct ConstantsApi; impl ConstantsApi { - #[doc = " Maximum pending reversible transactions allowed per account. Used for BoundedVec."] - pub fn max_pending_per_account( + #[doc = " Maximum number of accounts an interceptor can intercept for. Used for BoundedVec."] + pub fn max_interceptor_accounts( &self, ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< ::core::primitive::u32, > { ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( "ReversibleTransfers", - "MaxPendingPerAccount", + "MaxInterceptorAccounts", [ 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, @@ -10851,15 +10598,15 @@ pub mod api { ], ) } - #[doc = " Maximum number of accounts an interceptor can intercept for. Used for BoundedVec."] - pub fn max_interceptor_accounts( + #[doc = " Maximum pending reversible transactions allowed per account."] + pub fn max_pending_per_account( &self, ) -> ::subxt::ext::subxt_core::constants::address::StaticAddress< ::core::primitive::u32, > { ::subxt::ext::subxt_core::constants::address::StaticAddress::new_static( "ReversibleTransfers", - "MaxInterceptorAccounts", + "MaxPendingPerAccount", [ 98u8, 252u8, 116u8, 72u8, 26u8, 180u8, 225u8, 83u8, 200u8, 157u8, 125u8, 151u8, 53u8, 76u8, 168u8, 26u8, 10u8, 9u8, 98u8, 68u8, 9u8, @@ -14555,10 +14302,10 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 74u8, 28u8, 170u8, 7u8, 84u8, 125u8, 208u8, 229u8, 206u8, 35u8, 213u8, - 58u8, 187u8, 211u8, 153u8, 234u8, 193u8, 109u8, 97u8, 114u8, 59u8, - 238u8, 20u8, 171u8, 27u8, 139u8, 40u8, 12u8, 219u8, 199u8, 220u8, - 245u8, + 138u8, 215u8, 99u8, 222u8, 139u8, 128u8, 44u8, 8u8, 70u8, 23u8, 174u8, + 102u8, 142u8, 62u8, 176u8, 98u8, 216u8, 41u8, 138u8, 101u8, 201u8, + 105u8, 99u8, 164u8, 144u8, 176u8, 94u8, 228u8, 191u8, 175u8, 145u8, + 30u8, ], ) } @@ -19522,10 +19269,8 @@ pub mod api { #[doc = "- A deposit (refundable - returned immediately on execution/cancellation)"] #[doc = "- A fee (non-refundable, burned immediately)"] #[doc = ""] - #[doc = "**Auto-cleanup:** Before creating a new proposal, ALL proposer's expired"] - #[doc = "proposals are automatically removed. This is the primary cleanup mechanism."] - #[doc = ""] - #[doc = "**For threshold=1:** If the multisig threshold is 1, the proposal executes immediately."] + #[doc = "**For threshold=1:** The proposal is created with `Approved` status immediately"] + #[doc = "and can be executed via `execute()` without additional approvals."] #[doc = ""] #[doc = "**Weight:** Charged upfront for worst-case (high-security path with decode)."] #[doc = "Refunded to actual cost on success based on whether HS path was taken."] @@ -19622,11 +19367,14 @@ pub mod api { #[doc = "Remove expired proposals and return deposits to proposers"] #[doc = ""] #[doc = "Can only be called by signers of the multisig."] - #[doc = "Only removes Active proposals that have expired (past expiry block)."] + #[doc = "Removes Active or Approved proposals that have expired (past expiry block)."] #[doc = "Executed and Cancelled proposals are automatically cleaned up immediately."] #[doc = ""] + #[doc = "Approved+expired proposals can become stuck if proposer is unavailable (e.g. lost"] + #[doc = "keys, compromise). Allowing any signer to remove them prevents permanent deposit"] + #[doc = "lockup and enables multisig dissolution."] + #[doc = ""] #[doc = "The deposit is always returned to the original proposer, not the caller."] - #[doc = "This allows any signer to help clean up storage even if proposer is inactive."] pub struct RemoveExpired { pub multisig_address: remove_expired::MultisigAddress, pub proposal_id: remove_expired::ProposalId, @@ -19655,10 +19403,10 @@ pub mod api { #[doc = ""] #[doc = "This is a batch operation that removes all expired proposals where:"] #[doc = "- Caller is the proposer"] - #[doc = "- Proposal is Active and past expiry block"] + #[doc = "- Proposal is Active or Approved and past expiry block"] #[doc = ""] #[doc = "Note: Executed and Cancelled proposals are automatically cleaned up immediately,"] - #[doc = "so only Active+Expired proposals need manual cleanup."] + #[doc = "so only Active+Expired and Approved+Expired proposals need manual cleanup."] #[doc = ""] #[doc = "Returns all proposal deposits to the proposer in a single transaction."] pub struct ClaimDeposits { @@ -19792,10 +19540,8 @@ pub mod api { #[doc = "- A deposit (refundable - returned immediately on execution/cancellation)"] #[doc = "- A fee (non-refundable, burned immediately)"] #[doc = ""] - #[doc = "**Auto-cleanup:** Before creating a new proposal, ALL proposer's expired"] - #[doc = "proposals are automatically removed. This is the primary cleanup mechanism."] - #[doc = ""] - #[doc = "**For threshold=1:** If the multisig threshold is 1, the proposal executes immediately."] + #[doc = "**For threshold=1:** The proposal is created with `Approved` status immediately"] + #[doc = "and can be executed via `execute()` without additional approvals."] #[doc = ""] #[doc = "**Weight:** Charged upfront for worst-case (high-security path with decode)."] #[doc = "Refunded to actual cost on success based on whether HS path was taken."] @@ -19867,11 +19613,14 @@ pub mod api { #[doc = "Remove expired proposals and return deposits to proposers"] #[doc = ""] #[doc = "Can only be called by signers of the multisig."] - #[doc = "Only removes Active proposals that have expired (past expiry block)."] + #[doc = "Removes Active or Approved proposals that have expired (past expiry block)."] #[doc = "Executed and Cancelled proposals are automatically cleaned up immediately."] #[doc = ""] + #[doc = "Approved+expired proposals can become stuck if proposer is unavailable (e.g. lost"] + #[doc = "keys, compromise). Allowing any signer to remove them prevents permanent deposit"] + #[doc = "lockup and enables multisig dissolution."] + #[doc = ""] #[doc = "The deposit is always returned to the original proposer, not the caller."] - #[doc = "This allows any signer to help clean up storage even if proposer is inactive."] pub fn remove_expired( &self, multisig_address: types::remove_expired::MultisigAddress, @@ -19893,10 +19642,10 @@ pub mod api { #[doc = ""] #[doc = "This is a batch operation that removes all expired proposals where:"] #[doc = "- Caller is the proposer"] - #[doc = "- Proposal is Active and past expiry block"] + #[doc = "- Proposal is Active or Approved and past expiry block"] #[doc = ""] #[doc = "Note: Executed and Cancelled proposals are automatically cleaned up immediately,"] - #[doc = "so only Active+Expired proposals need manual cleanup."] + #[doc = "so only Active+Expired and Approved+Expired proposals need manual cleanup."] #[doc = ""] #[doc = "Returns all proposal deposits to the proposer in a single transaction."] pub fn claim_deposits( @@ -24068,10 +23817,8 @@ pub mod api { #[doc = "- A deposit (refundable - returned immediately on execution/cancellation)"] #[doc = "- A fee (non-refundable, burned immediately)"] #[doc = ""] - #[doc = "**Auto-cleanup:** Before creating a new proposal, ALL proposer's expired"] - #[doc = "proposals are automatically removed. This is the primary cleanup mechanism."] - #[doc = ""] - #[doc = "**For threshold=1:** If the multisig threshold is 1, the proposal executes immediately."] + #[doc = "**For threshold=1:** The proposal is created with `Approved` status immediately"] + #[doc = "and can be executed via `execute()` without additional approvals."] #[doc = ""] #[doc = "**Weight:** Charged upfront for worst-case (high-security path with decode)."] #[doc = "Refunded to actual cost on success based on whether HS path was taken."] @@ -24109,11 +23856,14 @@ pub mod api { #[doc = "Remove expired proposals and return deposits to proposers"] #[doc = ""] #[doc = "Can only be called by signers of the multisig."] - #[doc = "Only removes Active proposals that have expired (past expiry block)."] + #[doc = "Removes Active or Approved proposals that have expired (past expiry block)."] #[doc = "Executed and Cancelled proposals are automatically cleaned up immediately."] #[doc = ""] + #[doc = "Approved+expired proposals can become stuck if proposer is unavailable (e.g. lost"] + #[doc = "keys, compromise). Allowing any signer to remove them prevents permanent deposit"] + #[doc = "lockup and enables multisig dissolution."] + #[doc = ""] #[doc = "The deposit is always returned to the original proposer, not the caller."] - #[doc = "This allows any signer to help clean up storage even if proposer is inactive."] remove_expired { multisig_address: ::subxt::ext::subxt_core::utils::AccountId32, proposal_id: ::core::primitive::u32, @@ -24123,10 +23873,10 @@ pub mod api { #[doc = ""] #[doc = "This is a batch operation that removes all expired proposals where:"] #[doc = "- Caller is the proposer"] - #[doc = "- Proposal is Active and past expiry block"] + #[doc = "- Proposal is Active or Approved and past expiry block"] #[doc = ""] #[doc = "Note: Executed and Cancelled proposals are automatically cleaned up immediately,"] - #[doc = "so only Active+Expired proposals need manual cleanup."] + #[doc = "so only Active+Expired and Approved+Expired proposals need manual cleanup."] #[doc = ""] #[doc = "Returns all proposal deposits to the proposer in a single transaction."] claim_deposits { @@ -25920,6 +25670,8 @@ pub mod api { #[doc = "account by transferring the entire balance to themselves."] #[doc = ""] #[doc = "This is an emergency function for when the high security account may be compromised."] + #[doc = "It cancels all pending transfers first (applying volume fees), then transfers"] + #[doc = "the remaining free balance to the guardian."] recover_funds { account: ::subxt::ext::subxt_core::utils::AccountId32 }, } #[derive( @@ -26108,16 +25860,8 @@ pub mod api { #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] pub enum Call { #[codec(index = 0)] - #[doc = "Anonymously schedule a task."] schedule { when: ::core::primitive::u32, - maybe_periodic: ::core::option::Option<( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - )>, priority: ::core::primitive::u8, call: ::subxt::ext::subxt_core::alloc::boxed::Box< runtime_types::quantus_runtime::RuntimeCall, @@ -26133,17 +25877,9 @@ pub mod api { index: ::core::primitive::u32, }, #[codec(index = 2)] - #[doc = "Schedule a named task."] schedule_named { id: [::core::primitive::u8; 32usize], when: ::core::primitive::u32, - maybe_periodic: ::core::option::Option<( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - )>, priority: ::core::primitive::u8, call: ::subxt::ext::subxt_core::alloc::boxed::Box< runtime_types::quantus_runtime::RuntimeCall, @@ -26153,39 +25889,23 @@ pub mod api { #[doc = "Cancel a named scheduled task."] cancel_named { id: [::core::primitive::u8; 32usize] }, #[codec(index = 4)] - #[doc = "Anonymously schedule a task after a delay."] schedule_after { after: runtime_types::qp_scheduler::BlockNumberOrTimestamp< ::core::primitive::u32, ::core::primitive::u64, >, - maybe_periodic: ::core::option::Option<( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - )>, priority: ::core::primitive::u8, call: ::subxt::ext::subxt_core::alloc::boxed::Box< runtime_types::quantus_runtime::RuntimeCall, >, }, #[codec(index = 5)] - #[doc = "Schedule a named task after a delay."] schedule_named_after { id: [::core::primitive::u8; 32usize], after: runtime_types::qp_scheduler::BlockNumberOrTimestamp< ::core::primitive::u32, ::core::primitive::u64, >, - maybe_periodic: ::core::option::Option<( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - )>, priority: ::core::primitive::u8, call: ::subxt::ext::subxt_core::alloc::boxed::Box< runtime_types::quantus_runtime::RuntimeCall, @@ -26197,10 +25917,9 @@ pub mod api { #[doc = "succeeds."] #[doc = ""] #[doc = "Tasks which need to be scheduled for a retry are still subject to weight metering and"] - #[doc = "agenda space, same as a regular task. If a periodic task fails, it will be scheduled"] - #[doc = "normally while the task is retrying."] + #[doc = "agenda space, same as a regular task."] #[doc = ""] - #[doc = "Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic"] + #[doc = "Tasks scheduled as a result of a retry are unnamed"] #[doc = "clones of the original task. Their retry configuration will be derived from the"] #[doc = "original task's configuration, but will have a lower value for `remaining` than the"] #[doc = "original `total_retries`."] @@ -26224,10 +25943,9 @@ pub mod api { #[doc = "it succeeds."] #[doc = ""] #[doc = "Tasks which need to be scheduled for a retry are still subject to weight metering and"] - #[doc = "agenda space, same as a regular task. If a periodic task fails, it will be scheduled"] - #[doc = "normally while the task is retrying."] + #[doc = "agenda space, same as a regular task."] #[doc = ""] - #[doc = "Tasks scheduled as a result of a retry for a periodic task are unnamed, non-periodic"] + #[doc = "Tasks scheduled as a result of a retry are unnamed"] #[doc = "clones of the original task. Their retry configuration will be derived from the"] #[doc = "original task's configuration, but will have a lower value for `remaining` than the"] #[doc = "original `total_retries`."] @@ -26373,18 +26091,6 @@ pub mod api { id: ::core::option::Option<[::core::primitive::u8; 32usize]>, }, #[codec(index = 6)] - #[doc = "The given task was unable to be renewed since the agenda is full at that block."] - PeriodicFailed { - task: ( - runtime_types::qp_scheduler::BlockNumberOrTimestamp< - ::core::primitive::u32, - ::core::primitive::u64, - >, - ::core::primitive::u32, - ), - id: ::core::option::Option<[::core::primitive::u8; 32usize]>, - }, - #[codec(index = 7)] #[doc = "The given task was unable to be retried since the agenda is full at that block or there"] #[doc = "was not enough weight to reschedule it."] RetryFailed { @@ -26397,7 +26103,7 @@ pub mod api { ), id: ::core::option::Option<[::core::primitive::u8; 32usize]>, }, - #[codec(index = 8)] + #[codec(index = 7)] #[doc = "The given task can never be executed since it is overweight."] PermanentlyOverweight { task: ( @@ -26434,13 +26140,9 @@ pub mod api { pub maybe_id: ::core::option::Option<_0>, pub priority: ::core::primitive::u8, pub call: _1, - pub maybe_periodic: ::core::option::Option<( - runtime_types::qp_scheduler::BlockNumberOrTimestamp<_2, _5>, - _2, - )>, pub origin: _3, #[codec(skip)] - pub __ignore: ::core::marker::PhantomData<_4>, + pub __ignore: ::core::marker::PhantomData<(_4, _5, _2)>, } } pub mod pallet_sudo { @@ -27045,39 +26747,30 @@ pub mod api { #[doc = "The `Error` enum of this pallet."] pub enum Error { #[codec(index = 0)] - InvalidProof, - #[codec(index = 1)] - ProofDeserializationFailed, - #[codec(index = 2)] - VerificationFailed, - #[codec(index = 3)] InvalidPublicInputs, - #[codec(index = 4)] + #[codec(index = 1)] NullifierAlreadyUsed, - #[codec(index = 5)] + #[codec(index = 2)] VerifierNotAvailable, - #[codec(index = 6)] - InvalidStorageRoot, - #[codec(index = 7)] - StorageRootMismatch, - #[codec(index = 8)] + #[codec(index = 3)] BlockNotFound, - #[codec(index = 9)] - InvalidBlockNumber, - #[codec(index = 10)] + #[codec(index = 4)] AggregatedVerifierNotAvailable, - #[codec(index = 11)] + #[codec(index = 5)] AggregatedProofDeserializationFailed, - #[codec(index = 12)] + #[codec(index = 6)] AggregatedVerificationFailed, - #[codec(index = 13)] + #[codec(index = 7)] InvalidAggregatedPublicInputs, - #[codec(index = 14)] + #[codec(index = 8)] #[doc = "The volume fee rate in the proof doesn't match the configured rate"] InvalidVolumeFeeRate, - #[codec(index = 15)] + #[codec(index = 9)] #[doc = "Transfer amount is below the minimum required"] TransferAmountBelowMinimum, + #[codec(index = 10)] + #[doc = "Only native asset (asset_id = 0) is supported in this version"] + NonNativeAssetNotSupported, } #[derive( :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, diff --git a/src/cli/referenda.rs b/src/cli/referenda.rs index 04f4416..a1300e2 100644 --- a/src/cli/referenda.rs +++ b/src/cli/referenda.rs @@ -28,7 +28,7 @@ pub enum ReferendaCommands { #[arg(long)] password_file: Option, - /// Origin type: signed (default), none (for signaling track), root + /// Origin type: signed (default) or root #[arg(long, default_value = "signed")] origin: String, }, @@ -51,7 +51,7 @@ pub enum ReferendaCommands { #[arg(long)] password_file: Option, - /// Origin type: signed (default), none (for signaling track), root + /// Origin type: signed (default) or root #[arg(long, default_value = "signed")] origin: String, }, @@ -332,19 +332,18 @@ async fn submit_remark_proposal( ); quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin) }, - "none" => { - let raw_origin = - quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::None; - quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin) - }, "root" => { let raw_origin = quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::Root; quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin) }, + "none" => + return Err(QuantusError::Generic( + "Invalid origin type: none. Use 'signed' or 'root'.".to_string(), + )), _ => return Err(QuantusError::Generic(format!( - "Invalid origin type: {}. Must be 'signed', 'none', or 'root'", + "Invalid origin type: {}. Must be 'signed' or 'root'", origin_type ))), }; @@ -449,19 +448,18 @@ async fn submit_proposal( ); quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin) }, - "none" => { - let raw_origin = - quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::None; - quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin) - }, "root" => { let raw_origin = quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::Root; quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin) }, + "none" => + return Err(QuantusError::Generic( + "Invalid origin type: none. Use 'signed' or 'root'.".to_string(), + )), _ => return Err(QuantusError::Generic(format!( - "Invalid origin type: {}. Must be 'signed', 'none', or 'root'", + "Invalid origin type: {}. Must be 'signed' or 'root'", origin_type ))), }; @@ -720,12 +718,8 @@ async fn vote_on_referendum( let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; - // Parse amount - let amount_value: u128 = (amount - .parse::() - .map_err(|_| QuantusError::Generic("Invalid amount format".to_string()))? - .max(0.0) * - 1_000_000_000_000_000_000.0) as u128; + // Parse amount using chain decimals (12 for DEV) + let amount_value: u128 = crate::cli::send::parse_amount(quantus_client, amount).await?; // Validate conviction if conviction > 6 { diff --git a/src/cli/reversible.rs b/src/cli/reversible.rs index 63d5ed0..83940e5 100644 --- a/src/cli/reversible.rs +++ b/src/cli/reversible.rs @@ -389,11 +389,8 @@ async fn list_pending_transactions( // Determine which address to query let target_address = match (address, wallet_name) { (Some(addr), _) => { - // Validate the provided address - SpAccountId32::from_ss58check(&addr).map_err(|e| { - crate::error::QuantusError::Generic(format!("Invalid address: {e:?}")) - })?; - addr + // --address accepts SS58 or wallet name + resolve_address(&addr)? }, (None, Some(wallet)) => { // Load wallet and get its address @@ -416,105 +413,66 @@ async fn list_pending_transactions( log_verbose!("🔍 Querying pending transfers for: {}", target_address); - // Query pending transfers by sender (outgoing) - let sender_storage_address = crate::chain::quantus_subxt::api::storage() - .reversible_transfers() - .pending_transfers_by_sender(account_id.clone()); - - // Get the latest block hash to read from the latest state (not finalized) let latest_block_hash = quantus_client.get_latest_block().await?; - - let outgoing_transfers = quantus_client - .client() - .storage() - .at(latest_block_hash) - .fetch(&sender_storage_address) - .await - .map_err(|e| crate::error::QuantusError::NetworkError(format!("Fetch error: {e:?}")))?; - - // Query pending transfers by recipient (incoming) - let recipient_storage_address = crate::chain::quantus_subxt::api::storage() + let storage_at = quantus_client.client().storage().at(latest_block_hash); + let pending_iter = crate::chain::quantus_subxt::api::storage() .reversible_transfers() - .pending_transfers_by_recipient(account_id); + .pending_transfers_iter(); + + let mut outgoing = Vec::new(); + let mut incoming = Vec::new(); + let mut iter = storage_at.iter(pending_iter).await.map_err(|e| { + crate::error::QuantusError::NetworkError(format!("Storage iter error: {e:?}")) + })?; - let incoming_transfers = quantus_client - .client() - .storage() - .at(latest_block_hash) - .fetch(&recipient_storage_address) - .await - .map_err(|e| crate::error::QuantusError::NetworkError(format!("Fetch error: {e:?}")))?; + while let Some(result) = iter.next().await { + match result { + Ok(entry) => { + // Key is storage prefix + tx_id (H256, 32 bytes). Extract last 32 bytes. + let tx_id_hex = if entry.key_bytes.len() >= 32 { + hex::encode(&entry.key_bytes[entry.key_bytes.len() - 32..]) + } else { + hex::encode(&entry.key_bytes) + }; + let transfer = entry.value; + if transfer.from == account_id { + outgoing.push((tx_id_hex, transfer)); + } else if transfer.to == account_id { + incoming.push((tx_id_hex, transfer)); + } + }, + Err(e) => { + log_verbose!("âš ī¸ Error reading pending transfer: {:?}", e); + }, + } + } let mut total_transfers = 0; - // Display outgoing transfers - if let Some(outgoing_hashes) = outgoing_transfers { - if !outgoing_hashes.0.is_empty() { - log_print!("📤 Outgoing pending transfers:"); - for (i, hash) in outgoing_hashes.0.iter().enumerate() { - total_transfers += 1; - log_print!(" {}. 0x{}", i + 1, hex::encode(hash.as_ref())); - - // Try to get transfer details - let transfer_storage_address = crate::chain::quantus_subxt::api::storage() - .reversible_transfers() - .pending_transfers(*hash); - - if let Ok(Some(transfer_details)) = quantus_client - .client() - .storage() - .at(latest_block_hash) - .fetch(&transfer_storage_address) - .await - .map_err(|e| { - crate::error::QuantusError::NetworkError(format!("Fetch error: {e:?}")) - }) { - let formatted_amount = format_amount(transfer_details.amount); - log_print!(" 👤 To: {}", transfer_details.to.to_quantus_ss58()); - log_print!(" 💰 Amount: {}", formatted_amount); - log_print!( - " 🔄 Interceptor: {}", - transfer_details.interceptor.to_quantus_ss58() - ); - } - } + if !outgoing.is_empty() { + log_print!("📤 Outgoing pending transfers:"); + for (i, (tx_id_hex, transfer)) in outgoing.iter().enumerate() { + total_transfers += 1; + log_print!(" {}. 0x{}", i + 1, tx_id_hex); + let formatted_amount = format_amount(transfer.amount); + log_print!(" 👤 To: {}", transfer.to.to_quantus_ss58()); + log_print!(" 💰 Amount: {}", formatted_amount); + log_print!(" 🔄 Interceptor: {}", transfer.interceptor.to_quantus_ss58()); } } - // Display incoming transfers - if let Some(incoming_hashes) = incoming_transfers { - if !incoming_hashes.0.is_empty() { - if total_transfers > 0 { - log_print!(""); - } - log_print!("đŸ“Ĩ Incoming pending transfers:"); - for (i, hash) in incoming_hashes.0.iter().enumerate() { - total_transfers += 1; - log_print!(" {}. 0x{}", i + 1, hex::encode(hash.as_ref())); - - // Try to get transfer details - let transfer_storage_address = crate::chain::quantus_subxt::api::storage() - .reversible_transfers() - .pending_transfers(*hash); - - if let Ok(Some(transfer_details)) = quantus_client - .client() - .storage() - .at(latest_block_hash) - .fetch(&transfer_storage_address) - .await - .map_err(|e| { - crate::error::QuantusError::NetworkError(format!("Fetch error: {e:?}")) - }) { - let formatted_amount = format_amount(transfer_details.amount); - log_print!(" 👤 From: {}", transfer_details.from.to_quantus_ss58()); - log_print!(" 💰 Amount: {}", formatted_amount); - log_print!( - " 🔄 Interceptor: {}", - transfer_details.interceptor.to_quantus_ss58() - ); - } - } + if !incoming.is_empty() { + if total_transfers > 0 { + log_print!(""); + } + log_print!("đŸ“Ĩ Incoming pending transfers:"); + for (i, (tx_id_hex, transfer)) in incoming.iter().enumerate() { + total_transfers += 1; + log_print!(" {}. 0x{}", i + 1, tx_id_hex); + let formatted_amount = format_amount(transfer.amount); + log_print!(" 👤 From: {}", transfer.from.to_quantus_ss58()); + log_print!(" 💰 Amount: {}", formatted_amount); + log_print!(" 🔄 Interceptor: {}", transfer.interceptor.to_quantus_ss58()); } } diff --git a/src/cli/scheduler.rs b/src/cli/scheduler.rs index e89a1cd..89055f0 100644 --- a/src/cli/scheduler.rs +++ b/src/cli/scheduler.rs @@ -121,13 +121,11 @@ async fn schedule_remark( // When: after N blocks (u32) let when_u32: u32 = after; - let maybe_periodic = None; let priority: u8 = 0; // Submit schedule extrinsic let keypair = crate::wallet::load_keypair_from_wallet(from, None, None)?; - let schedule_tx = - api::tx().scheduler().schedule(when_u32, maybe_periodic, priority, runtime_call); + let schedule_tx = api::tx().scheduler().schedule(when_u32, priority, runtime_call); let tx_hash = crate::cli::common::submit_transaction( quantus_client, &keypair, diff --git a/src/cli/wallet.rs b/src/cli/wallet.rs index ea636a9..703b52d 100644 --- a/src/cli/wallet.rs +++ b/src/cli/wallet.rs @@ -240,28 +240,43 @@ async fn fetch_pending_transfers_for_guardian( ) -> crate::error::Result<(u32, Vec<(String, u32)>)> { let latest = quantus_client.get_latest_block().await?; let storage = quantus_client.client().storage().at(latest); + let pending_iter = + quantus_subxt::api::storage().reversible_transfers().pending_transfers_iter(); + + let entrusted_ids: Vec<[u8; 32]> = entrusted_ss58 + .iter() + .map(|s| { + let id = SpAccountId32::from_ss58check(s).map_err(|e| { + QuantusError::Generic(format!("Invalid SS58 for pending lookup: {e:?}")) + })?; + Ok::<_, crate::error::QuantusError>(*id.as_ref()) + }) + .collect::, _>>()?; + + let mut counts: std::collections::HashMap<[u8; 32], u32> = + entrusted_ids.iter().map(|id| (*id, 0u32)).collect(); + + let mut iter = storage + .iter(pending_iter) + .await + .map_err(|e| QuantusError::NetworkError(format!("Pending transfers iter: {e:?}")))?; + + while let Some(result) = iter.next().await { + if let Ok(entry) = result { + let from_bytes: [u8; 32] = *entry.value.from.as_ref(); + if let Some(c) = counts.get_mut(&from_bytes) { + *c += 1; + } + } + } + let mut total = 0u32; let mut per_account = Vec::with_capacity(entrusted_ss58.len()); - - for ss58 in entrusted_ss58 { - let account_id_sp = SpAccountId32::from_ss58check(ss58).map_err(|e| { - QuantusError::Generic(format!("Invalid SS58 for pending lookup: {e:?}")) - })?; - let account_bytes: [u8; 32] = *account_id_sp.as_ref(); - let account_id = subxt::ext::subxt_core::utils::AccountId32::from(account_bytes); - - let addr = quantus_subxt::api::storage() - .reversible_transfers() - .pending_transfers_by_sender(account_id); - let value = storage.fetch(&addr).await.map_err(|e| { - QuantusError::NetworkError(format!("Fetch pending_transfers_by_sender: {e:?}")) - })?; - - let count = value.map(|bounded| bounded.0.len() as u32).unwrap_or(0); + for (ss58, id) in entrusted_ss58.iter().zip(entrusted_ids.iter()) { + let count = *counts.get(id).unwrap_or(&0); total += count; per_account.push((ss58.clone(), count)); } - Ok((total, per_account)) } diff --git a/src/config/mod.rs b/src/config/mod.rs index a8f3074..d846972 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -3,7 +3,7 @@ //! This module handles runtime compatibility information. /// List of runtime spec versions that this CLI is compatible with -pub const COMPATIBLE_RUNTIME_VERSIONS: &[u32] = &[118]; +pub const COMPATIBLE_RUNTIME_VERSIONS: &[u32] = &[118, 119]; /// Check if a runtime version is compatible with this CLI pub fn is_runtime_compatible(spec_version: u32) -> bool { diff --git a/src/quantus_metadata.scale b/src/quantus_metadata.scale index d77a70b0b04abf18c938614aa8f726adf6c82203..c213df497dcdb848e6c49e6761cd93c0ad0f0cda 100644 GIT binary patch delta 10656 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 S%h>6QF7c=wR7K}y=|2Fn{1puV diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 0837d2d..e784dbb 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -773,8 +773,10 @@ mod tests { let (wallet_manager, _temp_dir) = create_test_wallet_manager().await; let test_mnemonic = "orchard answer curve patient visual flower maze noise retreat penalty cage small earth domain scan pitch bottom crunch theme club client swap slice raven"; - let expected_address = "qzoog56PJKvDwqo9GwkzRN74kxEgDEspxu5zVA62y18ttt3tG"; // default derivation path index 0 - let expected_address_no_derive = "qzofkFbmnEYLX6iHwqJ9uKYXFi7ypQwcBBMxcYYLVD17vGpsm"; + // Addresses derived from mnemonic via DEFAULT_DERIVATION_PATH (m/44'/189189'/0'/0'/0') + // and no-derivation path (m/44'/189189'/0'). Update if qp-rusty-crystals-hdwallet changes. + let expected_address = "qznibgrYxiVTcBVLAoRPHgMqkXk16t1FfzGYcE4f4dVnJC3U8"; + let expected_address_no_derive = "qzkpGYFNw3LshweJnW5PgkNrZcUxXyoHFQHqBjJoZ1MeiQThC"; let imported_wallet = wallet_manager .import_wallet("imported-test-wallet", test_mnemonic, Some("import-password")) From d19ef71246eaad90e03081b641e47bf674de4c29 Mon Sep 17 00:00:00 2001 From: Cezary Olborski Date: Wed, 8 Apr 2026 09:14:49 +0800 Subject: [PATCH 3/8] fix: Preimage hash fix --- src/cli/referenda.rs | 7 +++---- src/cli/tech_referenda.rs | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/cli/referenda.rs b/src/cli/referenda.rs index a1300e2..9964f27 100644 --- a/src/cli/referenda.rs +++ b/src/cli/referenda.rs @@ -269,7 +269,7 @@ async fn submit_remark_proposal( origin_type: &str, execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { - use qp_poseidon::PoseidonHasher; + use sp_runtime::traits::{BlakeTwo256, Hash}; log_print!("📝 Submitting System::remark Proposal to Referenda"); log_print!(" đŸ’Ŧ Message: {}", message.bright_cyan()); @@ -288,9 +288,8 @@ async fn submit_remark_proposal( log_verbose!("📝 Encoded call size: {} bytes", encoded_call.len()); - // Compute preimage hash using Poseidon - let preimage_hash: sp_core::H256 = - ::hash(&encoded_call); + // Must match `frame_system::Config::Hashing` (BlakeTwo256) — same key as `pallet_preimage`. + let preimage_hash: sp_core::H256 = BlakeTwo256::hash(&encoded_call); log_print!("🔗 Preimage hash: {:?}", preimage_hash); diff --git a/src/cli/tech_referenda.rs b/src/cli/tech_referenda.rs index 6fc8860..b94d056 100644 --- a/src/cli/tech_referenda.rs +++ b/src/cli/tech_referenda.rs @@ -360,7 +360,7 @@ async fn submit_runtime_upgrade_with_preimage( password_file: Option, execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { - use qp_poseidon::PoseidonHasher; + use sp_runtime::traits::{BlakeTwo256, Hash}; log_print!("📝 Submitting Runtime Upgrade Proposal to Tech Referenda"); log_print!(" 📂 WASM file: {}", wasm_file.display().to_string().bright_cyan()); @@ -393,9 +393,8 @@ async fn submit_runtime_upgrade_with_preimage( log_verbose!("📝 Encoded call size: {} bytes", encoded_call.len()); - // Compute preimage hash using Poseidon (runtime uses PoseidonHasher) - let preimage_hash: sp_core::H256 = - ::hash(&encoded_call); + // Must match `frame_system::Config::Hashing` (BlakeTwo256) — same key as `pallet_preimage`. + let preimage_hash: sp_core::H256 = BlakeTwo256::hash(&encoded_call); log_print!("🔗 Preimage hash: {:?}", preimage_hash); From fe65d0c5a26b0daf7a00730bb2b4408c0552d4d2 Mon Sep 17 00:00:00 2001 From: Cezary Olborski Date: Wed, 8 Apr 2026 14:03:59 +0800 Subject: [PATCH 4/8] chore: Metadata refresh + new runtime version --- src/chain/quantus_subxt.rs | 128 +++++++++++++++++++++++++------------ src/cli/referenda.rs | 4 +- src/cli/tech_referenda.rs | 4 +- src/config/mod.rs | 2 +- src/quantus_metadata.scale | Bin 162741 -> 163589 bytes 5 files changed, 92 insertions(+), 46 deletions(-) diff --git a/src/chain/quantus_subxt.rs b/src/chain/quantus_subxt.rs index a7fa077..2437777 100644 --- a/src/chain/quantus_subxt.rs +++ b/src/chain/quantus_subxt.rs @@ -1959,9 +1959,9 @@ pub mod api { .hash(); runtime_metadata_hash == [ - 9u8, 252u8, 101u8, 200u8, 161u8, 142u8, 241u8, 130u8, 224u8, 189u8, 72u8, 23u8, - 15u8, 35u8, 16u8, 38u8, 233u8, 12u8, 177u8, 101u8, 41u8, 225u8, 185u8, 137u8, - 187u8, 153u8, 77u8, 45u8, 214u8, 214u8, 215u8, 198u8, + 126u8, 218u8, 159u8, 250u8, 59u8, 149u8, 173u8, 241u8, 56u8, 124u8, 210u8, 212u8, + 182u8, 54u8, 120u8, 239u8, 158u8, 147u8, 158u8, 70u8, 131u8, 157u8, 164u8, 69u8, + 167u8, 177u8, 13u8, 11u8, 12u8, 225u8, 206u8, 202u8, ] } pub mod system { @@ -7466,7 +7466,7 @@ pub mod api { [::core::primitive::u8; 32usize], runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >, ::core::primitive::u32, runtime_types::quantus_runtime::OriginCaller, @@ -8531,7 +8531,7 @@ pub mod api { pub type ProposalOrigin = runtime_types::quantus_runtime::OriginCaller; pub type Proposal = runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >; pub type EnactmentMoment = runtime_types::frame_support::traits::schedule::DispatchTime< @@ -9022,7 +9022,7 @@ pub mod api { pub type Track = ::core::primitive::u16; pub type Proposal = runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >; } impl ::subxt::ext::subxt_core::events::StaticEvent for Submitted { @@ -9116,7 +9116,7 @@ pub mod api { pub type Track = ::core::primitive::u16; pub type Proposal = runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >; pub type Tally = runtime_types::pallet_conviction_voting::types::Tally<::core::primitive::u128>; @@ -9373,7 +9373,7 @@ pub mod api { ::core::primitive::u32, runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >, ::core::primitive::u128, runtime_types::pallet_conviction_voting::types::Tally< @@ -10344,7 +10344,7 @@ pub mod api { ::core::primitive::u128, runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >, >; pub type Param0 = ::subxt::ext::subxt_core::utils::H256; @@ -12501,7 +12501,7 @@ pub mod api { pub type ProposalOrigin = runtime_types::quantus_runtime::OriginCaller; pub type Proposal = runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >; pub type EnactmentMoment = runtime_types::frame_support::traits::schedule::DispatchTime< @@ -12992,7 +12992,7 @@ pub mod api { pub type Track = ::core::primitive::u16; pub type Proposal = runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >; } impl ::subxt::ext::subxt_core::events::StaticEvent for Submitted { @@ -13086,7 +13086,7 @@ pub mod api { pub type Track = ::core::primitive::u16; pub type Proposal = runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >; pub type Tally = runtime_types::pallet_ranked_collective::Tally; } @@ -13337,7 +13337,7 @@ pub mod api { ::core::primitive::u32, runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >, ::core::primitive::u128, runtime_types::pallet_ranked_collective::Tally, @@ -20420,7 +20420,11 @@ pub mod api { #[encode_as_type( crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" )] - #[doc = "Verify an aggregated wormhole proof and process all transfers in the batch"] + #[doc = "Verify an aggregated wormhole proof and process all transfers in the batch."] + #[doc = ""] + #[doc = "Returns `DispatchResultWithPostInfo` to allow weight correction on early failures."] + #[doc = "If pre-validation fails (deserialization, cheap checks), we return the actual"] + #[doc = "consumed weight to free block capacity for other transactions."] pub struct VerifyAggregatedProof { pub proof_bytes: verify_aggregated_proof::ProofBytes, } @@ -20436,7 +20440,11 @@ pub mod api { } pub struct TransactionApi; impl TransactionApi { - #[doc = "Verify an aggregated wormhole proof and process all transfers in the batch"] + #[doc = "Verify an aggregated wormhole proof and process all transfers in the batch."] + #[doc = ""] + #[doc = "Returns `DispatchResultWithPostInfo` to allow weight correction on early failures."] + #[doc = "If pre-validation fails (deserialization, cheap checks), we return the actual"] + #[doc = "consumed weight to free block capacity for other transactions."] pub fn verify_aggregated_proof( &self, proof_bytes: types::verify_aggregated_proof::ProofBytes, @@ -20553,6 +20561,12 @@ pub mod api { pub type TransferCount = ::core::primitive::u64; pub type Param0 = ::subxt::ext::subxt_core::utils::AccountId32; } + pub mod genesis_endowments_pending { + use super::runtime_types; + pub type GenesisEndowmentsPending = ::subxt::ext::subxt_core::alloc::vec::Vec< + (::subxt::ext::subxt_core::utils::AccountId32, ::core::primitive::u128), + >; + } } pub struct StorageApi; impl StorageApi { @@ -20709,6 +20723,32 @@ pub mod api { ], ) } + #[doc = " Genesis endowments pending event emission."] + #[doc = " Stores (to_address, amount) for each genesis endowment."] + #[doc = " These are processed in on_initialize at block 1 to emit NativeTransferred events,"] + #[doc = " then cleared. This ensures indexers like Subsquid can track genesis transfers."] + #[doc = ""] + #[doc = " Unbounded because it's only populated at genesis and cleared on block 1."] + pub fn genesis_endowments_pending( + &self, + ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< + (), + types::genesis_endowments_pending::GenesisEndowmentsPending, + ::subxt::ext::subxt_core::utils::Yes, + ::subxt::ext::subxt_core::utils::Yes, + (), + > { + ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( + "Wormhole", + "GenesisEndowmentsPending", + (), + [ + 92u8, 149u8, 109u8, 170u8, 10u8, 130u8, 163u8, 174u8, 224u8, 98u8, + 190u8, 125u8, 213u8, 240u8, 211u8, 23u8, 222u8, 20u8, 104u8, 45u8, 7u8, + 73u8, 225u8, 73u8, 21u8, 88u8, 91u8, 57u8, 207u8, 252u8, 25u8, 76u8, + ], + ) + } } } pub mod constants { @@ -25033,7 +25073,7 @@ pub mod api { >, proposal: runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >, enactment_moment: runtime_types::frame_support::traits::schedule::DispatchTime< @@ -25190,7 +25230,7 @@ pub mod api { track: ::core::primitive::u16, proposal: runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >, }, #[codec(index = 1)] @@ -25220,7 +25260,7 @@ pub mod api { track: ::core::primitive::u16, proposal: runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >, tally: runtime_types::pallet_conviction_voting::types::Tally< ::core::primitive::u128, @@ -25313,7 +25353,7 @@ pub mod api { track: ::core::primitive::u16, proposal: runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >, }, #[codec(index = 1)] @@ -25343,7 +25383,7 @@ pub mod api { track: ::core::primitive::u16, proposal: runtime_types::frame_support::traits::preimages::Bounded< runtime_types::quantus_runtime::RuntimeCall, - runtime_types::qp_poseidon::PoseidonHasher, + runtime_types::sp_runtime::traits::BlakeTwo256, >, tally: runtime_types::pallet_ranked_collective::Tally, }, @@ -26758,7 +26798,11 @@ pub mod api { #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] pub enum Call { #[codec(index = 2)] - #[doc = "Verify an aggregated wormhole proof and process all transfers in the batch"] + #[doc = "Verify an aggregated wormhole proof and process all transfers in the batch."] + #[doc = ""] + #[doc = "Returns `DispatchResultWithPostInfo` to allow weight correction on early failures."] + #[doc = "If pre-validation fails (deserialization, cheap checks), we return the actual"] + #[doc = "consumed weight to free block capacity for other transactions."] verify_aggregated_proof { proof_bytes: ::subxt::ext::subxt_core::alloc::vec::Vec<::core::primitive::u8>, @@ -26782,24 +26826,22 @@ pub mod api { #[codec(index = 1)] NullifierAlreadyUsed, #[codec(index = 2)] - VerifierNotAvailable, - #[codec(index = 3)] BlockNotFound, - #[codec(index = 4)] + #[codec(index = 3)] AggregatedVerifierNotAvailable, - #[codec(index = 5)] + #[codec(index = 4)] AggregatedProofDeserializationFailed, - #[codec(index = 6)] + #[codec(index = 5)] AggregatedVerificationFailed, - #[codec(index = 7)] + #[codec(index = 6)] InvalidAggregatedPublicInputs, - #[codec(index = 8)] + #[codec(index = 7)] #[doc = "The volume fee rate in the proof doesn't match the configured rate"] InvalidVolumeFeeRate, - #[codec(index = 9)] + #[codec(index = 8)] #[doc = "Transfer amount is below the minimum required"] TransferAmountBelowMinimum, - #[codec(index = 10)] + #[codec(index = 9)] #[doc = "Only native asset (asset_id = 0) is supported in this version"] NonNativeAssetNotSupported, } @@ -26906,17 +26948,6 @@ pub mod api { pub digest: runtime_types::sp_runtime::generic::digest::Digest, } } - pub mod qp_poseidon { - use super::runtime_types; - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - pub struct PoseidonHasher; - } pub mod qp_scheduler { use super::runtime_types; #[derive( @@ -27968,6 +27999,21 @@ pub mod api { DecodeError, } } + pub mod traits { + use super::runtime_types; + #[derive( + :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, + :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, + Debug, + )] + #[decode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" + )] + #[encode_as_type( + crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" + )] + pub struct BlakeTwo256; + } pub mod transaction_validity { use super::runtime_types; #[derive( diff --git a/src/cli/referenda.rs b/src/cli/referenda.rs index 9964f27..797252a 100644 --- a/src/cli/referenda.rs +++ b/src/cli/referenda.rs @@ -311,7 +311,7 @@ async fn submit_remark_proposal( type ProposalBounded = quantus_subxt::api::runtime_types::frame_support::traits::preimages::Bounded< quantus_subxt::api::runtime_types::quantus_runtime::RuntimeCall, - quantus_subxt::api::runtime_types::qp_poseidon::PoseidonHasher, + quantus_subxt::api::runtime_types::sp_runtime::traits::BlakeTwo256, >; let preimage_hash_subxt: subxt::utils::H256 = preimage_hash; @@ -427,7 +427,7 @@ async fn submit_proposal( type ProposalBounded = quantus_subxt::api::runtime_types::frame_support::traits::preimages::Bounded< quantus_subxt::api::runtime_types::quantus_runtime::RuntimeCall, - quantus_subxt::api::runtime_types::qp_poseidon::PoseidonHasher, + quantus_subxt::api::runtime_types::sp_runtime::traits::BlakeTwo256, >; let preimage_hash_subxt: subxt::utils::H256 = preimage_hash_parsed; diff --git a/src/cli/tech_referenda.rs b/src/cli/tech_referenda.rs index b94d056..df2d060 100644 --- a/src/cli/tech_referenda.rs +++ b/src/cli/tech_referenda.rs @@ -316,7 +316,7 @@ async fn submit_runtime_upgrade( type ProposalBounded = quantus_subxt::api::runtime_types::frame_support::traits::preimages::Bounded< quantus_subxt::api::runtime_types::quantus_runtime::RuntimeCall, - quantus_subxt::api::runtime_types::qp_poseidon::PoseidonHasher, + quantus_subxt::api::runtime_types::sp_runtime::traits::BlakeTwo256, >; let preimage_hash_subxt: subxt::utils::H256 = preimage_hash_parsed; @@ -416,7 +416,7 @@ async fn submit_runtime_upgrade_with_preimage( type ProposalBounded = quantus_subxt::api::runtime_types::frame_support::traits::preimages::Bounded< quantus_subxt::api::runtime_types::quantus_runtime::RuntimeCall, - quantus_subxt::api::runtime_types::qp_poseidon::PoseidonHasher, + quantus_subxt::api::runtime_types::sp_runtime::traits::BlakeTwo256, >; let preimage_hash_subxt: subxt::utils::H256 = preimage_hash; diff --git a/src/config/mod.rs b/src/config/mod.rs index d846972..a5a4ff1 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -3,7 +3,7 @@ //! This module handles runtime compatibility information. /// List of runtime spec versions that this CLI is compatible with -pub const COMPATIBLE_RUNTIME_VERSIONS: &[u32] = &[118, 119]; +pub const COMPATIBLE_RUNTIME_VERSIONS: &[u32] = &[123]; /// Check if a runtime version is compatible with this CLI pub fn is_runtime_compatible(spec_version: u32) -> bool { diff --git a/src/quantus_metadata.scale b/src/quantus_metadata.scale index fb8eb490852dcc5ee77ffc96baed709214f37a68..1b842b60d75a463b3257f2266e50a34266593db2 100644 GIT binary patch delta 1861 zcma)7e`pj(6rML3?L|{Ks4X!TI%-ps63-|qmTDoXQDUg3@eHL|TiYO|4sd$AcmGmrJJ{~PsaU(57HoO}h zs)TioogDt4~5n{?dDJr!7VZououCeR%-N^fz~*7%KGDyRap`y*30r==%HI zz%dEcdk*=MBO~CZADR>T6=ntlVuU$zR>z$~_X4gi3`=o3Vz9diR@1{UNOqWkX z0~G7dX%JL0ee?|0nwf@IH(CrDo29Y)P*!vXvaZ|rEJs<(!kIz75OAlkEhq7T;j3psp5Q`sl9f=zmKkQ~CBLQXuAtyqRU8E1go1_YCKZfB$ z!0MnMb7F@&7#YGaLQ3j9kCFaDR=>VA2OD&57G8k&^{2D20Z!?$Sy-!opM&T1qgj~5 z1&ry0LESVD<#1Ma&%=vb&oahqlei(TiENBDKqqC*P)Zp22!W#;{e%&`2#a;nQgTlJ zJP%Dz4Kk>%cW}F; zY)}^;AJoM{%i$Nj#0Xxhg-SQV)B(7u?>vAin9xr@giWg^!}2wh+-7=s9hBu;AHq9DAo3G` z!*mI}o&RwqU3dfH`O7VIfcCcTmyT4Hs&h;?m%*W_M(LQA(+=b<#z^TGd@+FI@?r$f z7DBk}!UQfemQr|p61Vta-$kwR3g2xJriqWLii-@MdA~9ek`zXow-+i#fW1-8L_P3i z8dc1NCsE|CftjdGD>Q-@%dz}O-T2yHl;_saJg~6O52EI~WHQudN}_+51y-tR4}@}e zxM8D{NHc*IEQLi?XeS75%5LfPDsEdHk{=G*RA*qBsCy?AIy%4-%}DkLtrDah_z|Zq zlrWZQlZFV8vgL15NE5v(>t+KRwQ7bum(qoUpalw{s}?)!$v~~{6DbO5!AoD=N6%t zvG&tAnsCPGzFpGuaT~X!JU7Fga2r>l`xbgk_lFZSs= rSbdXKNZ_@BWt;l-94*c759l>0nqVXOvK&2H1e5um<4C;dHY5K4mMCw` delta 1024 zcmZWoO-xi*6u#e?Q+y~*#2}yp{*t~apA&-5jqOCrfGV|>1N{1&AsQ| zobP<+cjVvFnJ1+sG0Qdm_oqv8!78IZ5$}pSDJvXu?46ze3%ku!kCjwkT0?@Q7TWfXv11* zeW+iioPUVp)fS`kkk#GT5jPWQt7X7VhV4|iyGbdFm7*}Ku+%MK8)9;J344){ZmvgGtj)ncaEvJjIBol^OE= zGB(R^f1({@Qj^0LjLZHUw(b~bu51n_Eo;9SH@FQ6;zI~1R-bFKX9s=BN^iwRf&%KS zoX_FF%VUg&J+>~LWxMa2uBp^S!K>|$@OHzw;()j)puFAUfF=u2?-4FwN=`k-mUpL% zGC1>m24@Pn$X|4YmEPLHz$~j-x%L?K>*k()1g}6{l}}etEtM;35O3=e_m>;=?iT;!|YHFyMW&hH^(x z=AAh~ACZiQ=+&~A6N>gb$ykpQwIuTo%4K#F9rZR_bQgS#mEo22&~516TL{xTx}_?5 z>9TIApL(f<)9n9FGQG4xwngX$PRm~r`WZuVJxUo}(yw9^TWhjEq-!z8XJx%j%dbqZ z;SLN_?aBN|boJ;_Ydq(bJ2Xd_@_tQF6)^4noup3)bMkSTW^h%S`t(U43GQoxe|`USo_JmvKc(s3Uay!j#RxbGgT{{RvmL8t%# From 405ddd9d22b7e3f962b6b7ca8cc921621357b0de Mon Sep 17 00:00:00 2001 From: Cezary Olborski Date: Thu, 9 Apr 2026 14:46:18 +0800 Subject: [PATCH 5/8] fix: Collective members decoder --- src/cli/tech_collective.rs | 57 +++++++++-------- src/cli/tech_referenda.rs | 127 +++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+), 28 deletions(-) diff --git a/src/cli/tech_collective.rs b/src/cli/tech_collective.rs index 6234b6f..6a8d923 100644 --- a/src/cli/tech_collective.rs +++ b/src/cli/tech_collective.rs @@ -275,42 +275,43 @@ pub async fn get_member_count( Ok(count_data) } -/// Get list of all members +/// Get list of all members (rank 0 indices via `IndexToId`). +/// +/// We do **not** use `members_iter()`: subxt decodes iterable map keys into `keys: ()` for this +/// storage layout, and guessing AccountId from raw `key_bytes` is fragile. `MemberCount` + +/// `IndexToId(rank, index)` matches FRAME's ranked collective layout and matches RPC/state layout. pub async fn get_member_list( quantus_client: &crate::chain::client::QuantusClient, ) -> crate::error::Result> { - log_verbose!("🔍 Getting member list..."); + log_verbose!("🔍 Getting member list via MemberCount + IndexToId..."); - // Get the latest block hash to read from the latest state (not finalized) let latest_block_hash = quantus_client.get_latest_block().await?; - let storage_at = quantus_client.client().storage().at(latest_block_hash); - // Query all Members storage entries - let members_storage = quantus_subxt::api::storage().tech_collective().members_iter(); - - let mut members = Vec::new(); - let mut iter = storage_at.iter(members_storage).await.map_err(|e| { - QuantusError::NetworkError(format!("Failed to create members iterator: {e:?}")) - })?; - - while let Some(result) = iter.next().await { - match result { - Ok(storage_entry) => { - let key = storage_entry.key_bytes; - // The key contains the AccountId32 after the storage prefix - // TechCollective Members storage key format: prefix + AccountId32 - if key.len() >= 32 { - // Extract the last 32 bytes as AccountId32 - let account_bytes: [u8; 32] = - key[key.len() - 32..].try_into().unwrap_or([0u8; 32]); - let sp_account = AccountId32::from(account_bytes); - log_verbose!("Found member: {}", sp_account.to_quantus_ss58()); - members.push(sp_account); - } + let count_addr = quantus_subxt::api::storage().tech_collective().member_count(0u16); + let count = storage_at + .fetch(&count_addr) + .await + .map_err(|e| QuantusError::NetworkError(format!("Failed to fetch member count: {e:?}")))? + .unwrap_or(0); + + let mut members = Vec::with_capacity(count as usize); + for index in 0..count { + let id_addr = quantus_subxt::api::storage().tech_collective().index_to_id(0u16, index); + match storage_at.fetch(&id_addr).await { + Ok(Some(subxt_account)) => { + let account_bytes: [u8; 32] = *subxt_account.as_ref(); + let sp_account = AccountId32::from(account_bytes); + log_verbose!("Found member [{}]: {}", index, sp_account.to_quantus_ss58()); + members.push(sp_account); + }, + Ok(None) => { + log_verbose!("âš ī¸ IndexToId missing for rank 0 index {index} (count={count})"); }, Err(e) => { - log_verbose!("âš ī¸ Error reading member entry: {:?}", e); + return Err(QuantusError::NetworkError(format!( + "Failed to fetch IndexToId(0, {index}): {e:?}" + ))); }, } } @@ -445,7 +446,7 @@ pub async fn handle_tech_collective_command( } }, Err(e) => { - log_verbose!("âš ī¸ Failed to get member list: {:?}", e); + log_print!("âš ī¸ Failed to get member list: {e}"); // Fallback to member count match get_member_count(&quantus_client).await? { Some(count_data) => { diff --git a/src/cli/tech_referenda.rs b/src/cli/tech_referenda.rs index df2d060..8ec4a31 100644 --- a/src/cli/tech_referenda.rs +++ b/src/cli/tech_referenda.rs @@ -48,6 +48,27 @@ pub enum TechReferendaCommands { password_file: Option, }, + /// Submit a proposal to set Treasury `treasury_portion` (Permill) via Tech Referenda (creates preimage first) + SubmitTreasuryPortion { + /// New treasury portion in Permill (parts per million): 0..=1_000_000 + /// + /// Example: 500_000 = 50% + #[arg(long, value_parser = clap::value_parser!(u32).range(0..=1_000_000))] + portion_permill: u32, + + /// Wallet name to sign with (must be a Tech Collective member or root) + #[arg(short, long)] + from: String, + + /// Password for the wallet + #[arg(short, long)] + password: Option, + + /// Read password from file + #[arg(long)] + password_file: Option, + }, + /// List all active Tech Referenda proposals List, @@ -212,6 +233,21 @@ pub async fn handle_tech_referenda_command( execution_mode, ) .await, + TechReferendaCommands::SubmitTreasuryPortion { + portion_permill, + from, + password, + password_file, + } => + submit_treasury_portion_with_preimage( + &quantus_client, + portion_permill, + &from, + password, + password_file, + execution_mode, + ) + .await, TechReferendaCommands::List => list_proposals(&quantus_client).await, TechReferendaCommands::Get { index } => get_proposal_details(&quantus_client, index).await, TechReferendaCommands::Status { index } => @@ -451,6 +487,97 @@ async fn submit_runtime_upgrade_with_preimage( Ok(()) } +/// Submit a Tech Referenda proposal to set the Treasury portion (creates preimage first) +async fn submit_treasury_portion_with_preimage( + quantus_client: &crate::chain::client::QuantusClient, + portion_permill: u32, + from: &str, + password: Option, + password_file: Option, + execution_mode: crate::cli::common::ExecutionMode, +) -> crate::error::Result<()> { + use sp_runtime::traits::{BlakeTwo256, Hash}; + + log_print!("📝 Submitting Treasury Portion Update Proposal to Tech Referenda"); + log_print!(" 📊 New portion (Permill): {}", portion_permill.to_string().bright_cyan()); + log_print!( + " 📊 New portion (%): {}", + format!("{:.2}%", (portion_permill as f64) / 10000.0).bright_cyan() + ); + log_print!(" 🔑 Submitted by: {}", from.bright_yellow()); + + // Load wallet keypair + let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; + + // Build a static payload for TreasuryPallet::set_treasury_portion and encode full call data + // Note: runtime_types::Permill is a tuple struct (u32 parts-per-million). + let portion = + quantus_subxt::api::runtime_types::sp_arithmetic::per_things::Permill(portion_permill); + let set_portion_payload = + quantus_subxt::api::tx().treasury_pallet().set_treasury_portion(portion); + + let metadata = quantus_client.client().metadata(); + let encoded_call = <_ as subxt::tx::Payload>::encode_call_data(&set_portion_payload, &metadata) + .map_err(|e| QuantusError::Generic(format!("Failed to encode call data: {:?}", e)))?; + + log_verbose!("📝 Encoded call size: {} bytes", encoded_call.len()); + + // Must match `frame_system::Config::Hashing` (BlakeTwo256) — same key as `pallet_preimage`. + let preimage_hash: sp_core::H256 = BlakeTwo256::hash(&encoded_call); + log_print!("🔗 Preimage hash: {:?}", preimage_hash); + + // Submit Preimage::note_preimage with bounded bytes + type PreimageBytes = quantus_subxt::api::preimage::calls::types::note_preimage::Bytes; + let bounded_bytes: PreimageBytes = encoded_call.clone(); + + 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, execution_mode) + .await?; + log_print!("✅ Preimage transaction submitted: {:?}", preimage_tx_hash); + + log_print!("âŗ Waiting for preimage transaction confirmation..."); + + // Build TechReferenda::submit call using Lookup preimage reference + type ProposalBounded = + quantus_subxt::api::runtime_types::frame_support::traits::preimages::Bounded< + quantus_subxt::api::runtime_types::quantus_runtime::RuntimeCall, + quantus_subxt::api::runtime_types::sp_runtime::traits::BlakeTwo256, + >; + + let preimage_hash_subxt: subxt::utils::H256 = preimage_hash; + let proposal: ProposalBounded = + ProposalBounded::Lookup { hash: preimage_hash_subxt, len: encoded_call.len() as u32 }; + + let raw_origin_root = + quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::Root; + let origin_caller = + quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin_root); + + let enactment = + quantus_subxt::api::runtime_types::frame_support::traits::schedule::DispatchTime::After( + 0u32, + ); + + log_print!("🔧 Creating TechReferenda::submit call..."); + let submit_call = + quantus_subxt::api::tx() + .tech_referenda() + .submit(origin_caller, proposal, enactment); + + let tx_hash = + submit_transaction(quantus_client, &keypair, submit_call, None, execution_mode).await?; + log_print!( + "✅ {} Treasury portion proposal submitted! Hash: {:?}", + "SUCCESS".bright_green().bold(), + tx_hash + ); + + log_print!("💡 Use 'quantus tech-referenda list' to see active proposals"); + Ok(()) +} + /// List recent Tech Referenda proposals async fn list_proposals( quantus_client: &crate::chain::client::QuantusClient, From 9ee3a5dd2dad2daaa9ba98a85d075ff8e99d56ad Mon Sep 17 00:00:00 2001 From: Cezary Olborski Date: Thu, 9 Apr 2026 17:14:31 +0800 Subject: [PATCH 6/8] feat: Refresh with chain 0.5.3 --- Cargo.lock | 58 ++-- Cargo.toml | 18 +- src/chain/quantus_subxt.rs | 625 ++++--------------------------------- src/cli/generic_call.rs | 42 +-- src/cli/mod.rs | 4 +- src/cli/runtime.rs | 82 +++-- src/cli/storage.rs | 151 +-------- src/cli/tech_collective.rs | 106 +------ src/cli/tech_referenda.rs | 146 +-------- src/quantus_metadata.scale | Bin 163589 -> 161568 bytes 10 files changed, 201 insertions(+), 1031 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9ccdd41..4411351 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1107,6 +1107,12 @@ dependencies = [ "libc", ] +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + [[package]] name = "crossbeam-deque" version = "0.8.6" @@ -3117,6 +3123,10 @@ name = "once_cell" version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +dependencies = [ + "critical-section", + "portable-atomic", +] [[package]] name = "once_cell_polyfill" @@ -3639,18 +3649,20 @@ dependencies = [ [[package]] name = "qp-plonky2" -version = "1.1.6" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d74c09b03472d90b14309122930a9efb80541e0df2b83eae0ee280dc60d09657" +checksum = "414a0203c2d4787ad76be16aaa6a3e5bedf4ac5baa66ecfab46ed40c88d10af9" dependencies = [ "ahash", "anyhow", + "critical-section", "getrandom 0.2.17", "hashbrown 0.14.5", "itertools 0.11.0", "keccak-hash 0.8.0", "log", "num", + "once_cell", "p3-field", "p3-goldilocks", "p3-poseidon2", @@ -3671,9 +3683,9 @@ dependencies = [ [[package]] name = "qp-plonky2-core" -version = "1.1.6" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d4b67b899994eae278d802c9d8735fc824f4ecfc1b61f8a2a9163b88384162a" +checksum = "e97d56a59ca75de58414a058195e6d8630b524ffb333d1a4555f2b49f4113cdd" dependencies = [ "ahash", "anyhow", @@ -3697,9 +3709,9 @@ dependencies = [ [[package]] name = "qp-plonky2-field" -version = "1.1.6" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c90a6abc681568deeb0a1f238225de5d3bf11e89373894e5199395268c68cd8" +checksum = "bf15d2ccea0cb80e61ee27315bdcb272fdbbb19c1826936569887c4c5b499627" dependencies = [ "anyhow", "itertools 0.11.0", @@ -3714,17 +3726,19 @@ dependencies = [ [[package]] name = "qp-plonky2-verifier" -version = "1.1.6" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5283d4b8c9bf9f5488643f46b8a9886161acfc654ef8b7d77c53745f3c6e0f56" +checksum = "7741059492bd163a1eeaec7471e2cf3d00b403e1ddec476fa5248237f7493298" dependencies = [ "ahash", "anyhow", + "critical-section", "hashbrown 0.14.5", "itertools 0.11.0", "keccak-hash 0.8.0", "log", "num", + "once_cell", "p3-field", "p3-goldilocks", "p3-poseidon2", @@ -3816,9 +3830,9 @@ dependencies = [ [[package]] name = "qp-wormhole-aggregator" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b1c758c298bc5b19a3389fe7606a620603a690cfdd19a79a487fa080cb11d2" +checksum = "2a96cf6018afa939953257a738e503ce305546c85d8777aa66153f21dc535ffe" dependencies = [ "anyhow", "hex", @@ -3835,9 +3849,9 @@ dependencies = [ [[package]] name = "qp-wormhole-circuit" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e303f0f9076d27518b5ee21f25ddb1c1fc75bbea733f06abdedd08074392fa4" +checksum = "b86a9f070a7cc9d00e69caed517d2add5913484ce05052e3fb9849cd9c0587d4" dependencies = [ "anyhow", "hex", @@ -3848,9 +3862,9 @@ dependencies = [ [[package]] name = "qp-wormhole-circuit-builder" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "242e1e510e2f6cf3d8797fa1b92cf7c06e53f121fe8515d26d57c9458f87d249" +checksum = "177ce48156dd5fe8d84e581ba70ffaf4ee1334986697f58305b04c11b9d3566c" dependencies = [ "anyhow", "clap", @@ -3862,18 +3876,18 @@ dependencies = [ [[package]] name = "qp-wormhole-inputs" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39fcd1a9f1161d6c2f7b723e35ca76425c41853f582355ddba9ccfd1f9d04b23" +checksum = "6b81b137f4cf98b62f4437694fb1849e07b65f2b556dddeea6e91e7209cbf168" dependencies = [ "anyhow", ] [[package]] name = "qp-wormhole-prover" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28ff0f27b5de4c41e3984a31ae12d212494de9a55cb22a503bce294d5ab1dfab" +checksum = "4fae60b441328ecf956c5bd34c98810cb7d536bccdc65ceccfed5bf2b46344eb" dependencies = [ "anyhow", "qp-plonky2", @@ -3884,9 +3898,9 @@ dependencies = [ [[package]] name = "qp-wormhole-verifier" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245908bc1b88872566931e8c7c5b00bc6bd6aa042fdbcb1703c4fe289e7e3bdf" +checksum = "3f9d517f9570578944a22a53f514ce9f7643857f28b256252c6ba82cbebc308a" dependencies = [ "anyhow", "qp-plonky2-verifier", @@ -3895,9 +3909,9 @@ dependencies = [ [[package]] name = "qp-zk-circuits-common" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d2d4ac7c42d0f118af80e7d9aec273432999268ea76a8a982ad7d780bb8bf98" +checksum = "9d0649182166496ef48ad23f9c94062baf5d98499c409ff9a92f784bf5fa4efe" dependencies = [ "anyhow", "hex", diff --git a/Cargo.toml b/Cargo.toml index a3f10e2..9859dd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -77,18 +77,18 @@ subxt-metadata = "0.44" # ZK proof generation (aligned with chain) anyhow = "1.0" -qp-wormhole-circuit = { version = "1.3.0", default-features = false, features = ["std"] } -qp-wormhole-prover = { version = "1.3.0", default-features = false, features = ["std"] } -qp-wormhole-verifier = { version = "1.3.0", default-features = false, features = ["std"] } -qp-wormhole-aggregator = { version = "1.3.0", default-features = false, features = ["rayon", "std"] } -qp-wormhole-inputs = { version = "1.3.0", default-features = false, features = ["std"] } -qp-zk-circuits-common = { version = "1.3.0", default-features = false, features = ["std"] } -qp-plonky2 = { version = "1.1.6", default-features = false, features = ["rand", "std"] } -qp-wormhole-circuit-builder = { version = "1.3.0" } +qp-wormhole-circuit = { version = "1.4.0", default-features = false, features = ["std"] } +qp-wormhole-prover = { version = "1.4.0", default-features = false, features = ["std"] } +qp-wormhole-verifier = { version = "1.4.0", default-features = false, features = ["std"] } +qp-wormhole-aggregator = { version = "1.4.0", default-features = false, features = ["rayon", "std"] } +qp-wormhole-inputs = { version = "1.4.0", default-features = false, features = ["std"] } +qp-zk-circuits-common = { version = "1.4.0", default-features = false, features = ["std"] } +qp-plonky2 = { version = "1.4.0", default-features = false, features = ["rand", "std"] } +qp-wormhole-circuit-builder = { version = "1.4.0" } [build-dependencies] -qp-wormhole-circuit-builder = { version = "1.3.0" } +qp-wormhole-circuit-builder = { version = "1.4.0" } [dev-dependencies] tempfile = "3.8.1" diff --git a/src/chain/quantus_subxt.rs b/src/chain/quantus_subxt.rs index 2437777..dc41a34 100644 --- a/src/chain/quantus_subxt.rs +++ b/src/chain/quantus_subxt.rs @@ -6,12 +6,11 @@ pub mod api { mod root_mod { pub use super::*; } - pub static PALLETS: [&str; 21usize] = [ + pub static PALLETS: [&str; 20usize] = [ "System", "Timestamp", "Balances", "TransactionPayment", - "Sudo", "QPoW", "MiningRewards", "Preimage", @@ -1432,10 +1431,10 @@ pub mod api { "query_call_info", types::QueryCallInfo { call, len }, [ - 218u8, 133u8, 148u8, 251u8, 115u8, 98u8, 41u8, 181u8, 220u8, 98u8, - 96u8, 5u8, 83u8, 71u8, 198u8, 107u8, 19u8, 120u8, 188u8, 127u8, 50u8, - 201u8, 132u8, 73u8, 13u8, 118u8, 124u8, 200u8, 48u8, 103u8, 188u8, - 219u8, + 251u8, 117u8, 187u8, 14u8, 196u8, 176u8, 208u8, 219u8, 61u8, 234u8, + 23u8, 241u8, 174u8, 156u8, 167u8, 160u8, 89u8, 42u8, 178u8, 155u8, + 190u8, 179u8, 124u8, 114u8, 251u8, 186u8, 67u8, 205u8, 239u8, 51u8, + 177u8, 90u8, ], ) } @@ -1453,10 +1452,10 @@ pub mod api { "query_call_fee_details", types::QueryCallFeeDetails { call, len }, [ - 222u8, 82u8, 209u8, 219u8, 210u8, 175u8, 13u8, 207u8, 13u8, 17u8, - 234u8, 166u8, 55u8, 25u8, 194u8, 92u8, 155u8, 69u8, 143u8, 95u8, 18u8, - 181u8, 70u8, 191u8, 64u8, 119u8, 244u8, 116u8, 44u8, 172u8, 251u8, - 66u8, + 213u8, 155u8, 136u8, 5u8, 157u8, 246u8, 224u8, 16u8, 227u8, 103u8, + 222u8, 116u8, 172u8, 213u8, 203u8, 43u8, 153u8, 98u8, 75u8, 158u8, + 131u8, 22u8, 186u8, 186u8, 116u8, 25u8, 242u8, 159u8, 130u8, 122u8, + 152u8, 125u8, ], ) } @@ -1841,9 +1840,6 @@ pub mod api { pub fn transaction_payment(&self) -> transaction_payment::storage::StorageApi { transaction_payment::storage::StorageApi } - pub fn sudo(&self) -> sudo::storage::StorageApi { - sudo::storage::StorageApi - } pub fn q_po_w(&self) -> q_po_w::storage::StorageApi { q_po_w::storage::StorageApi } @@ -1901,9 +1897,6 @@ pub mod api { pub fn balances(&self) -> balances::calls::TransactionApi { balances::calls::TransactionApi } - pub fn sudo(&self) -> sudo::calls::TransactionApi { - sudo::calls::TransactionApi - } pub fn preimage(&self) -> preimage::calls::TransactionApi { preimage::calls::TransactionApi } @@ -1959,9 +1952,9 @@ pub mod api { .hash(); runtime_metadata_hash == [ - 126u8, 218u8, 159u8, 250u8, 59u8, 149u8, 173u8, 241u8, 56u8, 124u8, 210u8, 212u8, - 182u8, 54u8, 120u8, 239u8, 158u8, 147u8, 158u8, 70u8, 131u8, 157u8, 164u8, 69u8, - 167u8, 177u8, 13u8, 11u8, 12u8, 225u8, 206u8, 202u8, + 95u8, 161u8, 29u8, 63u8, 6u8, 191u8, 169u8, 252u8, 9u8, 18u8, 126u8, 99u8, 29u8, + 6u8, 27u8, 29u8, 251u8, 189u8, 252u8, 166u8, 35u8, 141u8, 155u8, 35u8, 238u8, 85u8, + 244u8, 246u8, 49u8, 113u8, 167u8, 219u8, ] } pub mod system { @@ -3060,9 +3053,10 @@ pub mod api { "Events", (), [ - 219u8, 135u8, 2u8, 5u8, 35u8, 85u8, 207u8, 98u8, 136u8, 150u8, 109u8, - 92u8, 64u8, 218u8, 201u8, 111u8, 25u8, 157u8, 42u8, 17u8, 112u8, 204u8, - 180u8, 241u8, 138u8, 97u8, 146u8, 96u8, 223u8, 24u8, 107u8, 44u8, + 114u8, 203u8, 75u8, 252u8, 183u8, 122u8, 99u8, 127u8, 226u8, 41u8, + 125u8, 202u8, 177u8, 177u8, 136u8, 66u8, 221u8, 204u8, 240u8, 189u8, + 146u8, 54u8, 190u8, 211u8, 240u8, 69u8, 233u8, 62u8, 78u8, 177u8, 97u8, + 8u8, ], ) } @@ -5387,369 +5381,6 @@ pub mod api { } } } - pub mod sudo { - use super::{root_mod, runtime_types}; - #[doc = "Error for the Sudo pallet."] - pub type Error = runtime_types::pallet_sudo::pallet::Error; - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub type Call = runtime_types::pallet_sudo::pallet::Call; - pub mod calls { - use super::{root_mod, runtime_types}; - type DispatchError = runtime_types::sp_runtime::DispatchError; - pub mod types { - use super::runtime_types; - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Authenticates the sudo key and dispatches a function call with `Root` origin."] - pub struct Sudo { - pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, - } - pub mod sudo { - use super::runtime_types; - pub type Call = runtime_types::quantus_runtime::RuntimeCall; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for Sudo { - const PALLET: &'static str = "Sudo"; - const CALL: &'static str = "sudo"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Authenticates the sudo key and dispatches a function call with `Root` origin."] - #[doc = "This function does not check the weight of the call, and instead allows the"] - #[doc = "Sudo user to specify the weight of the call."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - pub struct SudoUncheckedWeight { - pub call: - ::subxt::ext::subxt_core::alloc::boxed::Box, - pub weight: sudo_unchecked_weight::Weight, - } - pub mod sudo_unchecked_weight { - use super::runtime_types; - pub type Call = runtime_types::quantus_runtime::RuntimeCall; - pub type Weight = runtime_types::sp_weights::weight_v2::Weight; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for SudoUncheckedWeight { - const PALLET: &'static str = "Sudo"; - const CALL: &'static str = "sudo_unchecked_weight"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Authenticates the current sudo key and sets the given AccountId (`new`) as the new sudo"] - #[doc = "key."] - pub struct SetKey { - pub new: set_key::New, - } - pub mod set_key { - use super::runtime_types; - pub type New = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for SetKey { - const PALLET: &'static str = "Sudo"; - const CALL: &'static str = "set_key"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Authenticates the sudo key and dispatches a function call with `Signed` origin from"] - #[doc = "a given account."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - pub struct SudoAs { - pub who: sudo_as::Who, - pub call: ::subxt::ext::subxt_core::alloc::boxed::Box, - } - pub mod sudo_as { - use super::runtime_types; - pub type Who = ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >; - pub type Call = runtime_types::quantus_runtime::RuntimeCall; - } - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for SudoAs { - const PALLET: &'static str = "Sudo"; - const CALL: &'static str = "sudo_as"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Permanently removes the sudo key."] - #[doc = ""] - #[doc = "**This cannot be un-done.**"] - pub struct RemoveKey; - impl ::subxt::ext::subxt_core::blocks::StaticExtrinsic for RemoveKey { - const PALLET: &'static str = "Sudo"; - const CALL: &'static str = "remove_key"; - } - } - pub struct TransactionApi; - impl TransactionApi { - #[doc = "Authenticates the sudo key and dispatches a function call with `Root` origin."] - pub fn sudo( - &self, - call: types::sudo::Call, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Sudo", - "sudo", - types::Sudo { - call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), - }, - [ - 92u8, 222u8, 38u8, 218u8, 220u8, 120u8, 153u8, 82u8, 131u8, 21u8, - 133u8, 192u8, 226u8, 24u8, 106u8, 70u8, 156u8, 171u8, 231u8, 175u8, - 152u8, 51u8, 118u8, 15u8, 247u8, 6u8, 137u8, 153u8, 189u8, 181u8, - 207u8, 118u8, - ], - ) - } - #[doc = "Authenticates the sudo key and dispatches a function call with `Root` origin."] - #[doc = "This function does not check the weight of the call, and instead allows the"] - #[doc = "Sudo user to specify the weight of the call."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - pub fn sudo_unchecked_weight( - &self, - call: types::sudo_unchecked_weight::Call, - weight: types::sudo_unchecked_weight::Weight, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload - { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Sudo", - "sudo_unchecked_weight", - types::SudoUncheckedWeight { - call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), - weight, - }, - [ - 18u8, 172u8, 114u8, 181u8, 239u8, 91u8, 227u8, 49u8, 11u8, 101u8, 81u8, - 116u8, 159u8, 79u8, 57u8, 170u8, 121u8, 12u8, 231u8, 89u8, 163u8, 95u8, - 8u8, 144u8, 157u8, 93u8, 162u8, 156u8, 198u8, 99u8, 4u8, 123u8, - ], - ) - } - #[doc = "Authenticates the current sudo key and sets the given AccountId (`new`) as the new sudo"] - #[doc = "key."] - pub fn set_key( - &self, - new: types::set_key::New, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Sudo", - "set_key", - types::SetKey { new }, - [ - 9u8, 73u8, 39u8, 205u8, 188u8, 127u8, 143u8, 54u8, 128u8, 94u8, 8u8, - 227u8, 197u8, 44u8, 70u8, 93u8, 228u8, 196u8, 64u8, 165u8, 226u8, - 158u8, 101u8, 192u8, 22u8, 193u8, 102u8, 84u8, 21u8, 35u8, 92u8, 198u8, - ], - ) - } - #[doc = "Authenticates the sudo key and dispatches a function call with `Signed` origin from"] - #[doc = "a given account."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - pub fn sudo_as( - &self, - who: types::sudo_as::Who, - call: types::sudo_as::Call, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Sudo", - "sudo_as", - types::SudoAs { - who, - call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), - }, - [ - 25u8, 155u8, 115u8, 44u8, 183u8, 108u8, 169u8, 74u8, 11u8, 123u8, - 235u8, 102u8, 23u8, 199u8, 181u8, 104u8, 66u8, 183u8, 147u8, 133u8, - 155u8, 30u8, 203u8, 92u8, 78u8, 234u8, 38u8, 168u8, 178u8, 73u8, 108u8, - 50u8, - ], - ) - } - #[doc = "Permanently removes the sudo key."] - #[doc = ""] - #[doc = "**This cannot be un-done.**"] - pub fn remove_key( - &self, - ) -> ::subxt::ext::subxt_core::tx::payload::StaticPayload { - ::subxt::ext::subxt_core::tx::payload::StaticPayload::new_static( - "Sudo", - "remove_key", - types::RemoveKey {}, - [ - 133u8, 253u8, 54u8, 175u8, 202u8, 239u8, 5u8, 198u8, 180u8, 138u8, - 25u8, 28u8, 109u8, 40u8, 30u8, 56u8, 126u8, 100u8, 52u8, 205u8, 250u8, - 191u8, 61u8, 195u8, 172u8, 142u8, 184u8, 239u8, 247u8, 10u8, 211u8, - 79u8, - ], - ) - } - } - } - #[doc = "The `Event` enum of this pallet"] - pub type Event = runtime_types::pallet_sudo::pallet::Event; - pub mod events { - use super::runtime_types; - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "A sudo call just took place."] - pub struct Sudid { - pub sudo_result: sudid::SudoResult, - } - pub mod sudid { - use super::runtime_types; - pub type SudoResult = - ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for Sudid { - const PALLET: &'static str = "Sudo"; - const EVENT: &'static str = "Sudid"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "The sudo key has been updated."] - pub struct KeyChanged { - pub old: key_changed::Old, - pub new: key_changed::New, - } - pub mod key_changed { - use super::runtime_types; - pub type Old = ::core::option::Option<::subxt::ext::subxt_core::utils::AccountId32>; - pub type New = ::subxt::ext::subxt_core::utils::AccountId32; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for KeyChanged { - const PALLET: &'static str = "Sudo"; - const EVENT: &'static str = "KeyChanged"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "The key was permanently removed."] - pub struct KeyRemoved; - impl ::subxt::ext::subxt_core::events::StaticEvent for KeyRemoved { - const PALLET: &'static str = "Sudo"; - const EVENT: &'static str = "KeyRemoved"; - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode")] - #[encode_as_type(crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode")] - #[doc = "A [sudo_as](Pallet::sudo_as) call just took place."] - pub struct SudoAsDone { - pub sudo_result: sudo_as_done::SudoResult, - } - pub mod sudo_as_done { - use super::runtime_types; - pub type SudoResult = - ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>; - } - impl ::subxt::ext::subxt_core::events::StaticEvent for SudoAsDone { - const PALLET: &'static str = "Sudo"; - const EVENT: &'static str = "SudoAsDone"; - } - } - pub mod storage { - use super::runtime_types; - pub mod types { - use super::runtime_types; - pub mod key { - use super::runtime_types; - pub type Key = ::subxt::ext::subxt_core::utils::AccountId32; - } - } - pub struct StorageApi; - impl StorageApi { - #[doc = " The `AccountId` of the sudo key."] - pub fn key( - &self, - ) -> ::subxt::ext::subxt_core::storage::address::StaticAddress< - (), - types::key::Key, - ::subxt::ext::subxt_core::utils::Yes, - (), - (), - > { - ::subxt::ext::subxt_core::storage::address::StaticAddress::new_static( - "Sudo", - "Key", - (), - [ - 72u8, 14u8, 225u8, 162u8, 205u8, 247u8, 227u8, 105u8, 116u8, 57u8, 4u8, - 31u8, 84u8, 137u8, 227u8, 228u8, 133u8, 245u8, 206u8, 227u8, 117u8, - 36u8, 252u8, 151u8, 107u8, 15u8, 180u8, 4u8, 4u8, 152u8, 195u8, 144u8, - ], - ) - } - } - } - } pub mod q_po_w { use super::{root_mod, runtime_types}; #[doc = "The `Event` enum of this pallet"] @@ -7009,10 +6640,9 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 166u8, 18u8, 39u8, 234u8, 251u8, 53u8, 21u8, 117u8, 134u8, 194u8, - 163u8, 196u8, 144u8, 31u8, 132u8, 122u8, 44u8, 9u8, 134u8, 32u8, 222u8, - 32u8, 173u8, 128u8, 182u8, 71u8, 87u8, 253u8, 109u8, 104u8, 222u8, - 32u8, + 209u8, 44u8, 38u8, 115u8, 192u8, 245u8, 230u8, 98u8, 4u8, 221u8, 48u8, + 218u8, 180u8, 45u8, 205u8, 242u8, 98u8, 60u8, 73u8, 209u8, 152u8, + 217u8, 39u8, 90u8, 46u8, 7u8, 50u8, 50u8, 214u8, 210u8, 178u8, 180u8, ], ) } @@ -7051,10 +6681,9 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 232u8, 133u8, 188u8, 74u8, 36u8, 170u8, 171u8, 99u8, 255u8, 226u8, - 174u8, 26u8, 109u8, 166u8, 144u8, 41u8, 219u8, 85u8, 170u8, 155u8, - 192u8, 22u8, 176u8, 97u8, 47u8, 17u8, 44u8, 223u8, 100u8, 65u8, 69u8, - 35u8, + 168u8, 23u8, 39u8, 121u8, 55u8, 131u8, 250u8, 35u8, 37u8, 194u8, 185u8, + 120u8, 150u8, 83u8, 251u8, 46u8, 33u8, 65u8, 144u8, 38u8, 77u8, 195u8, + 178u8, 91u8, 237u8, 254u8, 91u8, 211u8, 168u8, 181u8, 160u8, 137u8, ], ) } @@ -7090,10 +6719,9 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 128u8, 96u8, 130u8, 203u8, 5u8, 21u8, 127u8, 65u8, 92u8, 180u8, 92u8, - 228u8, 4u8, 71u8, 196u8, 224u8, 121u8, 194u8, 193u8, 213u8, 150u8, - 149u8, 253u8, 188u8, 121u8, 221u8, 209u8, 133u8, 46u8, 247u8, 221u8, - 29u8, + 72u8, 139u8, 81u8, 86u8, 46u8, 244u8, 58u8, 159u8, 117u8, 243u8, 134u8, + 98u8, 80u8, 240u8, 110u8, 81u8, 213u8, 76u8, 158u8, 96u8, 72u8, 193u8, + 249u8, 80u8, 251u8, 116u8, 166u8, 73u8, 81u8, 215u8, 75u8, 220u8, ], ) } @@ -7115,10 +6743,9 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 143u8, 66u8, 101u8, 79u8, 129u8, 219u8, 60u8, 16u8, 207u8, 159u8, - 231u8, 137u8, 114u8, 222u8, 149u8, 153u8, 60u8, 133u8, 35u8, 124u8, - 175u8, 66u8, 67u8, 97u8, 172u8, 207u8, 100u8, 13u8, 27u8, 169u8, 51u8, - 128u8, + 79u8, 224u8, 38u8, 251u8, 249u8, 207u8, 215u8, 115u8, 81u8, 65u8, 63u8, + 214u8, 84u8, 8u8, 50u8, 37u8, 55u8, 55u8, 61u8, 128u8, 25u8, 111u8, + 143u8, 130u8, 144u8, 164u8, 26u8, 145u8, 105u8, 180u8, 88u8, 94u8, ], ) } @@ -8113,9 +7740,9 @@ pub mod api { "batch", types::Batch { calls }, [ - 12u8, 35u8, 169u8, 238u8, 108u8, 124u8, 242u8, 241u8, 158u8, 144u8, - 55u8, 181u8, 164u8, 80u8, 109u8, 149u8, 149u8, 89u8, 202u8, 4u8, 65u8, - 16u8, 217u8, 49u8, 232u8, 146u8, 244u8, 123u8, 48u8, 8u8, 45u8, 101u8, + 241u8, 24u8, 68u8, 209u8, 219u8, 28u8, 161u8, 192u8, 127u8, 101u8, + 153u8, 143u8, 78u8, 9u8, 24u8, 122u8, 110u8, 250u8, 63u8, 159u8, 174u8, + 88u8, 85u8, 23u8, 195u8, 141u8, 225u8, 43u8, 138u8, 241u8, 44u8, 111u8, ], ) } @@ -8145,9 +7772,9 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 58u8, 129u8, 55u8, 87u8, 210u8, 249u8, 143u8, 136u8, 81u8, 237u8, 43u8, - 136u8, 156u8, 85u8, 92u8, 204u8, 228u8, 131u8, 218u8, 62u8, 54u8, 87u8, - 20u8, 248u8, 249u8, 118u8, 83u8, 233u8, 174u8, 3u8, 69u8, 110u8, + 165u8, 80u8, 171u8, 13u8, 254u8, 5u8, 209u8, 126u8, 47u8, 137u8, 90u8, + 96u8, 227u8, 196u8, 159u8, 55u8, 118u8, 49u8, 178u8, 50u8, 178u8, 34u8, + 131u8, 3u8, 41u8, 245u8, 119u8, 197u8, 221u8, 20u8, 174u8, 102u8, ], ) } @@ -8173,9 +7800,9 @@ pub mod api { "batch_all", types::BatchAll { calls }, [ - 160u8, 132u8, 211u8, 158u8, 79u8, 68u8, 196u8, 4u8, 17u8, 136u8, 198u8, - 11u8, 217u8, 69u8, 52u8, 19u8, 244u8, 95u8, 1u8, 43u8, 47u8, 107u8, - 71u8, 70u8, 129u8, 180u8, 96u8, 162u8, 243u8, 62u8, 255u8, 246u8, + 96u8, 62u8, 146u8, 237u8, 252u8, 60u8, 1u8, 202u8, 235u8, 81u8, 106u8, + 115u8, 226u8, 96u8, 214u8, 188u8, 216u8, 173u8, 83u8, 15u8, 78u8, 97u8, + 158u8, 66u8, 225u8, 63u8, 117u8, 196u8, 242u8, 185u8, 28u8, 145u8, ], ) } @@ -8198,9 +7825,10 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 70u8, 236u8, 128u8, 245u8, 79u8, 164u8, 36u8, 254u8, 249u8, 100u8, - 132u8, 160u8, 42u8, 245u8, 92u8, 122u8, 66u8, 71u8, 16u8, 194u8, 241u8, - 243u8, 146u8, 27u8, 3u8, 164u8, 155u8, 37u8, 133u8, 93u8, 15u8, 255u8, + 47u8, 109u8, 230u8, 121u8, 146u8, 49u8, 97u8, 31u8, 138u8, 224u8, + 206u8, 114u8, 57u8, 169u8, 75u8, 158u8, 2u8, 183u8, 138u8, 243u8, + 116u8, 32u8, 225u8, 61u8, 124u8, 106u8, 167u8, 238u8, 236u8, 20u8, + 202u8, 50u8, ], ) } @@ -8226,10 +7854,10 @@ pub mod api { "force_batch", types::ForceBatch { calls }, [ - 201u8, 43u8, 241u8, 144u8, 76u8, 120u8, 232u8, 97u8, 84u8, 126u8, - 227u8, 232u8, 69u8, 158u8, 222u8, 176u8, 144u8, 160u8, 104u8, 207u8, - 5u8, 106u8, 72u8, 119u8, 162u8, 214u8, 219u8, 131u8, 207u8, 153u8, - 24u8, 247u8, + 59u8, 222u8, 239u8, 78u8, 48u8, 183u8, 141u8, 107u8, 147u8, 104u8, + 49u8, 128u8, 119u8, 239u8, 68u8, 174u8, 68u8, 200u8, 166u8, 210u8, + 70u8, 69u8, 239u8, 174u8, 193u8, 143u8, 14u8, 45u8, 194u8, 153u8, + 198u8, 118u8, ], ) } @@ -8252,9 +7880,9 @@ pub mod api { weight, }, [ - 241u8, 184u8, 146u8, 128u8, 160u8, 33u8, 170u8, 130u8, 105u8, 26u8, - 128u8, 181u8, 154u8, 95u8, 76u8, 32u8, 133u8, 8u8, 115u8, 144u8, 198u8, - 25u8, 84u8, 96u8, 155u8, 30u8, 249u8, 235u8, 223u8, 158u8, 37u8, 13u8, + 86u8, 251u8, 42u8, 213u8, 7u8, 59u8, 69u8, 56u8, 170u8, 21u8, 184u8, + 32u8, 192u8, 34u8, 250u8, 122u8, 236u8, 31u8, 174u8, 104u8, 80u8, + 255u8, 209u8, 64u8, 251u8, 39u8, 162u8, 198u8, 163u8, 61u8, 73u8, 91u8, ], ) } @@ -8294,9 +7922,9 @@ pub mod api { fallback: ::subxt::ext::subxt_core::alloc::boxed::Box::new(fallback), }, [ - 199u8, 6u8, 145u8, 140u8, 251u8, 79u8, 237u8, 173u8, 162u8, 41u8, 31u8, - 94u8, 225u8, 34u8, 245u8, 153u8, 233u8, 225u8, 87u8, 190u8, 233u8, - 191u8, 3u8, 25u8, 216u8, 212u8, 30u8, 180u8, 168u8, 145u8, 54u8, 150u8, + 63u8, 128u8, 67u8, 20u8, 83u8, 111u8, 204u8, 20u8, 153u8, 162u8, 212u8, + 42u8, 117u8, 96u8, 212u8, 248u8, 70u8, 189u8, 85u8, 158u8, 136u8, + 110u8, 142u8, 61u8, 39u8, 54u8, 195u8, 118u8, 241u8, 6u8, 55u8, 130u8, ], ) } @@ -8319,10 +7947,9 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 222u8, 246u8, 25u8, 101u8, 155u8, 44u8, 93u8, 141u8, 239u8, 33u8, - 186u8, 124u8, 253u8, 4u8, 203u8, 161u8, 102u8, 220u8, 158u8, 48u8, - 81u8, 82u8, 9u8, 99u8, 50u8, 26u8, 210u8, 64u8, 165u8, 102u8, 227u8, - 84u8, + 167u8, 171u8, 21u8, 97u8, 73u8, 57u8, 83u8, 87u8, 141u8, 218u8, 49u8, + 79u8, 243u8, 165u8, 230u8, 26u8, 227u8, 116u8, 81u8, 203u8, 246u8, + 196u8, 209u8, 183u8, 16u8, 236u8, 9u8, 87u8, 169u8, 76u8, 73u8, 46u8, ], ) } @@ -14312,9 +13939,10 @@ pub mod api { call: ::subxt::ext::subxt_core::alloc::boxed::Box::new(call), }, [ - 0u8, 144u8, 16u8, 19u8, 207u8, 225u8, 184u8, 92u8, 212u8, 17u8, 156u8, - 224u8, 97u8, 23u8, 96u8, 104u8, 207u8, 206u8, 163u8, 26u8, 91u8, 130u8, - 113u8, 130u8, 171u8, 57u8, 255u8, 83u8, 240u8, 20u8, 199u8, 126u8, + 145u8, 166u8, 24u8, 188u8, 62u8, 129u8, 16u8, 49u8, 10u8, 139u8, 33u8, + 24u8, 183u8, 248u8, 92u8, 239u8, 141u8, 11u8, 109u8, 166u8, 232u8, + 206u8, 123u8, 228u8, 213u8, 173u8, 87u8, 199u8, 92u8, 239u8, 240u8, + 30u8, ], ) } @@ -20423,8 +20051,8 @@ pub mod api { #[doc = "Verify an aggregated wormhole proof and process all transfers in the batch."] #[doc = ""] #[doc = "Returns `DispatchResultWithPostInfo` to allow weight correction on early failures."] - #[doc = "If pre-validation fails (deserialization, cheap checks), we return the actual"] - #[doc = "consumed weight to free block capacity for other transactions."] + #[doc = "If validation fails before ZK verification, we return minimal weight."] + #[doc = "If ZK verification fails, we return full weight since the work was done."] pub struct VerifyAggregatedProof { pub proof_bytes: verify_aggregated_proof::ProofBytes, } @@ -20443,8 +20071,8 @@ pub mod api { #[doc = "Verify an aggregated wormhole proof and process all transfers in the batch."] #[doc = ""] #[doc = "Returns `DispatchResultWithPostInfo` to allow weight correction on early failures."] - #[doc = "If pre-validation fails (deserialization, cheap checks), we return the actual"] - #[doc = "consumed weight to free block capacity for other transactions."] + #[doc = "If validation fails before ZK verification, we return minimal weight."] + #[doc = "If ZK verification fails, we return full weight since the work was done."] pub fn verify_aggregated_proof( &self, proof_bytes: types::verify_aggregated_proof::ProofBytes, @@ -26209,125 +25837,6 @@ pub mod api { pub __ignore: ::core::marker::PhantomData<(_4, _5, _2)>, } } - pub mod pallet_sudo { - use super::runtime_types; - pub mod pallet { - use super::runtime_types; - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Contains a variant per dispatchable extrinsic that this pallet has."] - pub enum Call { - #[codec(index = 0)] - #[doc = "Authenticates the sudo key and dispatches a function call with `Root` origin."] - sudo { - call: ::subxt::ext::subxt_core::alloc::boxed::Box< - runtime_types::quantus_runtime::RuntimeCall, - >, - }, - #[codec(index = 1)] - #[doc = "Authenticates the sudo key and dispatches a function call with `Root` origin."] - #[doc = "This function does not check the weight of the call, and instead allows the"] - #[doc = "Sudo user to specify the weight of the call."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - sudo_unchecked_weight { - call: ::subxt::ext::subxt_core::alloc::boxed::Box< - runtime_types::quantus_runtime::RuntimeCall, - >, - weight: runtime_types::sp_weights::weight_v2::Weight, - }, - #[codec(index = 2)] - #[doc = "Authenticates the current sudo key and sets the given AccountId (`new`) as the new sudo"] - #[doc = "key."] - set_key { - new: ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >, - }, - #[codec(index = 3)] - #[doc = "Authenticates the sudo key and dispatches a function call with `Signed` origin from"] - #[doc = "a given account."] - #[doc = ""] - #[doc = "The dispatch origin for this call must be _Signed_."] - sudo_as { - who: ::subxt::ext::subxt_core::utils::MultiAddress< - ::subxt::ext::subxt_core::utils::AccountId32, - (), - >, - call: ::subxt::ext::subxt_core::alloc::boxed::Box< - runtime_types::quantus_runtime::RuntimeCall, - >, - }, - #[codec(index = 4)] - #[doc = "Permanently removes the sudo key."] - #[doc = ""] - #[doc = "**This cannot be un-done.**"] - remove_key, - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "Error for the Sudo pallet."] - pub enum Error { - #[codec(index = 0)] - #[doc = "Sender must be the Sudo account."] - RequireSudo, - } - #[derive( - :: subxt :: ext :: subxt_core :: ext :: scale_decode :: DecodeAsType, - :: subxt :: ext :: subxt_core :: ext :: scale_encode :: EncodeAsType, - Debug, - )] - #[decode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_decode" - )] - #[encode_as_type( - crate_path = ":: subxt :: ext :: subxt_core :: ext :: scale_encode" - )] - #[doc = "The `Event` enum of this pallet"] - pub enum Event { - #[codec(index = 0)] - #[doc = "A sudo call just took place."] - Sudid { - sudo_result: - ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>, - }, - #[codec(index = 1)] - #[doc = "The sudo key has been updated."] - KeyChanged { - old: ::core::option::Option<::subxt::ext::subxt_core::utils::AccountId32>, - new: ::subxt::ext::subxt_core::utils::AccountId32, - }, - #[codec(index = 2)] - #[doc = "The key was permanently removed."] - KeyRemoved, - #[codec(index = 3)] - #[doc = "A [sudo_as](Pallet::sudo_as) call just took place."] - SudoAsDone { - sudo_result: - ::core::result::Result<(), runtime_types::sp_runtime::DispatchError>, - }, - } - } - } pub mod pallet_timestamp { use super::runtime_types; pub mod pallet { @@ -26801,8 +26310,8 @@ pub mod api { #[doc = "Verify an aggregated wormhole proof and process all transfers in the batch."] #[doc = ""] #[doc = "Returns `DispatchResultWithPostInfo` to allow weight correction on early failures."] - #[doc = "If pre-validation fails (deserialization, cheap checks), we return the actual"] - #[doc = "consumed weight to free block capacity for other transactions."] + #[doc = "If validation fails before ZK verification, we return minimal weight."] + #[doc = "If ZK verification fails, we return full weight since the work was done."] verify_aggregated_proof { proof_bytes: ::subxt::ext::subxt_core::alloc::vec::Vec<::core::primitive::u8>, @@ -27063,8 +26572,6 @@ pub mod api { Timestamp(runtime_types::pallet_timestamp::pallet::Call), #[codec(index = 2)] Balances(runtime_types::pallet_balances::pallet::Call), - #[codec(index = 4)] - Sudo(runtime_types::pallet_sudo::pallet::Call), #[codec(index = 7)] Preimage(runtime_types::pallet_preimage::pallet::Call), #[codec(index = 8)] @@ -27104,8 +26611,6 @@ pub mod api { System(runtime_types::frame_system::pallet::Error), #[codec(index = 2)] Balances(runtime_types::pallet_balances::pallet::Error), - #[codec(index = 4)] - Sudo(runtime_types::pallet_sudo::pallet::Error), #[codec(index = 7)] Preimage(runtime_types::pallet_preimage::pallet::Error), #[codec(index = 8)] @@ -27149,8 +26654,6 @@ pub mod api { Balances(runtime_types::pallet_balances::pallet::Event), #[codec(index = 3)] TransactionPayment(runtime_types::pallet_transaction_payment::pallet::Event), - #[codec(index = 4)] - Sudo(runtime_types::pallet_sudo::pallet::Event), #[codec(index = 5)] QPoW(runtime_types::pallet_qpow::pallet::Event), #[codec(index = 6)] diff --git a/src/cli/generic_call.rs b/src/cli/generic_call.rs index fe2049a..6c6797b 100644 --- a/src/cli/generic_call.rs +++ b/src/cli/generic_call.rs @@ -79,9 +79,6 @@ pub async fn execute_generic_call( 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, execution_mode) @@ -117,7 +114,6 @@ pub async fn execute_generic_call( log_print!("💡 Supported pallets in SubXT:"); log_print!(" â€ĸ Balances: transfer_allow_death, transfer_keep_alive"); log_print!(" â€ĸ System: remark"); - log_print!(" â€ĸ Sudo: sudo"); log_print!(" â€ĸ TechCollective: add_member, remove_member, vote"); log_print!(" â€ĸ ReversibleTransfers: schedule_transfer"); log_print!(" â€ĸ Scheduler: schedule, cancel"); @@ -225,20 +221,6 @@ async fn submit_system_remark( .await } -/// Submit sudo call -async fn submit_sudo_call( - _quantus_client: &crate::chain::client::QuantusClient, - _from_keypair: &QuantumKeyPair, - _args: &[Value], -) -> crate::error::Result { - // For now, this is a placeholder - sudo calls need the inner call to be constructed - log_error!("❌ Sudo calls through generic call are complex - use specific sudo wrappers"); - log_print!("💡 Use dedicated subxt commands that already wrap calls in sudo"); - Err(QuantusError::Generic( - "Sudo calls not supported in generic call - use specific commands".to_string(), - )) -} - /// Submit tech collective add member async fn submit_tech_collective_add_member( quantus_client: &crate::chain::client::QuantusClient, @@ -264,17 +246,14 @@ async fn submit_tech_collective_add_member( let member_account_id_subxt = subxt::ext::subxt_core::utils::AccountId32::from(member_account_id_bytes); - // Wrap in sudo for privileged operation - let sudo_call = quantus_subxt::api::tx().sudo().sudo(quantus_subxt::api::Call::TechCollective( - quantus_subxt::api::tech_collective::Call::add_member { - who: subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id_subxt), - }, - )); + let call = quantus_subxt::api::tx().tech_collective().add_member( + subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id_subxt), + ); crate::cli::common::submit_transaction( quantus_client, from_keypair, - sudo_call, + call, None, execution_mode, ) @@ -306,18 +285,15 @@ async fn submit_tech_collective_remove_member( let member_account_id_subxt = subxt::ext::subxt_core::utils::AccountId32::from(member_account_id_bytes); - // Wrap in sudo for privileged operation - let sudo_call = quantus_subxt::api::tx().sudo().sudo(quantus_subxt::api::Call::TechCollective( - quantus_subxt::api::tech_collective::Call::remove_member { - who: subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id_subxt), - min_rank: 0, // Default rank - }, - )); + let call = quantus_subxt::api::tx().tech_collective().remove_member( + subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id_subxt), + 0u16, // Default rank + ); crate::cli::common::submit_transaction( quantus_client, from_keypair, - sudo_call, + call, None, execution_mode, ) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 694baed..f2b2aa3 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -91,7 +91,7 @@ pub enum Commands { #[command(subcommand)] Scheduler(scheduler::SchedulerCommands), - /// Direct interaction with chain storage (Sudo required for set) + /// Direct interaction with chain storage (read-only) #[command(subcommand)] Storage(storage::StorageCommands), @@ -119,7 +119,7 @@ pub enum Commands { #[command(subcommand)] Transfers(transfers::TransfersCommands), - /// Runtime management commands (requires root/sudo permissions) + /// Runtime management commands (via governance where required) #[command(subcommand)] Runtime(runtime::RuntimeCommands), diff --git a/src/cli/runtime.rs b/src/cli/runtime.rs index 08ed810..3a9548c 100644 --- a/src/cli/runtime.rs +++ b/src/cli/runtime.rs @@ -12,13 +12,13 @@ use subxt::OnlineClient; #[derive(Subcommand, Debug)] pub enum RuntimeCommands { - /// Update the runtime using a WASM file (requires root permissions) + /// Propose a runtime upgrade using a WASM file (via Tech Referenda; creates preimage first) Update { /// Path to the runtime WASM file #[arg(short, long)] wasm_file: PathBuf, - /// Wallet name to sign with (must have root/sudo permissions) + /// Wallet name to sign with (must be allowed to submit Tech Referenda) #[arg(short, long)] from: String, @@ -43,7 +43,7 @@ pub enum RuntimeCommands { }, } -/// Update runtime with sudo wrapper +/// Propose runtime upgrade via Tech Referenda (no sudo pallet) pub async fn update_runtime( quantus_client: &crate::chain::client::QuantusClient, wasm_code: Vec, @@ -55,6 +55,8 @@ pub async fn update_runtime( log_print!("📋 Current runtime version:"); log_print!(" â€ĸ Use 'quantus system --runtime' to see current version"); + log_print!("📋 Upgrade path:"); + log_print!(" â€ĸ This submits a Tech Referendum with Root origin (not an immediate root call)"); // Show confirmation prompt unless force is used if !force { @@ -64,9 +66,9 @@ pub async fn update_runtime( "WARNING:".bright_red().bold(), "Runtime update is a critical operation!" ); - log_print!(" â€ĸ This will update the blockchain runtime immediately"); - log_print!(" â€ĸ All nodes will need to upgrade to stay in sync"); - log_print!(" â€ĸ This operation cannot be easily reversed"); + log_print!(" â€ĸ This will submit a governance proposal to upgrade the runtime"); + log_print!(" â€ĸ If approved and enacted, all nodes will need to upgrade to stay in sync"); + log_print!(" â€ĸ Governance operations cannot be easily reversed"); log_print!(""); // Simple confirmation prompt @@ -83,18 +85,62 @@ pub async fn update_runtime( } } - // Create the System::set_code call using RuntimeCall type alias - let set_code_call = - quantus_subxt::api::Call::System(quantus_subxt::api::system::Call::set_code { - code: wasm_code, - }); + // Build a static payload for System::set_code and encode full call data (pallet + call + args) + use sp_runtime::traits::{BlakeTwo256, Hash}; + let set_code_payload = quantus_subxt::api::tx().system().set_code(wasm_code.clone()); + let metadata = quantus_client.client().metadata(); + let encoded_call = <_ as subxt::tx::Payload>::encode_call_data(&set_code_payload, &metadata) + .map_err(|e| QuantusError::Generic(format!("Failed to encode call data: {:?}", e)))?; - // Wrap with sudo for root permissions - let sudo_call = quantus_subxt::api::tx().sudo().sudo(set_code_call); - - // Submit transaction - log_print!("📡 Submitting runtime update transaction..."); + log_print!("📡 Submitting runtime upgrade proposal (preimage + referendum)..."); log_print!("âŗ This may take longer than usual due to WASM size..."); + log_verbose!("📝 Encoded call size: {} bytes", encoded_call.len()); + + let preimage_hash: sp_core::H256 = BlakeTwo256::hash(&encoded_call); + log_print!("🔗 Preimage hash: {:?}", preimage_hash); + + // Submit Preimage::note_preimage with bounded bytes + type PreimageBytes = quantus_subxt::api::preimage::calls::types::note_preimage::Bytes; + let bounded_bytes: PreimageBytes = encoded_call.clone(); + + log_print!("📝 Submitting preimage..."); + let note_preimage_tx = quantus_subxt::api::tx().preimage().note_preimage(bounded_bytes); + let preimage_tx_hash = crate::cli::common::submit_transaction( + quantus_client, + from_keypair, + note_preimage_tx, + None, + execution_mode, + ) + .await?; + log_success!("✅ Preimage transaction submitted: {:?}", preimage_tx_hash); + + // Build TechReferenda::submit call using Lookup preimage reference + type ProposalBounded = + quantus_subxt::api::runtime_types::frame_support::traits::preimages::Bounded< + quantus_subxt::api::runtime_types::quantus_runtime::RuntimeCall, + quantus_subxt::api::runtime_types::sp_runtime::traits::BlakeTwo256, + >; + + let preimage_hash_subxt: subxt::utils::H256 = preimage_hash; + let proposal: ProposalBounded = + ProposalBounded::Lookup { hash: preimage_hash_subxt, len: encoded_call.len() as u32 }; + + let raw_origin_root = + quantus_subxt::api::runtime_types::frame_support::dispatch::RawOrigin::Root; + let origin_caller = + quantus_subxt::api::runtime_types::quantus_runtime::OriginCaller::system(raw_origin_root); + + let enactment = + quantus_subxt::api::runtime_types::frame_support::traits::schedule::DispatchTime::After( + 0u32, + ); + + log_print!("🔧 Creating TechReferenda::submit call..."); + let submit_call = + quantus_subxt::api::tx() + .tech_referenda() + .submit(origin_caller, proposal, enactment); if !execution_mode.finalized { log_print!( @@ -105,14 +151,14 @@ pub async fn update_runtime( let tx_hash = crate::cli::common::submit_transaction( quantus_client, from_keypair, - sudo_call, + submit_call, None, execution_mode, ) .await?; log_success!( - "✅ SUCCESS Runtime update transaction submitted! Hash: 0x{}", + "✅ SUCCESS Runtime upgrade proposal submitted! Hash: 0x{}", hex::encode(tx_hash) ); diff --git a/src/cli/storage.rs b/src/cli/storage.rs index 2ad0ce0..0c95fa4 100644 --- a/src/cli/storage.rs +++ b/src/cli/storage.rs @@ -7,11 +7,11 @@ use crate::{ log_error, log_print, log_success, log_verbose, }; use clap::Subcommand; -use codec::{Decode, Encode}; +use codec::Decode; use colored::Colorize; use serde::Deserialize; use sp_core::{ - crypto::{AccountId32, Ss58Codec}, + crypto::{AccountId32}, twox_128, }; use std::{collections::BTreeMap, str::FromStr}; @@ -52,7 +52,7 @@ fn validate_pallet_exists( Ok(()) } -/// Direct interaction with chain storage (Sudo required for set) +/// Direct interaction with chain storage (read-only) #[derive(Subcommand, Debug)] pub enum StorageCommands { /// Get a storage value from a pallet. @@ -152,40 +152,6 @@ pub enum StorageCommands { block: Option, }, - /// Set a storage value on the chain. - /// - /// This requires sudo privileges. It constructs a `system.set_storage` call - /// and wraps it in a `sudo.sudo` extrinsic. The provided value should be - /// a hex-encoded SCALE representation of the value. - Set { - /// The name of the pallet (e.g., "Scheduler") - #[arg(long)] - pallet: String, - - /// The name of the storage item (e.g., "LastProcessedTimestamp") - #[arg(long)] - name: String, - - /// The new value. Can be a plain string if --type is used, otherwise a hex string. - #[arg(long)] - value: String, - - /// The type of the value to be encoded (e.g., "u64", "moment", "accountid") - #[arg(long)] - r#type: Option, - - /// The name of the wallet to sign the transaction with (must have sudo rights) - #[arg(long)] - wallet: String, - - /// The password for the wallet - #[arg(long)] - password: Option, - - /// Read password from file (for scripting) - #[arg(long)] - password_file: Option, - }, } /// Get block hash from block number or parse existing hash @@ -251,39 +217,6 @@ pub async fn get_storage_raw_at_block( Ok(result) } -/// Set storage value using sudo (requires sudo privileges) -pub async fn set_storage_value( - quantus_client: &crate::chain::client::QuantusClient, - from_keypair: &crate::wallet::QuantumKeyPair, - storage_key: Vec, - value_bytes: Vec, - execution_mode: crate::cli::common::ExecutionMode, -) -> crate::error::Result { - log_verbose!("âœī¸ Creating set_storage transaction..."); - - // Create the System::set_storage call using RuntimeCall type alias - let set_storage_call = - quantus_subxt::api::Call::System(quantus_subxt::api::system::Call::set_storage { - items: vec![(storage_key, value_bytes)], - }); - - // Wrap in Sudo::sudo call - let sudo_call = quantus_subxt::api::tx().sudo().sudo(set_storage_call); - - let tx_hash = crate::cli::common::submit_transaction( - quantus_client, - from_keypair, - sudo_call, - None, - execution_mode, - ) - .await?; - - log_verbose!("📋 Set storage transaction submitted: {:?}", tx_hash); - - Ok(tx_hash) -} - /// List all storage items in a pallet pub async fn list_storage_items( quantus_client: &crate::chain::client::QuantusClient, @@ -805,7 +738,7 @@ async fn get_storage_by_parts( pub async fn handle_storage_command( command: StorageCommands, node_url: &str, - execution_mode: crate::cli::common::ExecutionMode, + _execution_mode: crate::cli::common::ExecutionMode, ) -> crate::error::Result<()> { log_print!("đŸ—„ī¸ Storage"); @@ -847,82 +780,6 @@ pub async fn handle_storage_command( show_storage_stats(&quantus_client, pallet, detailed).await, StorageCommands::Iterate { pallet, name, limit, decode_as, block } => iterate_storage_entries(&quantus_client, &pallet, &name, limit, decode_as, block).await, - - StorageCommands::Set { pallet, name, value, wallet, password, password_file, r#type } => { - log_print!("âœī¸ Setting storage for {}::{}", pallet.bright_green(), name.bright_cyan()); - log_print!("\n{}", "🛑 This is a SUDO operation!".bright_red().bold()); - - // Validate pallet exists - validate_pallet_exists(quantus_client.client(), &pallet)?; - - // 1. Load wallet - let keypair = - crate::wallet::load_keypair_from_wallet(&wallet, password, password_file)?; - log_verbose!("🔐 Using wallet: {}", wallet.bright_green()); - - // 2. Encode the value based on the --type flag - let value_bytes = match r#type.as_deref() { - Some("u64") | Some("moment") => value - .parse::() - .map_err(|e| QuantusError::Generic(format!("Invalid u64 value: {e}")))? - .encode(), - Some("u128") | Some("balance") => value - .parse::() - .map_err(|e| QuantusError::Generic(format!("Invalid u128 value: {e}")))? - .encode(), - Some("accountid") | Some("accountid32") => AccountId32::from_ss58check(&value) - .map_err(|e| QuantusError::Generic(format!("Invalid AccountId value: {e:?}")))? - .encode(), - None => { - // Default to hex decoding if no type is specified - // Try to parse as H256 first, then fall back to hex decode - if value.starts_with("0x") && value.len() == 66 { - // 0x + 64 hex chars = 66 (32 bytes) - // Try to parse as H256 - let h256_value = subxt::utils::H256::from_str(&value).map_err(|e| { - QuantusError::Generic(format!("Invalid H256 value: {e}")) - })?; - h256_value.0.to_vec() - } else { - // Fall back to hex decode for other hex values - let value_hex = value.strip_prefix("0x").unwrap_or(&value); - hex::decode(value_hex) - .map_err(|e| QuantusError::Generic(format!("Invalid hex value: {e}")))? - } - }, - Some(unsupported) => - return Err(QuantusError::Generic(format!( - "Unsupported type for --type: {unsupported}" - ))), - }; - - log_verbose!("Encoded value bytes: 0x{}", hex::encode(&value_bytes).dimmed()); - - // 3. Construct the storage key - let storage_key = { - let mut key = twox_128(pallet.as_bytes()).to_vec(); - key.extend(&twox_128(name.as_bytes())); - key - }; - - // 4. Submit the set storage transaction - let tx_hash = set_storage_value( - &quantus_client, - &keypair, - storage_key, - value_bytes, - execution_mode, - ) - .await?; - - log_print!( - "✅ {} Set storage transaction submitted! Hash: {:?}", - "SUCCESS".bright_green().bold(), - tx_hash - ); - - Ok(()) - }, } } diff --git a/src/cli/tech_collective.rs b/src/cli/tech_collective.rs index 6a8d923..87b44ff 100644 --- a/src/cli/tech_collective.rs +++ b/src/cli/tech_collective.rs @@ -83,13 +83,6 @@ pub enum TechCollectiveCommands { address: String, }, - /// Check who has sudo permissions in the network - CheckSudo { - /// Address to check if it's the sudo account (optional) - #[arg(short, long)] - address: Option, - }, - /// List active Tech Referenda ListReferenda, @@ -101,7 +94,7 @@ pub enum TechCollectiveCommands { }, } -/// Add a member to the Tech Collective using sudo +/// Add a member to the Tech Collective pub async fn add_member( quantus_client: &crate::chain::client::QuantusClient, from_keypair: &crate::wallet::QuantumKeyPair, @@ -121,20 +114,14 @@ pub async fn add_member( log_verbose!("âœī¸ Creating add_member transaction..."); - // Create the TechCollective::add_member call as RuntimeCall enum - let add_member_call = quantus_subxt::api::Call::TechCollective( - quantus_subxt::api::tech_collective::Call::add_member { - who: subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id), - }, + let add_member_call = quantus_subxt::api::tx().tech_collective().add_member( + subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id), ); - // Wrap in Sudo::sudo call - let sudo_call = quantus_subxt::api::tx().sudo().sudo(add_member_call); - let tx_hash = crate::cli::common::submit_transaction( quantus_client, from_keypair, - sudo_call, + add_member_call, None, execution_mode, ) @@ -145,7 +132,7 @@ pub async fn add_member( Ok(tx_hash) } -/// Remove a member from the Tech Collective using sudo +/// Remove a member from the Tech Collective pub async fn remove_member( quantus_client: &crate::chain::client::QuantusClient, from_keypair: &crate::wallet::QuantumKeyPair, @@ -165,21 +152,15 @@ pub async fn remove_member( log_verbose!("âœī¸ Creating remove_member transaction..."); - // Create the TechCollective::remove_member call as RuntimeCall enum - let remove_member_call = quantus_subxt::api::Call::TechCollective( - quantus_subxt::api::tech_collective::Call::remove_member { - who: subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id), - min_rank: 0u16, // Use rank 0 as default - }, + let remove_member_call = quantus_subxt::api::tx().tech_collective().remove_member( + subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id), + 0u16, // Use rank 0 as default ); - // Wrap in Sudo::sudo call - let sudo_call = quantus_subxt::api::tx().sudo().sudo(remove_member_call); - let tx_hash = crate::cli::common::submit_transaction( quantus_client, from_keypair, - sudo_call, + remove_member_call, None, execution_mode, ) @@ -320,35 +301,6 @@ pub async fn get_member_list( Ok(members) } -/// Get sudo account information -pub async fn get_sudo_account( - quantus_client: &crate::chain::client::QuantusClient, -) -> crate::error::Result> { - log_verbose!("🔍 Getting sudo account..."); - - // Query Sudo::Key storage - let storage_addr = quantus_subxt::api::storage().sudo().key(); - - // Get the latest block hash to read from the latest state (not finalized) - let latest_block_hash = quantus_client.get_latest_block().await?; - - let storage_at = quantus_client.client().storage().at(latest_block_hash); - - let sudo_account = storage_at - .fetch(&storage_addr) - .await - .map_err(|e| QuantusError::NetworkError(format!("Failed to fetch sudo account: {e:?}")))?; - - // Convert from subxt_core AccountId32 to sp_core AccountId32 - if let Some(subxt_account) = sudo_account { - let account_bytes: [u8; 32] = *subxt_account.as_ref(); - let sp_account = AccountId32::from(account_bytes); - Ok(Some(sp_account)) - } else { - Ok(None) - } -} - /// Handle tech collective subxt commands pub async fn handle_tech_collective_command( command: TechCollectiveCommands, @@ -470,9 +422,9 @@ pub async fn handle_tech_collective_command( log_print!(""); log_print!("💡 To check specific membership:"); log_print!(" quantus tech-collective is-member --address
"); - log_print!("💡 To add a member (requires sudo):"); + log_print!("💡 To add a member:"); log_print!( - " quantus tech-collective add-member --who
--from " + " quantus tech-collective add-member --who
--from " ); }, @@ -493,42 +445,6 @@ pub async fn handle_tech_collective_command( } }, - TechCollectiveCommands::CheckSudo { address } => { - log_print!("đŸ›ī¸ Checking sudo permissions "); - - match get_sudo_account(&quantus_client).await? { - Some(sudo_account) => { - let sudo_address = sudo_account.to_quantus_ss58(); - log_verbose!("🔍 Found sudo account: {}", sudo_address); - log_success!("✅ Found sudo account: {}", sudo_address.bright_green()); - - // If an address was provided, check if it matches the sudo account - if let Some(check_address) = address { - log_verbose!("🔍 Checking if provided address is sudo..."); - - // Resolve address (could be wallet name or SS58 address) - let resolved_address = resolve_address(&check_address)?; - log_verbose!(" 👤 Address to check: {}", resolved_address); - - if sudo_address == resolved_address { - log_success!("✅ Provided address IS the sudo account!"); - } else { - log_print!("❌ Provided address is NOT the sudo account"); - log_verbose!("💡 Provided address: {}", resolved_address); - log_verbose!("💡 Actual sudo address: {}", sudo_address); - } - } else { - // No address provided, just show the sudo account - log_verbose!("💡 Use 'quantus tech-collective check-sudo --address
' to check if a specific address is sudo"); - } - }, - None => { - log_print!("📭 No sudo account found in network"); - log_verbose!("💡 The network may not have sudo configured"); - }, - } - }, - TechCollectiveCommands::ListReferenda => { log_print!("📜 Active Tech Referenda "); log_print!(""); diff --git a/src/cli/tech_referenda.rs b/src/cli/tech_referenda.rs index 8ec4a31..ae8ef6a 100644 --- a/src/cli/tech_referenda.rs +++ b/src/cli/tech_referenda.rs @@ -48,7 +48,8 @@ pub enum TechReferendaCommands { password_file: Option, }, - /// Submit a proposal to set Treasury `treasury_portion` (Permill) via Tech Referenda (creates preimage first) + /// Submit a proposal to set Treasury `treasury_portion` (Permill) via Tech Referenda (creates + /// preimage first) SubmitTreasuryPortion { /// New treasury portion in Permill (parts per million): 0..=1_000_000 /// @@ -105,63 +106,6 @@ pub enum TechReferendaCommands { password_file: Option, }, - /// Cancel a Tech Referendum (requires root permissions) - Cancel { - /// Referendum index to cancel - #[arg(short, long)] - index: u32, - - /// Wallet name to sign with (must have root permissions) - #[arg(short, long)] - from: String, - - /// Password for the wallet - #[arg(short, long)] - password: Option, - - /// Read password from file - #[arg(long)] - password_file: Option, - }, - - /// Kill a Tech Referendum (requires root permissions) - Kill { - /// Referendum index to kill - #[arg(short, long)] - index: u32, - - /// Wallet name to sign with (must have root permissions) - #[arg(short, long)] - from: String, - - /// Password for the wallet - #[arg(short, long)] - password: Option, - - /// Read password from file - #[arg(long)] - password_file: Option, - }, - - /// Nudge a Tech Referendum to next phase (sudo origin) - Nudge { - /// Referendum index to nudge - #[arg(short, long)] - index: u32, - - /// Wallet name to sign with - #[arg(short, long)] - from: String, - - /// Password for the wallet - #[arg(short, long)] - password: Option, - - /// Read password from file - #[arg(long)] - password_file: Option, - }, - /// Refund submission deposit for a completed Tech Referendum RefundSubmissionDeposit { /// Referendum index @@ -262,15 +206,6 @@ pub async fn handle_tech_referenda_command( execution_mode, ) .await, - TechReferendaCommands::Cancel { index, from, password, password_file } => - 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, execution_mode) - .await, - TechReferendaCommands::Nudge { index, from, password, password_file } => - nudge_proposal(&quantus_client, index, &from, password, password_file, execution_mode) - .await, TechReferendaCommands::RefundSubmissionDeposit { index, from, password, password_file } => refund_submission_deposit( &quantus_client, @@ -718,83 +653,6 @@ async fn place_decision_deposit( Ok(()) } -/// Cancel a Tech Referendum (sudo) -async fn cancel_proposal( - quantus_client: &crate::chain::client::QuantusClient, - index: u32, - from: &str, - password: Option, - password_file: Option, - execution_mode: crate::cli::common::ExecutionMode, -) -> crate::error::Result<()> { - log_print!("❌ Cancelling Tech Referendum #{}", index); - log_print!(" 🔑 Cancelled by: {}", from.bright_yellow()); - - let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; - - let inner = - quantus_subxt::api::Call::TechReferenda(quantus_subxt::api::tech_referenda::Call::cancel { - index, - }); - let sudo_call = quantus_subxt::api::tx().sudo().sudo(inner); - - 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(()) -} - -/// Kill a Tech Referendum (sudo) -async fn kill_proposal( - quantus_client: &crate::chain::client::QuantusClient, - index: u32, - from: &str, - password: Option, - password_file: Option, - execution_mode: crate::cli::common::ExecutionMode, -) -> crate::error::Result<()> { - log_print!("💀 Killing Tech Referendum #{}", index); - log_print!(" 🔑 Killed by: {}", from.bright_yellow()); - - let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; - - let inner = - quantus_subxt::api::Call::TechReferenda(quantus_subxt::api::tech_referenda::Call::kill { - index, - }); - let sudo_call = quantus_subxt::api::tx().sudo().sudo(inner); - - 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(()) -} - -/// Nudge a Tech Referendum to next phase (sudo) -async fn nudge_proposal( - quantus_client: &crate::chain::client::QuantusClient, - index: u32, - from: &str, - password: Option, - password_file: Option, - execution_mode: crate::cli::common::ExecutionMode, -) -> crate::error::Result<()> { - log_print!("🔄 Nudging Tech Referendum #{}", index); - log_print!(" 🔑 Nudged by: {}", from.bright_yellow()); - - let keypair = crate::wallet::load_keypair_from_wallet(from, password, password_file)?; - - let inner = quantus_subxt::api::Call::TechReferenda( - quantus_subxt::api::tech_referenda::Call::nudge_referendum { index }, - ); - let sudo_call = quantus_subxt::api::tx().sudo().sudo(inner); - - 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(()) -} - /// Get Tech Referenda configuration async fn get_config( quantus_client: &crate::chain::client::QuantusClient, diff --git a/src/quantus_metadata.scale b/src/quantus_metadata.scale index 1b842b60d75a463b3257f2266e50a34266593db2..74002ed6fa89073aa69d1f83c0223e40ce935997 100644 GIT binary patch delta 9810 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 Hj3WIv%_py% delta 11215 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 Date: Thu, 9 Apr 2026 17:14:58 +0800 Subject: [PATCH 7/8] fix: FMT --- src/cli/generic_call.rs | 26 +++++++------------------- src/cli/runtime.rs | 5 +---- src/cli/storage.rs | 6 +----- src/cli/tech_collective.rs | 6 +++--- 4 files changed, 12 insertions(+), 31 deletions(-) diff --git a/src/cli/generic_call.rs b/src/cli/generic_call.rs index 6c6797b..bce083d 100644 --- a/src/cli/generic_call.rs +++ b/src/cli/generic_call.rs @@ -246,18 +246,12 @@ async fn submit_tech_collective_add_member( let member_account_id_subxt = subxt::ext::subxt_core::utils::AccountId32::from(member_account_id_bytes); - let call = quantus_subxt::api::tx().tech_collective().add_member( - subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id_subxt), - ); + let call = quantus_subxt::api::tx() + .tech_collective() + .add_member(subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id_subxt)); - crate::cli::common::submit_transaction( - quantus_client, - from_keypair, - call, - None, - execution_mode, - ) - .await + crate::cli::common::submit_transaction(quantus_client, from_keypair, call, None, execution_mode) + .await } /// Submit tech collective remove member @@ -290,14 +284,8 @@ async fn submit_tech_collective_remove_member( 0u16, // Default rank ); - crate::cli::common::submit_transaction( - quantus_client, - from_keypair, - call, - None, - execution_mode, - ) - .await + crate::cli::common::submit_transaction(quantus_client, from_keypair, call, None, execution_mode) + .await } /// Submit tech collective vote diff --git a/src/cli/runtime.rs b/src/cli/runtime.rs index 3a9548c..7c010c6 100644 --- a/src/cli/runtime.rs +++ b/src/cli/runtime.rs @@ -157,10 +157,7 @@ pub async fn update_runtime( ) .await?; - log_success!( - "✅ SUCCESS Runtime upgrade proposal submitted! Hash: 0x{}", - hex::encode(tx_hash) - ); + log_success!("✅ SUCCESS Runtime upgrade proposal submitted! Hash: 0x{}", hex::encode(tx_hash)); Ok(tx_hash) } diff --git a/src/cli/storage.rs b/src/cli/storage.rs index 0c95fa4..ab4a1f1 100644 --- a/src/cli/storage.rs +++ b/src/cli/storage.rs @@ -10,10 +10,7 @@ use clap::Subcommand; use codec::Decode; use colored::Colorize; use serde::Deserialize; -use sp_core::{ - crypto::{AccountId32}, - twox_128, -}; +use sp_core::{crypto::AccountId32, twox_128}; use std::{collections::BTreeMap, str::FromStr}; use subxt::OnlineClient; @@ -151,7 +148,6 @@ pub enum StorageCommands { #[arg(long)] block: Option, }, - } /// Get block hash from block number or parse existing hash diff --git a/src/cli/tech_collective.rs b/src/cli/tech_collective.rs index 87b44ff..b9a9c41 100644 --- a/src/cli/tech_collective.rs +++ b/src/cli/tech_collective.rs @@ -114,9 +114,9 @@ pub async fn add_member( log_verbose!("âœī¸ Creating add_member transaction..."); - let add_member_call = quantus_subxt::api::tx().tech_collective().add_member( - subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id), - ); + let add_member_call = quantus_subxt::api::tx() + .tech_collective() + .add_member(subxt::ext::subxt_core::utils::MultiAddress::Id(member_account_id)); let tx_hash = crate::cli::common::submit_transaction( quantus_client, From 5becac69cdb492a9b8d74674f83c34ba67caffa4 Mon Sep 17 00:00:00 2001 From: Cezary Olborski Date: Thu, 9 Apr 2026 17:36:55 +0800 Subject: [PATCH 8/8] fix: binary generation --- .gitignore | 3 ++- build.rs | 38 +++++++++++++++++++++++++++++++++----- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index e6b176b..dcbb90e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ *.hex # Circuit binaries are generated at build time by build.rs -/generated-bins/ \ No newline at end of file +/generated-bins/ +/generated-bins \ No newline at end of file diff --git a/build.rs b/build.rs index d16bfeb..78a3cda 100644 --- a/build.rs +++ b/build.rs @@ -52,12 +52,40 @@ fn main() { // verification (manifest_dir is inside target/package/ in that case). let project_bins = Path::new(&manifest_dir).join("generated-bins"); if !manifest_dir.contains("target/package/") { - let _ = std::fs::create_dir_all(&project_bins); - if let Ok(entries) = std::fs::read_dir(&build_output_dir) { - for entry in entries.flatten() { - let dest = project_bins.join(entry.file_name()); - let _ = std::fs::copy(entry.path(), dest); + // Prefer a symlink to avoid copying large prover binaries on every build. + // If symlink creation fails (e.g. on filesystems without symlink support), + // fall back to copying and surface errors. + #[cfg(unix)] + { + use std::os::unix::fs::symlink; + // Remove any existing dir/file/symlink at destination. + if let Ok(meta) = std::fs::symlink_metadata(&project_bins) { + if meta.is_dir() { + std::fs::remove_dir_all(&project_bins) + .expect("Failed to remove existing generated-bins directory"); + } else { + std::fs::remove_file(&project_bins) + .expect("Failed to remove existing generated-bins file/symlink"); + } } + if let Err(e) = symlink(&build_output_dir, &project_bins) { + println!( + "cargo:warning=[quantus-cli] Failed to symlink generated-bins ({}). Falling back to copy...", + e + ); + } else { + // Symlink created successfully; we're done. + return; + } + } + + std::fs::create_dir_all(&project_bins).expect("Failed to create generated-bins directory"); + let entries = std::fs::read_dir(&build_output_dir) + .expect("Failed to read generated-bins directory in OUT_DIR"); + for entry in entries { + let entry = entry.expect("Failed to read generated-bins entry"); + let dest = project_bins.join(entry.file_name()); + std::fs::copy(entry.path(), dest).expect("Failed to copy generated-bins file"); } } }