@@ -509,8 +509,10 @@ impl WalletManager {
509
509
// If hex_secret is requested, we need to extract it from the wallet descriptor
510
510
if hex_secret {
511
511
// Parse the descriptor to extract the xprv and get the hex secret
512
- if let Some ( hex_secret_value) = self . extract_hex_secret_from_descriptor ( & export. descriptor ) ? {
513
- export. hex_secret = Some ( hex_secret_value) ;
512
+ if let Some ( descriptor) = & export. descriptor {
513
+ if let Some ( hex_secret_value) = self . extract_hex_secret_from_descriptor ( descriptor) ? {
514
+ export. hex_secret = Some ( hex_secret_value) ;
515
+ }
514
516
}
515
517
}
516
518
@@ -650,11 +652,55 @@ impl WalletManager {
650
652
name : name. to_string ( ) ,
651
653
network,
652
654
genesis_hash,
653
- space_descriptors : WalletDescriptors {
654
- external : export. descriptor ( ) ,
655
- internal : export
656
- . change_descriptor ( )
657
- . expect ( "expected a change descriptor" ) ,
655
+ space_descriptors : {
656
+ let external_descriptor = export. descriptor ( ) . expect ( "expected a descriptor" ) ;
657
+ let internal_descriptor = export. change_descriptor ( ) . expect ( "expected a change descriptor" ) ;
658
+
659
+ // Check if this is a hex-based descriptor and convert it
660
+ let ( external, internal) = if external_descriptor. starts_with ( "tr([hex:" ) {
661
+ // Extract hex secret from descriptor
662
+ if let Some ( hex_secret) = export. hex_secret . as_ref ( ) {
663
+ // Convert hex secret to proper xprv and create descriptors
664
+ let xpriv = Self :: xpriv_from_hex_secret ( network, hex_secret) ?;
665
+ let ( external_desc, internal_desc) = Self :: default_descriptors ( xpriv) ;
666
+
667
+ // Create a temporary wallet to get the descriptor strings
668
+ let temp_wallet = bdk:: Wallet :: create ( external_desc, internal_desc)
669
+ . network ( network)
670
+ . create_wallet_no_persist ( ) ?;
671
+
672
+ // Get descriptor strings using the same method as WalletExport
673
+ let external_str = temp_wallet
674
+ . public_descriptor ( KeychainKind :: External )
675
+ . to_string_with_secret (
676
+ & temp_wallet
677
+ . get_signers ( KeychainKind :: External )
678
+ . as_key_map ( temp_wallet. secp_ctx ( ) ) ,
679
+ ) ;
680
+ let internal_str = temp_wallet
681
+ . public_descriptor ( KeychainKind :: Internal )
682
+ . to_string_with_secret (
683
+ & temp_wallet
684
+ . get_signers ( KeychainKind :: Internal )
685
+ . as_key_map ( temp_wallet. secp_ctx ( ) ) ,
686
+ ) ;
687
+
688
+ // Remove checksums (same as WalletExport does)
689
+ let external_str = Self :: remove_checksum ( external_str) ;
690
+ let internal_str = Self :: remove_checksum ( internal_str) ;
691
+
692
+ ( external_str, internal_str)
693
+ } else {
694
+ return Err ( anyhow ! ( "Hex-based descriptor found but no hex_secret in export" ) ) ;
695
+ }
696
+ } else {
697
+ ( external_descriptor, internal_descriptor)
698
+ } ;
699
+
700
+ WalletDescriptors {
701
+ external,
702
+ internal,
703
+ }
658
704
} ,
659
705
} ;
660
706
@@ -692,13 +738,57 @@ impl WalletManager {
692
738
Ok ( xkey. into_xprv ( network) . expect ( "xpriv" ) )
693
739
}
694
740
741
+ fn xpriv_from_hex_secret ( network : Network , hex_secret : & str ) -> anyhow:: Result < Xpriv > {
742
+ use spaces_protocol:: bitcoin:: bip32:: Xpriv ;
743
+ use spaces_protocol:: bitcoin:: key:: Secp256k1 ;
744
+ use spaces_protocol:: bitcoin:: secp256k1:: SecretKey ;
745
+
746
+ // Parse hex secret
747
+ let secret_bytes = hex:: decode ( hex_secret)
748
+ . map_err ( |e| anyhow ! ( "Invalid hex secret: {}" , e) ) ?;
749
+
750
+ if secret_bytes. len ( ) != 32 {
751
+ return Err ( anyhow ! ( "Hex secret must be 32 bytes (64 hex characters)" ) ) ;
752
+ }
753
+
754
+ // Convert to SecretKey
755
+ let secret_key = SecretKey :: from_slice ( & secret_bytes)
756
+ . map_err ( |e| anyhow ! ( "Invalid secret key: {}" , e) ) ?;
757
+
758
+ // Create Xpriv from secret key
759
+ let secp = Secp256k1 :: new ( ) ;
760
+ let xpriv = Xpriv :: new_master ( network, & secret_key. secret_bytes ( ) )
761
+ . map_err ( |e| anyhow ! ( "Failed to create xpriv: {}" , e) ) ?;
762
+
763
+ Ok ( xpriv)
764
+ }
765
+
766
+ fn descriptor_from_hex_secret ( network : Network , hex_secret : & str ) -> anyhow:: Result < String > {
767
+ // Parse hex secret
768
+ let secret_bytes = hex:: decode ( hex_secret)
769
+ . map_err ( |e| anyhow ! ( "Invalid hex secret: {}" , e) ) ?;
770
+
771
+ if secret_bytes. len ( ) != 32 {
772
+ return Err ( anyhow ! ( "Hex secret must be 32 bytes (64 hex characters)" ) ) ;
773
+ }
774
+
775
+ // For now, create a simple descriptor that can be processed by the wallet creation
776
+ // The actual xprv conversion will need to be handled in the wallet creation process
777
+ // This is a placeholder format that indicates this is a hex-based import
778
+ Ok ( format ! ( "tr([hex:{}]/86'/0'/0'/0/*)" , hex_secret) )
779
+ }
780
+
695
781
fn default_descriptors ( x : Xpriv ) -> ( Bip86 < Xpriv > , Bip86 < Xpriv > ) {
696
782
(
697
783
Bip86 ( x, KeychainKind :: External ) ,
698
784
Bip86 ( x, KeychainKind :: Internal ) ,
699
785
)
700
786
}
701
787
788
+ fn remove_checksum ( s : String ) -> String {
789
+ s. split_once ( '#' ) . map ( |( a, _) | String :: from ( a) ) . unwrap_or ( s)
790
+ }
791
+
702
792
fn extract_hex_secret_from_descriptor ( & self , descriptor : & str ) -> anyhow:: Result < Option < String > > {
703
793
// Parse the descriptor to extract the xprv
704
794
// The descriptor format is typically: tr([xprv...]/path)...
@@ -722,6 +812,11 @@ impl WalletManager {
722
812
723
813
Ok ( None )
724
814
}
815
+
816
+ pub fn create_taproot_descriptor_from_hex ( & self , hex_secret : & str ) -> anyhow:: Result < String > {
817
+ let ( network, _) = self . fallback_network ( ) ;
818
+ Self :: descriptor_from_hex_secret ( network, hex_secret)
819
+ }
725
820
}
726
821
727
822
impl RpcServerImpl {
0 commit comments