@@ -65,7 +65,7 @@ impl Display for Mnemonic {
6565}
6666
6767/// A BIP-32 derivation path.
68- #[ derive( uniffi:: Object ) ]
68+ #[ derive( uniffi:: Object , Debug ) ]
6969pub struct DerivationPath {
7070 inner_mutex : Mutex < BdkDerivationPath > ,
7171}
@@ -83,23 +83,23 @@ impl DerivationPath {
8383 }
8484}
8585
86- /// A descriptor containing secret data .
86+ /// The descriptor secret key, either a single private key or an xprv .
8787#[ derive( Debug , uniffi:: Object ) ]
8888#[ uniffi:: export( Debug , Display ) ]
8989pub struct DescriptorSecretKey ( pub ( crate ) BdkDescriptorSecretKey ) ;
9090
9191#[ uniffi:: export]
9292impl DescriptorSecretKey {
93- /// Construct a secret descriptor using a mnemonic.
93+ /// Construct a secret descriptor key using a mnemonic.
9494 #[ uniffi:: constructor]
9595 pub fn new ( network : Network , mnemonic : & Mnemonic , password : Option < String > ) -> Self {
9696 let mnemonic = mnemonic. 0 . clone ( ) ;
9797 let xkey: ExtendedKey = ( mnemonic, password) . into_extended_key ( ) . unwrap ( ) ;
9898 let descriptor_secret_key = BdkDescriptorSecretKey :: XPrv ( DescriptorXKey {
9999 origin : None ,
100100 xkey : xkey. into_xprv ( network) . unwrap ( ) ,
101- derivation_path : BdkDerivationPath :: master ( ) ,
102- wildcard : Wildcard :: Unhardened ,
101+ derivation_path : BdkDerivationPath :: default ( ) ,
102+ wildcard : Wildcard :: None ,
103103 } ) ;
104104 Self ( descriptor_secret_key)
105105 }
@@ -160,6 +160,24 @@ impl DescriptorSecretKey {
160160 }
161161 }
162162
163+ pub fn add_wildcard ( & self ) -> Result < Arc < Self > , DescriptorKeyError > {
164+ let descriptor_secret_key = & self . 0 ;
165+ match descriptor_secret_key {
166+ BdkDescriptorSecretKey :: Single ( _) => Err ( DescriptorKeyError :: InvalidKeyType ) ,
167+ BdkDescriptorSecretKey :: XPrv ( descriptor_x_key) => {
168+ let descriptor_secret_key_with_wildcard =
169+ BdkDescriptorSecretKey :: XPrv ( DescriptorXKey {
170+ origin : descriptor_x_key. origin . clone ( ) ,
171+ xkey : descriptor_x_key. xkey ,
172+ derivation_path : descriptor_x_key. derivation_path . clone ( ) ,
173+ wildcard : Wildcard :: Unhardened ,
174+ } ) ;
175+ Ok ( Arc :: new ( Self ( descriptor_secret_key_with_wildcard) ) )
176+ }
177+ BdkDescriptorSecretKey :: MultiXPrv ( _) => Err ( DescriptorKeyError :: InvalidKeyType ) ,
178+ }
179+ }
180+
163181 /// Return the descriptor public key corresponding to this secret.
164182 pub fn as_public ( & self ) -> Arc < DescriptorPublicKey > {
165183 let secp = Secp256k1 :: new ( ) ;
@@ -199,6 +217,21 @@ pub struct DescriptorPublicKey(pub(crate) BdkDescriptorPublicKey);
199217
200218#[ uniffi:: export]
201219impl DescriptorPublicKey {
220+ /// Construct a public descriptor key using a mnemonic.
221+ #[ uniffi:: constructor]
222+ pub fn new ( network : Network , mnemonic : & Mnemonic , password : Option < String > ) -> Self {
223+ let secp = Secp256k1 :: new ( ) ;
224+ let mnemonic = mnemonic. 0 . clone ( ) ;
225+ let xkey: ExtendedKey = ( mnemonic, password) . into_extended_key ( ) . unwrap ( ) ;
226+ let descriptor_public_key = BdkDescriptorPublicKey :: XPub ( DescriptorXKey {
227+ origin : None ,
228+ xkey : xkey. into_xpub ( network, & secp) ,
229+ derivation_path : BdkDerivationPath :: default ( ) ,
230+ wildcard : Wildcard :: None ,
231+ } ) ;
232+ Self ( descriptor_public_key)
233+ }
234+
202235 /// Attempt to parse a string as a descriptor public key.
203236 #[ uniffi:: constructor]
204237 pub fn from_string ( public_key : String ) -> Result < Self , DescriptorKeyError > {
@@ -256,6 +289,24 @@ impl DescriptorPublicKey {
256289 }
257290 }
258291
292+ pub fn add_wildcard ( & self ) -> Result < Arc < Self > , DescriptorKeyError > {
293+ let descriptor_public_key = & self . 0 ;
294+ match descriptor_public_key {
295+ BdkDescriptorPublicKey :: Single ( _) => Err ( DescriptorKeyError :: InvalidKeyType ) ,
296+ BdkDescriptorPublicKey :: XPub ( descriptor_x_key) => {
297+ let descriptor_public_key_with_wildcard =
298+ BdkDescriptorPublicKey :: XPub ( DescriptorXKey {
299+ origin : descriptor_x_key. origin . clone ( ) ,
300+ xkey : descriptor_x_key. xkey ,
301+ derivation_path : descriptor_x_key. derivation_path . clone ( ) ,
302+ wildcard : Wildcard :: Unhardened ,
303+ } ) ;
304+ Ok ( Arc :: new ( Self ( descriptor_public_key_with_wildcard) ) )
305+ }
306+ BdkDescriptorPublicKey :: MultiXPub ( _) => Err ( DescriptorKeyError :: InvalidKeyType ) ,
307+ }
308+ }
309+
259310 /// Whether or not this key has multiple derivation paths.
260311 pub fn is_multipath ( & self ) -> bool {
261312 self . 0 . is_multipath ( )
@@ -320,38 +371,38 @@ mod test {
320371 #[ test]
321372 fn test_generate_descriptor_secret_key ( ) {
322373 let master_dsk = get_inner ( ) ;
323- assert_eq ! ( master_dsk. to_string( ) , "tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/* " ) ;
324- assert_eq ! ( master_dsk. as_public( ) . to_string( ) , "tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/* " ) ;
374+ assert_eq ! ( master_dsk. to_string( ) , "tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h" ) ;
375+ assert_eq ! ( master_dsk. as_public( ) . to_string( ) , "tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa" ) ;
325376 }
326377
327378 #[ test]
328379 fn test_derive_self ( ) {
329380 let master_dsk = get_inner ( ) ;
330381 let derived_dsk: & DescriptorSecretKey = & derive_dsk ( & master_dsk, "m" ) . unwrap ( ) ;
331- assert_eq ! ( derived_dsk. to_string( ) , "[d1d04177]tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/* " ) ;
382+ assert_eq ! ( derived_dsk. to_string( ) , "[d1d04177]tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h" ) ;
332383 let master_dpk: & DescriptorPublicKey = & master_dsk. as_public ( ) ;
333384 let derived_dpk: & DescriptorPublicKey = & derive_dpk ( master_dpk, "m" ) . unwrap ( ) ;
334- assert_eq ! ( derived_dpk. to_string( ) , "[d1d04177]tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/* " ) ;
385+ assert_eq ! ( derived_dpk. to_string( ) , "[d1d04177]tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa" ) ;
335386 }
336387
337388 #[ test]
338389 fn test_derive_descriptors_keys ( ) {
339390 let master_dsk = get_inner ( ) ;
340391 let derived_dsk: & DescriptorSecretKey = & derive_dsk ( & master_dsk, "m/0" ) . unwrap ( ) ;
341- assert_eq ! ( derived_dsk. to_string( ) , "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/* " ) ;
392+ assert_eq ! ( derived_dsk. to_string( ) , "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ" ) ;
342393 let master_dpk: & DescriptorPublicKey = & master_dsk. as_public ( ) ;
343394 let derived_dpk: & DescriptorPublicKey = & derive_dpk ( master_dpk, "m/0" ) . unwrap ( ) ;
344- assert_eq ! ( derived_dpk. to_string( ) , "[d1d04177/0]tpubD9oaCiP1MPmQdndm7DCD3D3QU34pWd6BbKSRedoZF1UJcNhEk3PJwkALNYkhxeTKL29oGNR7psqvT1KZydCGqUDEKXN6dVQJY2R8ooLPy8m/* " ) ;
395+ assert_eq ! ( derived_dpk. to_string( ) , "[d1d04177/0]tpubD9oaCiP1MPmQdndm7DCD3D3QU34pWd6BbKSRedoZF1UJcNhEk3PJwkALNYkhxeTKL29oGNR7psqvT1KZydCGqUDEKXN6dVQJY2R8ooLPy8m" ) ;
345396 }
346397
347398 #[ test]
348399 fn test_extend_descriptor_keys ( ) {
349400 let master_dsk = get_inner ( ) ;
350401 let extended_dsk: & DescriptorSecretKey = & extend_dsk ( & master_dsk, "m/0" ) . unwrap ( ) ;
351- assert_eq ! ( extended_dsk. to_string( ) , "tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/0/* " ) ;
402+ assert_eq ! ( extended_dsk. to_string( ) , "tprv8ZgxMBicQKsPdWuqM1t1CDRvQtQuBPyfL6GbhQwtxDKgUAVPbxmj71pRA8raTqLrec5LyTs5TqCxdABcZr77bt2KyWA5bizJHnC4g4ysm4h/0" ) ;
352403 let master_dpk: & DescriptorPublicKey = & master_dsk. as_public ( ) ;
353404 let extended_dpk: & DescriptorPublicKey = & extend_dpk ( master_dpk, "m/0" ) . unwrap ( ) ;
354- assert_eq ! ( extended_dpk. to_string( ) , "tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/0/* " ) ;
405+ assert_eq ! ( extended_dpk. to_string( ) , "tpubD6NzVbkrYhZ4WywdEfYbbd62yuvqLjAZuPsNyvzCNV85JekAEMbKHWSHLF9h3j45SxewXDcLv328B1SEZrxg4iwGfmdt1pDFjZiTkGiFqGa/0" ) ;
355406 let wif = "L2wTu6hQrnDMiFNWA5na6jB12ErGQqtXwqpSL7aWquJaZG8Ai3ch" ;
356407 let extended_key = DescriptorSecretKey :: from_string ( wif. to_string ( ) ) . unwrap ( ) ;
357408 let result = extended_key. derive ( & DerivationPath :: new ( "m/0" . to_string ( ) ) . unwrap ( ) ) ;
@@ -360,13 +411,13 @@ mod test {
360411 }
361412
362413 #[ test]
363- fn test_from_str_inner ( ) {
414+ fn test_from_str ( ) {
364415 let key1 = "L2wTu6hQrnDMiFNWA5na6jB12ErGQqtXwqpSL7aWquJaZG8Ai3ch" ;
365416 let key2 = "tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/1/1/*" ;
366417 let private_descriptor_key1 = DescriptorSecretKey :: from_string ( key1. to_string ( ) ) . unwrap ( ) ;
367418 let private_descriptor_key2 = DescriptorSecretKey :: from_string ( key2. to_string ( ) ) . unwrap ( ) ;
368- dbg ! ( private_descriptor_key1) ;
369- dbg ! ( private_descriptor_key2) ;
419+ dbg ! ( private_descriptor_key1. to_string ( ) ) ;
420+ dbg ! ( private_descriptor_key2. to_string ( ) ) ;
370421 // Should error out because you can't produce a DescriptorSecretKey from an xpub
371422 let key0 = "tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi" ;
372423 assert ! ( DescriptorSecretKey :: from_string( key0. to_string( ) ) . is_err( ) ) ;
@@ -377,10 +428,10 @@ mod test {
377428 let master_dsk = get_inner ( ) ;
378429 // derive DescriptorSecretKey with path "m/0" from master
379430 let derived_dsk: & DescriptorSecretKey = & derive_dsk ( & master_dsk, "m/0" ) . unwrap ( ) ;
380- assert_eq ! ( derived_dsk. to_string( ) , "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/* " ) ;
431+ assert_eq ! ( derived_dsk. to_string( ) , "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ" ) ;
381432 // extend derived_dsk with path "m/0"
382433 let extended_dsk: & DescriptorSecretKey = & extend_dsk ( derived_dsk, "m/0" ) . unwrap ( ) ;
383- assert_eq ! ( extended_dsk. to_string( ) , "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/0/* " ) ;
434+ assert_eq ! ( extended_dsk. to_string( ) , "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/0" ) ;
384435 }
385436
386437 #[ test]
@@ -390,16 +441,25 @@ mod test {
390441 assert ! ( derived_dpk. is_err( ) ) ;
391442 }
392443
393- // TODO 7: It appears that the to_hex() method is not available anymore.
394- // Look into the correct way to pull the hex out of the DescriptorSecretKey.
395- // Note: ToHex was removed in bitcoin_hashes 0.12.0
396- // #[test]
397- // fn test_retrieve_master_secret_key() {
398- // let master_dpk = get_inner();
399- // let master_private_key = master_dpk.secret_bytes().to_hex();
400- // assert_eq!(
401- // master_private_key,
402- // "e93315d6ce401eb4db803a56232f0ed3e69b053774e6047df54f1bd00e5ea936"
403- // )
404- // }
444+ #[ test]
445+ fn test_add_wildcard ( ) {
446+ let mnemonic = Mnemonic :: from_string ( "awesome awesome awesome awesome awesome awesome awesome awesome awesome awesome awesome awesome" . to_string ( ) ) . unwrap ( ) ;
447+ let key = DescriptorSecretKey :: new ( Network :: Testnet , & mnemonic, None ) ;
448+ println ! ( "{:?}" , key. to_string( ) ) ;
449+
450+ let derivation0 = "84/2h/1" . to_string ( ) ;
451+ let derivation_path = DerivationPath :: new ( derivation0) . unwrap ( ) ;
452+
453+ let extended_key = key. extend ( & derivation_path) . unwrap ( ) ;
454+ assert_eq ! ( extended_key. to_string( ) , "tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/84/2'/1" ) ;
455+
456+ let extended_key_with_wildcard = extended_key. add_wildcard ( ) . unwrap ( ) ;
457+ assert_eq ! ( extended_key_with_wildcard. to_string( ) , "tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/84/2'/1/*" ) ;
458+
459+ // You can call add_wildcard as many times as you want, it doesn't do anything after the first call
460+ let extended_key_with_wildcard_again = extended_key_with_wildcard. add_wildcard ( ) . unwrap ( ) ;
461+ let extended_key_with_wildcard_again_again =
462+ extended_key_with_wildcard_again. add_wildcard ( ) . unwrap ( ) ;
463+ assert_eq ! ( extended_key_with_wildcard_again_again. to_string( ) , "tprv8ZgxMBicQKsPdWAHbugK2tjtVtRjKGixYVZUdL7xLHMgXZS6BFbFi1UDb1CHT25Z5PU1F9j7wGxwUiRhqz9E3nZRztikGUV6HoRDYcqPhM4/84/2'/1/*" ) ;
464+ }
405465}
0 commit comments