@@ -35,32 +35,55 @@ use bdk_wallet::keys::{
3535 bip39:: WordCount ,
3636} ;
3737use bdk_wallet:: miniscript:: miniscript;
38+ use bdk_wallet:: bitcoin:: bip32:: { DerivationPath , KeySource } ;
39+ use bdk_wallet:: bitcoin:: consensus:: encode:: serialize_hex;
40+ use bdk_wallet:: bitcoin:: script:: PushBytesBuf ;
41+ use bdk_wallet:: bitcoin:: Network ;
42+ use bdk_wallet:: bitcoin:: { secp256k1:: Secp256k1 , Txid } ;
43+ use bdk_wallet:: bitcoin:: { Amount , FeeRate , Psbt , Sequence } ;
44+ use bdk_wallet:: descriptor:: { Descriptor , Segwitv0 } ;
45+ use bdk_wallet:: keys:: bip39:: WordCount ;
3846#[ cfg( feature = "sqlite" ) ]
3947use bdk_wallet:: rusqlite:: Connection ;
4048use bdk_wallet:: { KeychainKind , SignOptions , Wallet } ;
4149#[ cfg( feature = "compiler" ) ]
4250use bdk_wallet:: {
4351 descriptor:: { Descriptor , Legacy , Miniscript } ,
4452 miniscript:: { Tap , descriptor:: TapTree , policy:: Concrete } ,
53+ descriptor:: { Legacy , Miniscript } ,
54+ miniscript:: policy:: Concrete ,
4555} ;
4656use cli_table:: { Cell , CellStruct , Style , Table , format:: Justify } ;
4757use serde_json:: json;
58+ use bdk_wallet:: { KeychainKind , SignOptions , Wallet } ;
59+
60+ #[ cfg( feature = "electrum" ) ]
61+ use crate :: utils:: BlockchainClient :: Electrum ;
62+ #[ cfg( feature = "cbf" ) ]
63+ use bdk_kyoto:: { Info , LightClient } ;
64+ #[ cfg( feature = "compiler" ) ]
65+ use bdk_wallet:: bitcoin:: XOnlyPublicKey ;
66+ use bdk_wallet:: bitcoin:: base64:: prelude:: * ;
67+ use bdk_wallet:: keys:: DescriptorKey :: Secret ;
68+ use bdk_wallet:: keys:: {
69+ DerivableKey , DescriptorKey , DescriptorKey :: Secret , DescriptorPublicKey , ExtendedKey ,
70+ GeneratableKey , GeneratedKey , bip39:: WordCount ,
71+ } ;
72+ use bdk_wallet:: miniscript:: miniscript;
73+ use serde_json:: { Value , json} ;
4874use std:: collections:: BTreeMap ;
4975#[ cfg( any( feature = "electrum" , feature = "esplora" ) ) ]
5076use std:: collections:: HashSet ;
5177use std:: convert:: TryFrom ;
78+ use std:: fmt;
5279#[ cfg( any( feature = "repl" , feature = "electrum" , feature = "esplora" ) ) ]
5380use std:: io:: Write ;
5481use std:: str:: FromStr ;
55- #[ cfg( any( feature = "redb" , feature = "compiler" ) ) ]
56- use std:: sync:: Arc ;
5782
5883#[ cfg( feature = "electrum" ) ]
5984use crate :: utils:: BlockchainClient :: Electrum ;
6085#[ cfg( feature = "cbf" ) ]
6186use bdk_kyoto:: { Info , LightClient } ;
62- #[ cfg( feature = "compiler" ) ]
63- use bdk_wallet:: bitcoin:: XOnlyPublicKey ;
6487use bdk_wallet:: bitcoin:: base64:: prelude:: * ;
6588#[ cfg( feature = "cbf" ) ]
6689use tokio:: select;
@@ -72,7 +95,7 @@ use tokio::select;
7295) ) ]
7396use {
7497 crate :: commands:: OnlineWalletSubCommand :: * ,
75- bdk_wallet:: bitcoin:: { Transaction , consensus:: Decodable , hex:: FromHex } ,
98+ bdk_wallet:: bitcoin:: { consensus:: Decodable , hex:: FromHex , Transaction } ,
7699} ;
77100#[ cfg( feature = "esplora" ) ]
78101use { crate :: utils:: BlockchainClient :: Esplora , bdk_esplora:: EsploraAsyncExt } ;
@@ -1280,6 +1303,15 @@ pub(crate) async fn handle_command(cli_opts: CliOpts) -> Result<String, Error> {
12801303 }
12811304 Ok ( "" . to_string ( ) )
12821305 }
1306+ CliSubCommand :: Descriptor {
1307+ subcommand : descriptor_subcommand,
1308+ } => {
1309+ let network = cli_opts. network ;
1310+ let descriptor = handle_descriptor_subcommand ( network, descriptor_subcommand)
1311+ . map_err ( |e| Error :: Generic ( e. to_string ( ) ) ) ?;
1312+ let json = serde_json:: to_string_pretty ( & descriptor) ?;
1313+ Ok ( json)
1314+ }
12831315 } ;
12841316 result
12851317}
@@ -1353,6 +1385,103 @@ fn readline() -> Result<String, Error> {
13531385 Ok ( buffer)
13541386}
13551387
1388+ pub fn handle_descriptor_subcommand (
1389+ network : Network ,
1390+ subcommand : DescriptorSubCommand ,
1391+ ) -> Result < Value , Error > {
1392+ match subcommand {
1393+ DescriptorSubCommand :: Generate {
1394+ r#type,
1395+ multipath,
1396+ key,
1397+ } => {
1398+ let ( descriptor_type, derivation_path_str) = match r#type {
1399+ 44 => ( DescriptorType :: Bip44 , "m/44h/1h/0h" ) ,
1400+ 49 => ( DescriptorType :: Bip49 , "m/49h/1h/0h" ) ,
1401+ 84 => ( DescriptorType :: Bip84 , "m/84h/1h/0h" ) ,
1402+ 86 => ( DescriptorType :: Bip86 , "m/86h/1h/0h" ) ,
1403+ _ => return Err ( Error :: UnsupportedScriptType ( r#type) ) ,
1404+ } ;
1405+
1406+ match ( multipath, key. as_ref ( ) ) {
1407+ ( true , Some ( k) ) => generate_multipath_descriptor ( & network, r#type, k) ,
1408+ ( false , Some ( k) ) => {
1409+ if is_mnemonic ( k) {
1410+ generate_descriptor_from_mnemonic_string (
1411+ k,
1412+ network,
1413+ derivation_path_str,
1414+ descriptor_type,
1415+ )
1416+ } else {
1417+ generate_standard_descriptor ( & network, r#type, k)
1418+ }
1419+ }
1420+ ( false , None ) => generate_new_descriptor_with_mnemonic ( network, descriptor_type) ,
1421+ _ => Err ( Error :: InvalidArguments (
1422+ "Provide a key or weak string" . to_string ( ) ,
1423+ ) ) ,
1424+ }
1425+ }
1426+ DescriptorSubCommand :: Info { descriptor } => {
1427+ let parsed: Descriptor < DescriptorPublicKey > = descriptor
1428+ . parse ( )
1429+ . map_err ( |e| Error :: Generic ( format ! ( "Failed to parse descriptor: {}" , e) ) ) ?;
1430+
1431+ let checksum = parsed. to_string ( ) ;
1432+ let script_type = match parsed {
1433+ Descriptor :: Wpkh ( _) => "wpkh" ,
1434+ Descriptor :: Pkh ( _) => "pkh" ,
1435+ Descriptor :: Sh ( _) => "sh" ,
1436+ Descriptor :: Tr ( _) => "tr" ,
1437+ _ => "other" ,
1438+ } ;
1439+
1440+ let json = json ! ( {
1441+ "descriptor" : checksum,
1442+ "type" : script_type,
1443+ "is_multipath" : descriptor. contains( "/*" ) ,
1444+ } ) ;
1445+
1446+ Ok ( json)
1447+ }
1448+ }
1449+ }
1450+
1451+ pub fn generate_standard_descriptor (
1452+ network : & Network ,
1453+ script_type : u8 ,
1454+ key : & str ,
1455+ ) -> Result < Value , Error > {
1456+ let descriptor_type = match script_type {
1457+ 44 => DescriptorType :: Bip44 ,
1458+ 49 => DescriptorType :: Bip49 ,
1459+ 84 => DescriptorType :: Bip84 ,
1460+ 86 => DescriptorType :: Bip86 ,
1461+ _ => return Err ( Error :: UnsupportedScriptType ( script_type) ) ,
1462+ } ;
1463+
1464+ generate_descriptor_from_key_by_type ( network, key, descriptor_type)
1465+ }
1466+
1467+ impl fmt:: Display for DescriptorType {
1468+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1469+ let s = match self {
1470+ DescriptorType :: Bip44 => "bip44" ,
1471+ DescriptorType :: Bip49 => "bip49" ,
1472+ DescriptorType :: Bip84 => "bip84" ,
1473+ DescriptorType :: Bip86 => "bip86" ,
1474+ } ;
1475+ write ! ( f, "{}" , s)
1476+ }
1477+ }
1478+
1479+ #[ cfg( any(
1480+ feature = "electrum" ,
1481+ feature = "esplora" ,
1482+ feature = "cbf" ,
1483+ feature = "rpc"
1484+ ) ) ]
13561485#[ cfg( test) ]
13571486mod test {
13581487 #[ cfg( any(
0 commit comments