@@ -65,7 +65,7 @@ impl Display for Mnemonic {
65
65
}
66
66
67
67
/// A BIP-32 derivation path.
68
- #[ derive( uniffi:: Object ) ]
68
+ #[ derive( uniffi:: Object , Debug ) ]
69
69
pub struct DerivationPath {
70
70
inner_mutex : Mutex < BdkDerivationPath > ,
71
71
}
@@ -83,23 +83,23 @@ impl DerivationPath {
83
83
}
84
84
}
85
85
86
- /// A descriptor containing secret data .
86
+ /// The descriptor secret key, either a single private key or an xprv .
87
87
#[ derive( Debug , uniffi:: Object ) ]
88
88
#[ uniffi:: export( Debug , Display ) ]
89
89
pub struct DescriptorSecretKey ( pub ( crate ) BdkDescriptorSecretKey ) ;
90
90
91
91
#[ uniffi:: export]
92
92
impl DescriptorSecretKey {
93
- /// Construct a secret descriptor using a mnemonic.
93
+ /// Construct a secret descriptor key using a mnemonic.
94
94
#[ uniffi:: constructor]
95
95
pub fn new ( network : Network , mnemonic : & Mnemonic , password : Option < String > ) -> Self {
96
96
let mnemonic = mnemonic. 0 . clone ( ) ;
97
97
let xkey: ExtendedKey = ( mnemonic, password) . into_extended_key ( ) . unwrap ( ) ;
98
98
let descriptor_secret_key = BdkDescriptorSecretKey :: XPrv ( DescriptorXKey {
99
99
origin : None ,
100
100
xkey : xkey. into_xprv ( network) . unwrap ( ) ,
101
- derivation_path : BdkDerivationPath :: master ( ) ,
102
- wildcard : Wildcard :: Unhardened ,
101
+ derivation_path : BdkDerivationPath :: default ( ) ,
102
+ wildcard : Wildcard :: None ,
103
103
} ) ;
104
104
Self ( descriptor_secret_key)
105
105
}
@@ -160,6 +160,24 @@ impl DescriptorSecretKey {
160
160
}
161
161
}
162
162
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
+
163
181
/// Return the descriptor public key corresponding to this secret.
164
182
pub fn as_public ( & self ) -> Arc < DescriptorPublicKey > {
165
183
let secp = Secp256k1 :: new ( ) ;
@@ -199,6 +217,21 @@ pub struct DescriptorPublicKey(pub(crate) BdkDescriptorPublicKey);
199
217
200
218
#[ uniffi:: export]
201
219
impl 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
+
202
235
/// Attempt to parse a string as a descriptor public key.
203
236
#[ uniffi:: constructor]
204
237
pub fn from_string ( public_key : String ) -> Result < Self , DescriptorKeyError > {
@@ -256,6 +289,24 @@ impl DescriptorPublicKey {
256
289
}
257
290
}
258
291
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
+
259
310
/// Whether or not this key has multiple derivation paths.
260
311
pub fn is_multipath ( & self ) -> bool {
261
312
self . 0 . is_multipath ( )
@@ -320,38 +371,38 @@ mod test {
320
371
#[ test]
321
372
fn test_generate_descriptor_secret_key ( ) {
322
373
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" ) ;
325
376
}
326
377
327
378
#[ test]
328
379
fn test_derive_self ( ) {
329
380
let master_dsk = get_inner ( ) ;
330
381
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" ) ;
332
383
let master_dpk: & DescriptorPublicKey = & master_dsk. as_public ( ) ;
333
384
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" ) ;
335
386
}
336
387
337
388
#[ test]
338
389
fn test_derive_descriptors_keys ( ) {
339
390
let master_dsk = get_inner ( ) ;
340
391
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" ) ;
342
393
let master_dpk: & DescriptorPublicKey = & master_dsk. as_public ( ) ;
343
394
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" ) ;
345
396
}
346
397
347
398
#[ test]
348
399
fn test_extend_descriptor_keys ( ) {
349
400
let master_dsk = get_inner ( ) ;
350
401
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" ) ;
352
403
let master_dpk: & DescriptorPublicKey = & master_dsk. as_public ( ) ;
353
404
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" ) ;
355
406
let wif = "L2wTu6hQrnDMiFNWA5na6jB12ErGQqtXwqpSL7aWquJaZG8Ai3ch" ;
356
407
let extended_key = DescriptorSecretKey :: from_string ( wif. to_string ( ) ) . unwrap ( ) ;
357
408
let result = extended_key. derive ( & DerivationPath :: new ( "m/0" . to_string ( ) ) . unwrap ( ) ) ;
@@ -360,13 +411,13 @@ mod test {
360
411
}
361
412
362
413
#[ test]
363
- fn test_from_str_inner ( ) {
414
+ fn test_from_str ( ) {
364
415
let key1 = "L2wTu6hQrnDMiFNWA5na6jB12ErGQqtXwqpSL7aWquJaZG8Ai3ch" ;
365
416
let key2 = "tprv8ZgxMBicQKsPcwcD4gSnMti126ZiETsuX7qwrtMypr6FBwAP65puFn4v6c3jrN9VwtMRMph6nyT63NrfUL4C3nBzPcduzVSuHD7zbX2JKVc/1/1/1/*" ;
366
417
let private_descriptor_key1 = DescriptorSecretKey :: from_string ( key1. to_string ( ) ) . unwrap ( ) ;
367
418
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 ( ) ) ;
370
421
// Should error out because you can't produce a DescriptorSecretKey from an xpub
371
422
let key0 = "tpubDBrgjcxBxnXyL575sHdkpKohWu5qHKoQ7TJXKNrYznh5fVEGBv89hA8ENW7A8MFVpFUSvgLqc4Nj1WZcpePX6rrxviVtPowvMuGF5rdT2Vi" ;
372
423
assert ! ( DescriptorSecretKey :: from_string( key0. to_string( ) ) . is_err( ) ) ;
@@ -377,10 +428,10 @@ mod test {
377
428
let master_dsk = get_inner ( ) ;
378
429
// derive DescriptorSecretKey with path "m/0" from master
379
430
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" ) ;
381
432
// extend derived_dsk with path "m/0"
382
433
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" ) ;
384
435
}
385
436
386
437
#[ test]
@@ -390,16 +441,25 @@ mod test {
390
441
assert ! ( derived_dpk. is_err( ) ) ;
391
442
}
392
443
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
+ }
405
465
}
0 commit comments