@@ -24,9 +24,14 @@ use bdk_kyoto::{
2424 builder:: Builder ,
2525} ;
2626use bdk_wallet:: {
27- bitcoin:: secp256k1:: All ,
28- keys:: { IntoDescriptorKey , KeyMap } ,
29- miniscript:: { Legacy , Miniscript , Terminal } ,
27+ KeychainKind ,
28+ bitcoin:: bip32:: { DerivationPath , Xpub } ,
29+ keys:: DescriptorPublicKey ,
30+ miniscript:: {
31+ Descriptor , Miniscript , Terminal ,
32+ descriptor:: { DescriptorXKey , Wildcard } ,
33+ } ,
34+ template:: DescriptorTemplate ,
3035} ;
3136use cli_table:: { Cell , CellStruct , Style , Table } ;
3237
@@ -40,24 +45,14 @@ use crate::commands::ClientType;
4045
4146use bdk_wallet:: Wallet ;
4247#[ cfg( any( feature = "sqlite" , feature = "redb" ) ) ]
43- use bdk_wallet:: { KeychainKind , PersistedWallet , WalletPersister } ;
48+ use bdk_wallet:: { PersistedWallet , WalletPersister } ;
4449
4550use bdk_wallet:: bip39:: { Language , Mnemonic } ;
4651use bdk_wallet:: bitcoin:: {
47- Address , Network , OutPoint , ScriptBuf ,
48- bip32:: { DerivationPath , Xpriv , Xpub } ,
49- secp256k1:: Secp256k1 ,
50- } ;
51- use bdk_wallet:: descriptor:: {
52- Segwitv0 , { Descriptor , DescriptorPublicKey } ,
53- } ;
54- use bdk_wallet:: keys:: {
55- DerivableKey , DescriptorSecretKey , ExtendedKey , GeneratableKey , GeneratedKey , bip39:: WordCount ,
56- } ;
57- use bdk_wallet:: miniscript:: {
58- Tap ,
59- descriptor:: { DescriptorXKey , Wildcard } ,
52+ Address , Network , OutPoint , ScriptBuf , bip32:: Xpriv , secp256k1:: Secp256k1 ,
6053} ;
54+ use bdk_wallet:: descriptor:: Segwitv0 ;
55+ use bdk_wallet:: keys:: { GeneratableKey , GeneratedKey , bip39:: WordCount } ;
6156use serde_json:: { Value , json} ;
6257
6358/// Parse the recipient (Address,Amount) argument from cli input.
@@ -395,111 +390,68 @@ pub fn is_mnemonic(s: &str) -> bool {
395390 ( 12 ..=24 ) . contains ( & word_count) && s. chars ( ) . all ( |c| c. is_alphanumeric ( ) || c. is_whitespace ( ) )
396391}
397392
398- pub fn extract_keymap (
399- desc_type : & str ,
400- desc_secret : DescriptorSecretKey ,
401- secp : & Secp256k1 < All > ,
402- ) -> Result < ( DescriptorPublicKey , KeyMap ) , Error > {
403- let ( desc_pub, keymap, _) = match desc_type. to_lowercase ( ) . as_str ( ) {
404- "pkh" => {
405- let descriptor_key = IntoDescriptorKey :: < Legacy > :: into_descriptor_key ( desc_secret) ?;
406- descriptor_key. extract ( secp) ?
407- }
408- "wpkh" | "sh" | "wsh" => {
409- let descriptor_key = IntoDescriptorKey :: < Segwitv0 > :: into_descriptor_key ( desc_secret) ?;
410- descriptor_key. extract ( secp) ?
411- }
412- "tr" => {
413- let descriptor_key = IntoDescriptorKey :: < Tap > :: into_descriptor_key ( desc_secret) ?;
414- descriptor_key. extract ( secp) ?
415- }
416- _ => {
417- return Err ( Error :: Generic ( format ! (
418- "Unsupported descriptor type: {desc_type}"
419- ) ) ) ;
420- }
421- } ;
422- Ok ( ( desc_pub, keymap) )
423- }
424-
425- pub fn build_public_descriptor (
426- desc_type : & str ,
427- key : DescriptorPublicKey ,
428- ) -> Result < Descriptor < DescriptorPublicKey > , Error > {
429- match desc_type. to_lowercase ( ) . as_str ( ) {
430- "pkh" => Descriptor :: new_pkh ( key) . map_err ( Error :: from) ,
431- "wpkh" => Descriptor :: new_wpkh ( key) . map_err ( Error :: from) ,
432- "sh" => Descriptor :: new_sh_wpkh ( key) . map_err ( Error :: from) ,
433- "wsh" => {
434- let pk_k = Miniscript :: from_ast ( Terminal :: PkK ( key) ) . map_err ( Error :: from) ?;
435- let pk_ms: Miniscript < DescriptorPublicKey , Segwitv0 > =
436- Miniscript :: from_ast ( Terminal :: Check ( Arc :: new ( pk_k) ) ) . map_err ( Error :: from) ?;
437- Descriptor :: new_wsh ( pk_ms) . map_err ( Error :: from)
438- }
439- "tr" => Descriptor :: new_tr ( key, None ) . map_err ( Error :: from) ,
440- _ => Err ( Error :: Generic ( format ! (
441- "Unsupported descriptor type: {desc_type}"
442- ) ) ) ,
443- }
444- }
445-
446393pub fn generate_descriptors ( desc_type : & str , key : & str , network : Network ) -> Result < Value , Error > {
447- let secp = Secp256k1 :: new ( ) ;
448- let purpose = match desc_type. to_lowercase ( ) . as_str ( ) {
449- "pkh" => 44u32 ,
450- "sh" => 49u32 ,
451- "wpkh" | "wsh" => 84u32 ,
452- "tr" => 86u32 ,
453- _ => 84u32 ,
454- } ;
455- let coin_type = match network {
456- Network :: Bitcoin => 0u32 ,
457- _ => 1u32 ,
458- } ;
459- let derivation_base = format ! ( "/{purpose}h/{coin_type}h/0h" ) ;
460- let derivation_path = DerivationPath :: from_str ( & format ! ( "m{derivation_base}" ) ) ?;
461-
462394 let is_private = key. starts_with ( "xprv" ) || key. starts_with ( "tprv" ) ;
463395
464396 if is_private {
465- generate_private_descriptors ( desc_type, key, & derivation_path , & secp )
397+ generate_private_descriptors ( desc_type, key, network )
466398 } else {
399+ let purpose = match desc_type. to_lowercase ( ) . as_str ( ) {
400+ "pkh" => 44u32 ,
401+ "sh" => 49u32 ,
402+ "wpkh" | "wsh" => 84u32 ,
403+ "tr" => 86u32 ,
404+ _ => 84u32 ,
405+ } ;
406+ let coin_type = match network {
407+ Network :: Bitcoin => 0u32 ,
408+ _ => 1u32 ,
409+ } ;
410+ let derivation_path = DerivationPath :: from_str ( & format ! ( "m/{purpose}h/{coin_type}h/0h" ) ) ?;
467411 generate_public_descriptors ( desc_type, key, & derivation_path)
468412 }
469413}
470414
415+ /// Generate descriptors from private key using BIP templates
471416fn generate_private_descriptors (
472417 desc_type : & str ,
473418 key : & str ,
474- account_path : & DerivationPath ,
475- secp : & Secp256k1 < All > ,
419+ network : Network ,
476420) -> Result < Value , Error > {
477- let xprv: Xpriv = key. parse ( ) ?;
478- let fingerprint = xprv. fingerprint ( secp) ;
421+ use bdk_wallet:: template:: { Bip44 , Bip49 , Bip84 , Bip86 } ;
479422
480- let account_xprv = xprv. derive_priv ( secp, account_path) ?;
481-
482- let build_descriptor = |branch : & str | -> Result < ( String , String ) , Error > {
483- let branch_path = DerivationPath :: from_str ( branch) ?;
484-
485- let desc_xprv = DescriptorXKey {
486- origin : Some ( ( fingerprint, account_path. clone ( ) ) ) ,
487- xkey : account_xprv,
488- derivation_path : branch_path,
489- wildcard : Wildcard :: Unhardened ,
490- } ;
491- let desc_secret = DescriptorSecretKey :: XPrv ( desc_xprv) ;
423+ let secp = Secp256k1 :: new ( ) ;
424+ let xprv: Xpriv = key. parse ( ) ?;
425+ let fingerprint = xprv. fingerprint ( & secp) ;
492426
493- let ( desc_pub, keymap) = extract_keymap ( desc_type, desc_secret, secp) ?;
494- let descriptor = build_public_descriptor ( desc_type, desc_pub) ?;
495- let public_str = descriptor. to_string ( ) ;
496- let private_str = descriptor. to_string_with_secret ( & keymap) ;
427+ let ( external_desc, external_keymap, _) = match desc_type. to_lowercase ( ) . as_str ( ) {
428+ "pkh" => Bip44 ( xprv, KeychainKind :: External ) . build ( network) ?,
429+ "sh" => Bip49 ( xprv, KeychainKind :: External ) . build ( network) ?,
430+ "wpkh" | "wsh" => Bip84 ( xprv, KeychainKind :: External ) . build ( network) ?,
431+ "tr" => Bip86 ( xprv, KeychainKind :: External ) . build ( network) ?,
432+ _ => {
433+ return Err ( Error :: Generic ( format ! (
434+ "Unsupported descriptor type: {desc_type}"
435+ ) ) ) ;
436+ }
437+ } ;
497438
498- Ok ( ( public_str, private_str) )
439+ let ( internal_desc, internal_keymap, _) = match desc_type. to_lowercase ( ) . as_str ( ) {
440+ "pkh" => Bip44 ( xprv, KeychainKind :: Internal ) . build ( network) ?,
441+ "sh" => Bip49 ( xprv, KeychainKind :: Internal ) . build ( network) ?,
442+ "wpkh" | "wsh" => Bip84 ( xprv, KeychainKind :: Internal ) . build ( network) ?,
443+ "tr" => Bip86 ( xprv, KeychainKind :: Internal ) . build ( network) ?,
444+ _ => {
445+ return Err ( Error :: Generic ( format ! (
446+ "Unsupported descriptor type: {desc_type}"
447+ ) ) ) ;
448+ }
499449 } ;
500450
501- let ( external_pub, external_priv) = build_descriptor ( "0" ) ?;
502- let ( internal_pub, internal_priv) = build_descriptor ( "1" ) ?;
451+ let external_priv = external_desc. to_string_with_secret ( & external_keymap) ;
452+ let external_pub = external_desc. to_string ( ) ;
453+ let internal_priv = internal_desc. to_string_with_secret ( & internal_keymap) ;
454+ let internal_pub = internal_desc. to_string ( ) ;
503455
504456 Ok ( json ! ( {
505457 "public_descriptors" : {
@@ -514,21 +466,7 @@ fn generate_private_descriptors(
514466 } ) )
515467}
516468
517- pub fn generate_descriptor_with_mnemonic (
518- network : Network ,
519- desc_type : & str ,
520- ) -> Result < serde_json:: Value , Error > {
521- let mnemonic: GeneratedKey < Mnemonic , Segwitv0 > =
522- Mnemonic :: generate ( ( WordCount :: Words12 , Language :: English ) ) . map_err ( Error :: BIP39Error ) ?;
523-
524- let seed = mnemonic. to_seed ( "" ) ;
525- let xprv = Xpriv :: new_master ( network, & seed) ?;
526-
527- let mut result = generate_descriptors ( desc_type, & xprv. to_string ( ) , network) ?;
528- result[ "mnemonic" ] = json ! ( mnemonic. to_string( ) ) ;
529- Ok ( result)
530- }
531-
469+ /// Generate descriptors from public key (xpub/tpub)
532470pub fn generate_public_descriptors (
533471 desc_type : & str ,
534472 key : & str ,
@@ -562,16 +500,53 @@ pub fn generate_public_descriptors(
562500 } ) )
563501}
564502
503+ /// Build a descriptor from a public key
504+ pub fn build_public_descriptor (
505+ desc_type : & str ,
506+ key : DescriptorPublicKey ,
507+ ) -> Result < Descriptor < DescriptorPublicKey > , Error > {
508+ match desc_type. to_lowercase ( ) . as_str ( ) {
509+ "pkh" => Descriptor :: new_pkh ( key) . map_err ( Error :: from) ,
510+ "wpkh" => Descriptor :: new_wpkh ( key) . map_err ( Error :: from) ,
511+ "sh" => Descriptor :: new_sh_wpkh ( key) . map_err ( Error :: from) ,
512+ "wsh" => {
513+ let pk_k = Miniscript :: from_ast ( Terminal :: PkK ( key) ) . map_err ( Error :: from) ?;
514+ let pk_ms: Miniscript < DescriptorPublicKey , Segwitv0 > =
515+ Miniscript :: from_ast ( Terminal :: Check ( Arc :: new ( pk_k) ) ) . map_err ( Error :: from) ?;
516+ Descriptor :: new_wsh ( pk_ms) . map_err ( Error :: from)
517+ }
518+ "tr" => Descriptor :: new_tr ( key, None ) . map_err ( Error :: from) ,
519+ _ => Err ( Error :: Generic ( format ! (
520+ "Unsupported descriptor type: {desc_type}"
521+ ) ) ) ,
522+ }
523+ }
524+
525+ /// Generate new mnemonic and descriptors
526+ pub fn generate_descriptor_with_mnemonic (
527+ network : Network ,
528+ desc_type : & str ,
529+ ) -> Result < serde_json:: Value , Error > {
530+ let mnemonic: GeneratedKey < Mnemonic , Segwitv0 > =
531+ Mnemonic :: generate ( ( WordCount :: Words12 , Language :: English ) ) . map_err ( Error :: BIP39Error ) ?;
532+
533+ let seed = mnemonic. to_seed ( "" ) ;
534+ let xprv = Xpriv :: new_master ( network, & seed) ?;
535+
536+ let mut result = generate_descriptors ( desc_type, & xprv. to_string ( ) , network) ?;
537+ result[ "mnemonic" ] = json ! ( mnemonic. to_string( ) ) ;
538+ Ok ( result)
539+ }
540+
541+ /// Generate descriptors from existing mnemonic
565542pub fn generate_descriptor_from_mnemonic (
566543 mnemonic_str : & str ,
567544 network : Network ,
568545 desc_type : & str ,
569546) -> Result < serde_json:: Value , Error > {
570547 let mnemonic = Mnemonic :: parse_in ( Language :: English , mnemonic_str) ?;
571- let ext_key: ExtendedKey = mnemonic. into_extended_key ( ) ?;
572- let xprv = ext_key
573- . into_xprv ( network)
574- . ok_or_else ( || Error :: Generic ( "No xprv found" . to_string ( ) ) ) ?;
548+ let seed = mnemonic. to_seed ( "" ) ;
549+ let xprv = Xpriv :: new_master ( network, & seed) ?;
575550
576551 let mut result = generate_descriptors ( desc_type, & xprv. to_string ( ) , network) ?;
577552 result[ "mnemonic" ] = json ! ( mnemonic_str) ;
0 commit comments