Skip to content

Commit 91bb4bf

Browse files
committed
Update functions and command
1 parent b4ea29d commit 91bb4bf

File tree

4 files changed

+78
-35
lines changed

4 files changed

+78
-35
lines changed

Cargo.lock

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ thiserror = "2.0.11"
2222
tokio = { version = "1", features = ["full"] }
2323
anyhow = "1.0"
2424
serde = { version = "1.0", features = ["derive"] }
25+
miniscript = "12.3.2"
2526

2627
# Optional dependencies
2728
bdk_bitcoind_rpc = { version = "0.18.0", optional = true }

src/commands.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,6 @@ pub struct GenerateDescriptorArgs {
140140
#[clap(long)]
141141
pub multipath: bool,
142142

143-
#[clap(long)]
144-
pub weak: Option<String>, // If present, user supplied a weak string
145-
146143
pub key: Option<String>, // Positional argument (tprv/tpub/xprv/xpub)
147144
}
148145

src/descriptor_handler.rs

Lines changed: 74 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,24 @@ use bdk_wallet::bitcoin::Network;
88
use bdk_wallet::descriptor::Segwitv0;
99
use bdk_wallet::keys::bip39::{Language, Mnemonic, WordCount};
1010
use bdk_wallet::keys::{GeneratableKey, GeneratedKey};
11-
use bdk_wallet::miniscript::{Descriptor, DescriptorPublicKey};
11+
12+
use bdk_wallet::bitcoin::bip32::DerivationPath;
13+
use bdk_wallet::descriptor::{Descriptor, DescriptorPublicKey};
14+
15+
use bdk_wallet::keys::{DescriptorSecretKey, IntoDescriptorKey};
16+
use miniscript::descriptor::{DescriptorXKey, Wildcard};
17+
18+
use std::str::FromStr;
1219

1320
pub fn generate_descriptor_from_args(args: GenerateDescriptorArgs) -> Result<Value, anyhow::Error> {
14-
match (args.weak.as_ref(), args.multipath, args.key.as_ref()) {
15-
(Some(weak_str), _, _) => {
16-
generate_descriptor_from_weak_string(&args.network, args.r#type, weak_str)
17-
}
18-
(None, true, Some(key)) => {
21+
match (args.multipath, args.key.as_ref()) {
22+
(true, Some(key)) => {
1923
generate_multipath_descriptor(&args.network, args.r#type, key)
2024
}
21-
(None, false, Some(key)) => {
25+
(false, Some(key)) => {
2226
generate_standard_descriptor(&args.network, args.r#type, key)
2327
}
24-
(None, false, None) => {
28+
(false, None) => {
2529
// New default: generate descriptor from fresh mnemonic (for script_type 84 only maybe)
2630
if args.r#type == 84 {
2731
generate_new_bip84_descriptor_with_mnemonic(args.network)
@@ -43,15 +47,20 @@ pub fn generate_new_bip84_descriptor_with_mnemonic(network: Network) -> Result<s
4347
.map_err(|e| anyhow!("Mnemonic generation failed: {:?}", e))?;
4448

4549
let seed = mnemonic.to_seed("");
46-
let xprv = Xpriv::new_master(network, &seed)
50+
let master_xprv = Xpriv::new_master(network, &seed)
4751
.map_err(|e| anyhow!("Failed to create extended private key: {}", e))?;
4852

49-
let origin = xprv.fingerprint(&secp);
50-
let deriv_base = "/84h/1h/0h"; // You might want to dynamically compute this based on args
51-
let xprv_str = xprv.to_string();
53+
// Derive to account level: m/84'/1'/0'
54+
let deriv_path = DerivationPath::from_str("m/84h/1h/0h")?;
55+
let account_xprv = master_xprv.derive_priv(&secp, &deriv_path)?;
5256

53-
let external_desc = format!("wpkh([{}{}]{}{})", origin, deriv_base, xprv_str, "/0/*");
54-
let internal_desc = format!("wpkh([{}{}]{}{})", origin, deriv_base, xprv_str, "/1/*");
57+
let fingerprint = master_xprv.fingerprint(&secp);
58+
59+
let xprv_str = account_xprv.to_string();
60+
61+
// Build descriptors using proper derivation suffix
62+
let external_desc = format!("wpkh([{}{}]{}{})", fingerprint, deriv_path, xprv_str, "/0/*");
63+
let internal_desc = format!("wpkh([{}{}]{}{})", fingerprint, deriv_path, xprv_str, "/1/*");
5564

5665
let (desc, keymap) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, &external_desc)
5766
.map_err(|e| anyhow!("Failed to parse external descriptor: {}", e))?;
@@ -72,15 +81,6 @@ pub fn generate_new_bip84_descriptor_with_mnemonic(network: Network) -> Result<s
7281
}))
7382
}
7483

75-
fn generate_descriptor_from_weak_string(
76-
network: &Network,
77-
script_type: u8,
78-
weak_str: &str,
79-
) -> Result<Value, anyhow::Error> {
80-
// TODO: replace with real weak key generation logic
81-
let fake_xprv = format!("xprv-from-{}", weak_str);
82-
generate_standard_descriptor(network, script_type, &fake_xprv)
83-
}
8484

8585
fn generate_multipath_descriptor(
8686
_network: &Network,
@@ -108,15 +108,59 @@ fn generate_standard_descriptor(
108108
pub fn generate_bip84_descriptor_from_key(
109109
network: &Network,
110110
key: &str,
111-
) -> Result<Value, anyhow::Error> {
112-
// Adjust derivation paths according to BIP84
113-
let external = format!("wpkh([{fingerprint}/84'/1'/0']{key}/0/*)", fingerprint = "00000000");
114-
let internal = format!("wpkh([{fingerprint}/84'/1'/0']{key}/1/*)", fingerprint = "00000000");
111+
) -> Result<serde_json::Value, anyhow::Error> {
112+
let secp = Secp256k1::new();
113+
let derivation_path: DerivationPath = "m/84h/1h/0h".parse()?;
114+
let xprv: Xpriv = key.parse().map_err(|e| anyhow!("Invalid xprv: {e}"))?;
115+
let fingerprint = xprv.fingerprint(&secp);
115116

116-
Ok(json!({
117+
let make_desc_key = |branch: u32| -> Result<(String, String)> {
118+
let branch_path: DerivationPath = DerivationPath::from_str(&format!("{branch}"))?;
119+
120+
let desc_xprv = DescriptorXKey {
121+
origin: Some((fingerprint, derivation_path.clone())), // only account-level path
122+
xkey: xprv,
123+
derivation_path: branch_path, // just the change (0 for external, 1 for internal)
124+
wildcard: Wildcard::Unhardened,
125+
};
126+
127+
128+
let desc_secret = DescriptorSecretKey::XPrv(desc_xprv);
129+
130+
// Use the BDK extract() to get both descriptor and keymap
131+
let (desc_key, keymap, _) = IntoDescriptorKey::<Segwitv0>::into_descriptor_key(desc_secret.clone())?
132+
.extract(&secp)?;
133+
134+
// Create the public descriptor from the public key
135+
let public_descriptor = Descriptor::new_wpkh(desc_key.clone())?;
136+
137+
// Here, we need to ensure that `desc_secret` is a valid descriptor type
138+
// for the private descriptor; we must use DescriptorPublicKey
139+
let private_descriptor = Descriptor::new_wpkh(desc_key)?;
140+
141+
// Convert both to string representations
142+
let public_descriptor_str = public_descriptor.to_string();
143+
let private_descriptor_str = private_descriptor.to_string_with_secret(&keymap);
144+
145+
Ok((public_descriptor_str, private_descriptor_str))
146+
};
147+
148+
149+
150+
let (external_pub, external_priv) = make_desc_key(0)?;
151+
let (internal_pub, internal_priv) = make_desc_key(1)?;
152+
153+
Ok(serde_json::json!({
117154
"type": "bip84",
118-
"external": external,
119-
"internal": internal,
155+
"external": {
156+
"public": external_pub,
157+
"private": external_priv,
158+
},
159+
"internal": {
160+
"public": internal_pub,
161+
"private": internal_priv,
162+
},
163+
"fingerprint": fingerprint.to_string(),
120164
"network": network.to_string()
121165
}))
122166
}

0 commit comments

Comments
 (0)