@@ -8,20 +8,24 @@ use bdk_wallet::bitcoin::Network;
88use bdk_wallet:: descriptor:: Segwitv0 ;
99use bdk_wallet:: keys:: bip39:: { Language , Mnemonic , WordCount } ;
1010use 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
1320pub 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
8585fn generate_multipath_descriptor (
8686 _network : & Network ,
@@ -108,15 +108,59 @@ fn generate_standard_descriptor(
108108pub 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