Skip to content

Commit 70965f0

Browse files
committed
ref(utils): use types in desc output in utils
1 parent 2ce28b2 commit 70965f0

4 files changed

Lines changed: 98 additions & 147 deletions

File tree

src/handlers/descriptor.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@ use crate::{
22
error::BDKCliError as Error,
33
utils::{
44
descriptors::{
5-
format_descriptor_output, generate_descriptor_from_mnemonic,
6-
generate_descriptor_with_mnemonic, generate_descriptors,
5+
generate_descriptor_from_mnemonic, generate_descriptor_with_mnemonic,
6+
generate_descriptors,
77
},
88
is_mnemonic,
9+
output::FormatOutput,
910
},
1011
};
1112

1213
#[cfg(feature = "compiler")]
1314
use {
1415
crate::handlers::types::DescriptorResult,
15-
crate::utils::output::FormatOutput,
1616
bdk_wallet::{
1717
bitcoin::XOnlyPublicKey,
1818
miniscript::{
@@ -48,7 +48,7 @@ pub fn handle_descriptor_command(
4848
// Generate new mnemonic and descriptors
4949
None => generate_descriptor_with_mnemonic(network, &desc_type),
5050
}?;
51-
format_descriptor_output(&result, pretty)
51+
result.format(pretty)
5252
}
5353

5454
/// Handle the miniscript compiler sub-command
@@ -99,6 +99,7 @@ pub(crate) fn handle_compile_subcommand(
9999
public_descriptors: None,
100100
private_descriptors: None,
101101
mnemonic: None,
102+
fingerprint: None,
102103
};
103104
result.format(pretty)
104105
}

src/handlers/types.rs

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -70,29 +70,28 @@ pub struct TransactionListResult(pub Vec<TransactionDetails>);
7070

7171
impl FormatOutput for TransactionListResult {
7272
fn to_table(&self) -> Result<String, Error> {
73-
let mut rows: Vec<Vec<CellStruct>> = vec![];
74-
75-
for tx in &self.0 {
76-
rows.push(vec![
73+
let rows = self.0.iter().map(|tx| {
74+
vec![
7775
tx.txid.clone().cell(),
7876
tx.version_display.clone().cell().justify(Justify::Right),
7977
tx.is_rbf.to_string().cell().justify(Justify::Center),
8078
tx.input_count.to_string().cell().justify(Justify::Right),
8179
tx.output_count.to_string().cell().justify(Justify::Right),
8280
tx.total_value.to_string().cell().justify(Justify::Right),
83-
]);
84-
}
81+
]
82+
});
8583

86-
let title = vec![
87-
"Txid".cell().bold(true),
88-
"Version".cell().bold(true),
89-
"Is RBF".cell().bold(true),
90-
"Input Count".cell().bold(true),
91-
"Output Count".cell().bold(true),
92-
"Total Value (sat)".cell().bold(true),
93-
];
94-
95-
simple_table(rows, Some(title))
84+
simple_table(
85+
rows,
86+
Some(vec![
87+
"Txid".cell().bold(true),
88+
"Version".cell().bold(true),
89+
"Is RBF".cell().bold(true),
90+
"Input Count".cell().bold(true),
91+
"Output Count".cell().bold(true),
92+
"Total Value (sat)".cell().bold(true),
93+
]),
94+
)
9695
}
9796
}
9897

@@ -400,21 +399,20 @@ impl FormatOutput for WalletsListResult {
400399
return Ok("No wallets configured yet.".to_string());
401400
}
402401

403-
let mut rows: Vec<Vec<CellStruct>> = vec![];
404-
for (name, inner) in &self.0 {
402+
let rows = self.0.iter().map(|(name, inner)| {
405403
let desc: String = inner.ext_descriptor.chars().take(30).collect();
406404
let desc_display = if inner.ext_descriptor.len() > 30 {
407405
format!("{}...", desc)
408406
} else {
409407
desc
410408
};
411409

412-
rows.push(vec![
410+
vec![
413411
name.clone().cell(),
414412
inner.network.clone().cell(),
415413
desc_display.cell(),
416-
]);
417-
}
414+
]
415+
});
418416

419417
simple_table(
420418
rows,
@@ -427,47 +425,68 @@ impl FormatOutput for WalletsListResult {
427425
}
428426
}
429427

430-
431428
#[derive(Serialize)]
432429
pub struct DescriptorResult {
433430
#[serde(skip_serializing_if = "Option::is_none")]
434431
pub descriptor: Option<String>,
435-
432+
436433
#[serde(skip_serializing_if = "Option::is_none")]
437434
pub multipath_descriptor: Option<String>,
438-
435+
439436
#[serde(skip_serializing_if = "Option::is_none")]
440437
pub public_descriptors: Option<KeychainPair<String>>,
441-
438+
442439
#[serde(skip_serializing_if = "Option::is_none")]
443440
pub private_descriptors: Option<KeychainPair<String>>,
444-
441+
445442
#[serde(skip_serializing_if = "Option::is_none")]
446443
pub mnemonic: Option<String>,
444+
445+
#[serde(skip_serializing_if = "Option::is_none")]
446+
pub fingerprint: Option<String>,
447447
}
448448

449449
impl FormatOutput for DescriptorResult {
450450
fn to_table(&self) -> Result<String, Error> {
451451
let mut rows: Vec<Vec<CellStruct>> = vec![];
452-
452+
453453
if let Some(desc) = &self.descriptor {
454454
rows.push(vec!["Descriptor".cell().bold(true), desc.clone().cell()]);
455455
}
456456
if let Some(desc) = &self.multipath_descriptor {
457-
rows.push(vec!["Multipath Descriptor".cell().bold(true), desc.clone().cell()]);
457+
rows.push(vec![
458+
"Multipath Descriptor".cell().bold(true),
459+
desc.clone().cell(),
460+
]);
458461
}
459462
if let Some(pub_desc) = &self.public_descriptors {
460-
rows.push(vec!["External Public".cell().bold(true), pub_desc.external.clone().cell()]);
461-
rows.push(vec!["Internal Public".cell().bold(true), pub_desc.internal.clone().cell()]);
463+
rows.push(vec![
464+
"External Public".cell().bold(true),
465+
pub_desc.external.clone().cell(),
466+
]);
467+
rows.push(vec![
468+
"Internal Public".cell().bold(true),
469+
pub_desc.internal.clone().cell(),
470+
]);
462471
}
463472
if let Some(priv_desc) = &self.private_descriptors {
464-
rows.push(vec!["External Private".cell().bold(true), priv_desc.external.clone().cell()]);
465-
rows.push(vec!["Internal Private".cell().bold(true), priv_desc.internal.clone().cell()]);
473+
rows.push(vec![
474+
"External Private".cell().bold(true),
475+
priv_desc.external.clone().cell(),
476+
]);
477+
rows.push(vec![
478+
"Internal Private".cell().bold(true),
479+
priv_desc.internal.clone().cell(),
480+
]);
466481
}
467482
if let Some(mnemonic) = &self.mnemonic {
468483
rows.push(vec!["Mnemonic".cell().bold(true), mnemonic.clone().cell()]);
469484
}
470485

486+
if let Some(fp) = &self.fingerprint {
487+
rows.push(vec!["Fingerprint".cell().bold(true), fp.clone().cell()]);
488+
}
489+
471490
simple_table(rows, None)
472491
}
473492
}

src/utils/descriptors.rs

Lines changed: 37 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,15 @@ use bdk_wallet::{
1717
},
1818
template::DescriptorTemplate,
1919
};
20-
use cli_table::{Cell, CellStruct, Style, Table};
21-
use serde_json::{Value, json};
2220

2321
use crate::error::BDKCliError as Error;
22+
use crate::handlers::types::{DescriptorResult, KeychainPair};
2423

25-
pub fn generate_descriptors(desc_type: &str, key: &str, network: Network) -> Result<Value, Error> {
24+
pub fn generate_descriptors(
25+
desc_type: &str,
26+
key: &str,
27+
network: Network,
28+
) -> Result<DescriptorResult, Error> {
2629
let is_private = key.starts_with("xprv") || key.starts_with("tprv");
2730

2831
if is_private {
@@ -49,7 +52,7 @@ fn generate_private_descriptors(
4952
desc_type: &str,
5053
key: &str,
5154
network: Network,
52-
) -> Result<Value, Error> {
55+
) -> Result<DescriptorResult, Error> {
5356
use bdk_wallet::template::{Bip44, Bip49, Bip84, Bip86};
5457

5558
let secp = Secp256k1::new();
@@ -85,25 +88,28 @@ fn generate_private_descriptors(
8588
let internal_priv = internal_desc.to_string_with_secret(&internal_keymap);
8689
let internal_pub = internal_desc.to_string();
8790

88-
Ok(json!({
89-
"public_descriptors": {
90-
"external": external_pub,
91-
"internal": internal_pub
92-
},
93-
"private_descriptors": {
94-
"external": external_priv,
95-
"internal": internal_priv
96-
},
97-
"fingerprint": fingerprint.to_string()
98-
}))
91+
Ok(DescriptorResult {
92+
descriptor: None,
93+
multipath_descriptor: None,
94+
public_descriptors: Some(KeychainPair {
95+
external: external_pub,
96+
internal: internal_pub,
97+
}),
98+
private_descriptors: Some(KeychainPair {
99+
external: external_priv,
100+
internal: internal_priv,
101+
}),
102+
mnemonic: None,
103+
fingerprint: Some(fingerprint.to_string()),
104+
})
99105
}
100106

101107
/// Generate descriptors from public key (xpub/tpub)
102108
pub fn generate_public_descriptors(
103109
desc_type: &str,
104110
key: &str,
105111
derivation_path: &DerivationPath,
106-
) -> Result<Value, Error> {
112+
) -> Result<DescriptorResult, Error> {
107113
let xpub: Xpub = key.parse()?;
108114
let fingerprint = xpub.fingerprint();
109115

@@ -122,14 +128,17 @@ pub fn generate_public_descriptors(
122128

123129
let external_pub = build_descriptor("0")?;
124130
let internal_pub = build_descriptor("1")?;
125-
126-
Ok(json!({
127-
"public_descriptors": {
128-
"external": external_pub,
129-
"internal": internal_pub
130-
},
131-
"fingerprint": fingerprint.to_string()
132-
}))
131+
Ok(DescriptorResult {
132+
descriptor: None,
133+
multipath_descriptor: None,
134+
public_descriptors: Some(KeychainPair {
135+
external: external_pub,
136+
internal: internal_pub,
137+
}),
138+
private_descriptors: None,
139+
mnemonic: None,
140+
fingerprint: Some(fingerprint.to_string()),
141+
})
133142
}
134143

135144
/// Build a descriptor from a public key
@@ -158,15 +167,15 @@ pub fn build_public_descriptor(
158167
pub fn generate_descriptor_with_mnemonic(
159168
network: Network,
160169
desc_type: &str,
161-
) -> Result<serde_json::Value, Error> {
170+
) -> Result<DescriptorResult, Error> {
162171
let mnemonic: GeneratedKey<Mnemonic, Segwitv0> =
163172
Mnemonic::generate((WordCount::Words12, Language::English)).map_err(Error::BIP39Error)?;
164173

165174
let seed = mnemonic.to_seed("");
166175
let xprv = Xpriv::new_master(network, &seed)?;
167176

168177
let mut result = generate_descriptors(desc_type, &xprv.to_string(), network)?;
169-
result["mnemonic"] = json!(mnemonic.to_string());
178+
result.mnemonic = Some(mnemonic.to_string());
170179
Ok(result)
171180
}
172181

@@ -175,91 +184,12 @@ pub fn generate_descriptor_from_mnemonic(
175184
mnemonic_str: &str,
176185
network: Network,
177186
desc_type: &str,
178-
) -> Result<serde_json::Value, Error> {
187+
) -> Result<DescriptorResult, Error> {
179188
let mnemonic = Mnemonic::parse_in(Language::English, mnemonic_str)?;
180189
let seed = mnemonic.to_seed("");
181190
let xprv = Xpriv::new_master(network, &seed)?;
182191

183192
let mut result = generate_descriptors(desc_type, &xprv.to_string(), network)?;
184-
result["mnemonic"] = json!(mnemonic_str);
193+
result.mnemonic = Some(mnemonic_str.to_string());
185194
Ok(result)
186195
}
187-
188-
pub fn format_descriptor_output(result: &Value, pretty: bool) -> Result<String, Error> {
189-
if !pretty {
190-
return Ok(serde_json::to_string_pretty(result)?);
191-
}
192-
193-
let mut rows: Vec<Vec<CellStruct>> = vec![];
194-
195-
if let Some(desc_type) = result.get("type") {
196-
rows.push(vec![
197-
"Type".cell().bold(true),
198-
desc_type.as_str().unwrap_or("N/A").cell(),
199-
]);
200-
}
201-
202-
if let Some(finger_print) = result.get("fingerprint") {
203-
rows.push(vec![
204-
"Fingerprint".cell().bold(true),
205-
finger_print.as_str().unwrap_or("N/A").cell(),
206-
]);
207-
}
208-
209-
if let Some(network) = result.get("network") {
210-
rows.push(vec![
211-
"Network".cell().bold(true),
212-
network.as_str().unwrap_or("N/A").cell(),
213-
]);
214-
}
215-
if let Some(multipath_desc) = result.get("multipath_descriptor") {
216-
rows.push(vec![
217-
"Multipart Descriptor".cell().bold(true),
218-
multipath_desc.as_str().unwrap_or("N/A").cell(),
219-
]);
220-
}
221-
if let Some(pub_descs) = result.get("public_descriptors").and_then(|v| v.as_object()) {
222-
if let Some(ext) = pub_descs.get("external") {
223-
rows.push(vec![
224-
"External Public".cell().bold(true),
225-
ext.as_str().unwrap_or("N/A").cell(),
226-
]);
227-
}
228-
if let Some(int) = pub_descs.get("internal") {
229-
rows.push(vec![
230-
"Internal Public".cell().bold(true),
231-
int.as_str().unwrap_or("N/A").cell(),
232-
]);
233-
}
234-
}
235-
if let Some(priv_descs) = result
236-
.get("private_descriptors")
237-
.and_then(|v| v.as_object())
238-
{
239-
if let Some(ext) = priv_descs.get("external") {
240-
rows.push(vec![
241-
"External Private".cell().bold(true),
242-
ext.as_str().unwrap_or("N/A").cell(),
243-
]);
244-
}
245-
if let Some(int) = priv_descs.get("internal") {
246-
rows.push(vec![
247-
"Internal Private".cell().bold(true),
248-
int.as_str().unwrap_or("N/A").cell(),
249-
]);
250-
}
251-
}
252-
if let Some(mnemonic) = result.get("mnemonic") {
253-
rows.push(vec![
254-
"Mnemonic".cell().bold(true),
255-
mnemonic.as_str().unwrap_or("N/A").cell(),
256-
]);
257-
}
258-
259-
let table = rows
260-
.table()
261-
.display()
262-
.map_err(|e| Error::Generic(e.to_string()))?;
263-
264-
Ok(format!("{table}"))
265-
}

0 commit comments

Comments
 (0)