From: Vihiga Tyonum Date: Wed, 29 Apr 2026 15:35:19 +0000 (+0100) Subject: ref(utils): use types in desc output in utils X-Git-Url: http://internal-gitweb-vhost/blockdata/script/encode/-script/display/struct.DisplayArray.html?a=commitdiff_plain;h=ada34858d7e2d2a29dfa7d3ccfd311ff19a919f6;p=bdk-cli ref(utils): use types in desc output in utils --- diff --git a/src/handlers/descriptor.rs b/src/handlers/descriptor.rs index 44f1954..9babbc8 100644 --- a/src/handlers/descriptor.rs +++ b/src/handlers/descriptor.rs @@ -2,17 +2,17 @@ use crate::{ error::BDKCliError as Error, utils::{ descriptors::{ - format_descriptor_output, generate_descriptor_from_mnemonic, - generate_descriptor_with_mnemonic, generate_descriptors, + generate_descriptor_from_mnemonic, generate_descriptor_with_mnemonic, + generate_descriptors, }, is_mnemonic, + output::FormatOutput, }, }; #[cfg(feature = "compiler")] use { crate::handlers::types::DescriptorResult, - crate::utils::output::FormatOutput, bdk_wallet::{ bitcoin::XOnlyPublicKey, miniscript::{ @@ -48,7 +48,7 @@ pub fn handle_descriptor_command( // Generate new mnemonic and descriptors None => generate_descriptor_with_mnemonic(network, &desc_type), }?; - format_descriptor_output(&result, pretty) + result.format(pretty) } /// Handle the miniscript compiler sub-command @@ -99,6 +99,7 @@ pub(crate) fn handle_compile_subcommand( public_descriptors: None, private_descriptors: None, mnemonic: None, + fingerprint: None, }; result.format(pretty) } diff --git a/src/handlers/types.rs b/src/handlers/types.rs index 51a1b56..dacd578 100644 --- a/src/handlers/types.rs +++ b/src/handlers/types.rs @@ -70,29 +70,28 @@ pub struct TransactionListResult(pub Vec); impl FormatOutput for TransactionListResult { fn to_table(&self) -> Result { - let mut rows: Vec> = vec![]; - - for tx in &self.0 { - rows.push(vec![ + let rows = self.0.iter().map(|tx| { + vec![ tx.txid.clone().cell(), tx.version_display.clone().cell().justify(Justify::Right), tx.is_rbf.to_string().cell().justify(Justify::Center), tx.input_count.to_string().cell().justify(Justify::Right), tx.output_count.to_string().cell().justify(Justify::Right), tx.total_value.to_string().cell().justify(Justify::Right), - ]); - } + ] + }); - let title = vec![ - "Txid".cell().bold(true), - "Version".cell().bold(true), - "Is RBF".cell().bold(true), - "Input Count".cell().bold(true), - "Output Count".cell().bold(true), - "Total Value (sat)".cell().bold(true), - ]; - - simple_table(rows, Some(title)) + simple_table( + rows, + Some(vec![ + "Txid".cell().bold(true), + "Version".cell().bold(true), + "Is RBF".cell().bold(true), + "Input Count".cell().bold(true), + "Output Count".cell().bold(true), + "Total Value (sat)".cell().bold(true), + ]), + ) } } @@ -400,8 +399,7 @@ impl FormatOutput for WalletsListResult { return Ok("No wallets configured yet.".to_string()); } - let mut rows: Vec> = vec![]; - for (name, inner) in &self.0 { + let rows = self.0.iter().map(|(name, inner)| { let desc: String = inner.ext_descriptor.chars().take(30).collect(); let desc_display = if inner.ext_descriptor.len() > 30 { format!("{}...", desc) @@ -409,12 +407,12 @@ impl FormatOutput for WalletsListResult { desc }; - rows.push(vec![ + vec![ name.clone().cell(), inner.network.clone().cell(), desc_display.cell(), - ]); - } + ] + }); simple_table( rows, @@ -427,47 +425,68 @@ impl FormatOutput for WalletsListResult { } } - #[derive(Serialize)] pub struct DescriptorResult { #[serde(skip_serializing_if = "Option::is_none")] pub descriptor: Option, - + #[serde(skip_serializing_if = "Option::is_none")] pub multipath_descriptor: Option, - + #[serde(skip_serializing_if = "Option::is_none")] pub public_descriptors: Option>, - + #[serde(skip_serializing_if = "Option::is_none")] pub private_descriptors: Option>, - + #[serde(skip_serializing_if = "Option::is_none")] pub mnemonic: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub fingerprint: Option, } impl FormatOutput for DescriptorResult { fn to_table(&self) -> Result { let mut rows: Vec> = vec![]; - + if let Some(desc) = &self.descriptor { rows.push(vec!["Descriptor".cell().bold(true), desc.clone().cell()]); } if let Some(desc) = &self.multipath_descriptor { - rows.push(vec!["Multipath Descriptor".cell().bold(true), desc.clone().cell()]); + rows.push(vec![ + "Multipath Descriptor".cell().bold(true), + desc.clone().cell(), + ]); } if let Some(pub_desc) = &self.public_descriptors { - rows.push(vec!["External Public".cell().bold(true), pub_desc.external.clone().cell()]); - rows.push(vec!["Internal Public".cell().bold(true), pub_desc.internal.clone().cell()]); + rows.push(vec![ + "External Public".cell().bold(true), + pub_desc.external.clone().cell(), + ]); + rows.push(vec![ + "Internal Public".cell().bold(true), + pub_desc.internal.clone().cell(), + ]); } if let Some(priv_desc) = &self.private_descriptors { - rows.push(vec!["External Private".cell().bold(true), priv_desc.external.clone().cell()]); - rows.push(vec!["Internal Private".cell().bold(true), priv_desc.internal.clone().cell()]); + rows.push(vec![ + "External Private".cell().bold(true), + priv_desc.external.clone().cell(), + ]); + rows.push(vec![ + "Internal Private".cell().bold(true), + priv_desc.internal.clone().cell(), + ]); } if let Some(mnemonic) = &self.mnemonic { rows.push(vec!["Mnemonic".cell().bold(true), mnemonic.clone().cell()]); } + if let Some(fp) = &self.fingerprint { + rows.push(vec!["Fingerprint".cell().bold(true), fp.clone().cell()]); + } + simple_table(rows, None) } } diff --git a/src/utils/descriptors.rs b/src/utils/descriptors.rs index 30a0f23..d228999 100644 --- a/src/utils/descriptors.rs +++ b/src/utils/descriptors.rs @@ -17,12 +17,15 @@ use bdk_wallet::{ }, template::DescriptorTemplate, }; -use cli_table::{Cell, CellStruct, Style, Table}; -use serde_json::{Value, json}; use crate::error::BDKCliError as Error; +use crate::handlers::types::{DescriptorResult, KeychainPair}; -pub fn generate_descriptors(desc_type: &str, key: &str, network: Network) -> Result { +pub fn generate_descriptors( + desc_type: &str, + key: &str, + network: Network, +) -> Result { let is_private = key.starts_with("xprv") || key.starts_with("tprv"); if is_private { @@ -49,7 +52,7 @@ fn generate_private_descriptors( desc_type: &str, key: &str, network: Network, -) -> Result { +) -> Result { use bdk_wallet::template::{Bip44, Bip49, Bip84, Bip86}; let secp = Secp256k1::new(); @@ -85,17 +88,20 @@ fn generate_private_descriptors( let internal_priv = internal_desc.to_string_with_secret(&internal_keymap); let internal_pub = internal_desc.to_string(); - Ok(json!({ - "public_descriptors": { - "external": external_pub, - "internal": internal_pub - }, - "private_descriptors": { - "external": external_priv, - "internal": internal_priv - }, - "fingerprint": fingerprint.to_string() - })) + Ok(DescriptorResult { + descriptor: None, + multipath_descriptor: None, + public_descriptors: Some(KeychainPair { + external: external_pub, + internal: internal_pub, + }), + private_descriptors: Some(KeychainPair { + external: external_priv, + internal: internal_priv, + }), + mnemonic: None, + fingerprint: Some(fingerprint.to_string()), + }) } /// Generate descriptors from public key (xpub/tpub) @@ -103,7 +109,7 @@ pub fn generate_public_descriptors( desc_type: &str, key: &str, derivation_path: &DerivationPath, -) -> Result { +) -> Result { let xpub: Xpub = key.parse()?; let fingerprint = xpub.fingerprint(); @@ -122,14 +128,17 @@ pub fn generate_public_descriptors( let external_pub = build_descriptor("0")?; let internal_pub = build_descriptor("1")?; - - Ok(json!({ - "public_descriptors": { - "external": external_pub, - "internal": internal_pub - }, - "fingerprint": fingerprint.to_string() - })) + Ok(DescriptorResult { + descriptor: None, + multipath_descriptor: None, + public_descriptors: Some(KeychainPair { + external: external_pub, + internal: internal_pub, + }), + private_descriptors: None, + mnemonic: None, + fingerprint: Some(fingerprint.to_string()), + }) } /// Build a descriptor from a public key @@ -158,7 +167,7 @@ pub fn build_public_descriptor( pub fn generate_descriptor_with_mnemonic( network: Network, desc_type: &str, -) -> Result { +) -> Result { let mnemonic: GeneratedKey = Mnemonic::generate((WordCount::Words12, Language::English)).map_err(Error::BIP39Error)?; @@ -166,7 +175,7 @@ pub fn generate_descriptor_with_mnemonic( let xprv = Xpriv::new_master(network, &seed)?; let mut result = generate_descriptors(desc_type, &xprv.to_string(), network)?; - result["mnemonic"] = json!(mnemonic.to_string()); + result.mnemonic = Some(mnemonic.to_string()); Ok(result) } @@ -175,91 +184,12 @@ pub fn generate_descriptor_from_mnemonic( mnemonic_str: &str, network: Network, desc_type: &str, -) -> Result { +) -> Result { let mnemonic = Mnemonic::parse_in(Language::English, mnemonic_str)?; let seed = mnemonic.to_seed(""); let xprv = Xpriv::new_master(network, &seed)?; let mut result = generate_descriptors(desc_type, &xprv.to_string(), network)?; - result["mnemonic"] = json!(mnemonic_str); + result.mnemonic = Some(mnemonic_str.to_string()); Ok(result) } - -pub fn format_descriptor_output(result: &Value, pretty: bool) -> Result { - if !pretty { - return Ok(serde_json::to_string_pretty(result)?); - } - - let mut rows: Vec> = vec![]; - - if let Some(desc_type) = result.get("type") { - rows.push(vec![ - "Type".cell().bold(true), - desc_type.as_str().unwrap_or("N/A").cell(), - ]); - } - - if let Some(finger_print) = result.get("fingerprint") { - rows.push(vec![ - "Fingerprint".cell().bold(true), - finger_print.as_str().unwrap_or("N/A").cell(), - ]); - } - - if let Some(network) = result.get("network") { - rows.push(vec![ - "Network".cell().bold(true), - network.as_str().unwrap_or("N/A").cell(), - ]); - } - if let Some(multipath_desc) = result.get("multipath_descriptor") { - rows.push(vec![ - "Multipart Descriptor".cell().bold(true), - multipath_desc.as_str().unwrap_or("N/A").cell(), - ]); - } - if let Some(pub_descs) = result.get("public_descriptors").and_then(|v| v.as_object()) { - if let Some(ext) = pub_descs.get("external") { - rows.push(vec![ - "External Public".cell().bold(true), - ext.as_str().unwrap_or("N/A").cell(), - ]); - } - if let Some(int) = pub_descs.get("internal") { - rows.push(vec![ - "Internal Public".cell().bold(true), - int.as_str().unwrap_or("N/A").cell(), - ]); - } - } - if let Some(priv_descs) = result - .get("private_descriptors") - .and_then(|v| v.as_object()) - { - if let Some(ext) = priv_descs.get("external") { - rows.push(vec![ - "External Private".cell().bold(true), - ext.as_str().unwrap_or("N/A").cell(), - ]); - } - if let Some(int) = priv_descs.get("internal") { - rows.push(vec![ - "Internal Private".cell().bold(true), - int.as_str().unwrap_or("N/A").cell(), - ]); - } - } - if let Some(mnemonic) = result.get("mnemonic") { - rows.push(vec![ - "Mnemonic".cell().bold(true), - mnemonic.as_str().unwrap_or("N/A").cell(), - ]); - } - - let table = rows - .table() - .display() - .map_err(|e| Error::Generic(e.to_string()))?; - - Ok(format!("{table}")) -} diff --git a/src/utils/output.rs b/src/utils/output.rs index 5c4360b..4ad6e8e 100644 --- a/src/utils/output.rs +++ b/src/utils/output.rs @@ -19,10 +19,11 @@ pub trait FormatOutput: Serialize { } /// Helper for building simple tables -pub fn simple_table( - rows: Vec>, - title: Option>, -) -> Result { +pub fn simple_table(rows: R, title: Option>) -> Result +where + R: IntoIterator, + C: IntoIterator, +{ let mut table = rows.table(); if let Some(title) = title { table = table.title(title);