@@ -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:: 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" ) ]
61- use bdk_kyoto:: LightClient ;
62- #[ cfg( feature = "compiler" ) ]
63- use bdk_wallet:: bitcoin:: XOnlyPublicKey ;
86+ use bdk_kyoto:: { Info , LightClient } ;
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 } ;
@@ -1260,6 +1283,15 @@ pub(crate) async fn handle_command(cli_opts: CliOpts) -> Result<String, Error> {
12601283 }
12611284 Ok ( "" . to_string ( ) )
12621285 }
1286+ CliSubCommand :: Descriptor {
1287+ subcommand : descriptor_subcommand,
1288+ } => {
1289+ let network = cli_opts. network ;
1290+ let descriptor = handle_descriptor_subcommand ( network, descriptor_subcommand)
1291+ . map_err ( |e| Error :: Generic ( e. to_string ( ) ) ) ?;
1292+ let json = serde_json:: to_string_pretty ( & descriptor) ?;
1293+ Ok ( json)
1294+ }
12631295 } ;
12641296 result
12651297}
@@ -1333,6 +1365,103 @@ fn readline() -> Result<String, Error> {
13331365 Ok ( buffer)
13341366}
13351367
1368+ pub fn handle_descriptor_subcommand (
1369+ network : Network ,
1370+ subcommand : DescriptorSubCommand ,
1371+ ) -> Result < Value , Error > {
1372+ match subcommand {
1373+ DescriptorSubCommand :: Generate {
1374+ r#type,
1375+ multipath,
1376+ key,
1377+ } => {
1378+ let ( descriptor_type, derivation_path_str) = match r#type {
1379+ 44 => ( DescriptorType :: Bip44 , "m/44h/1h/0h" ) ,
1380+ 49 => ( DescriptorType :: Bip49 , "m/49h/1h/0h" ) ,
1381+ 84 => ( DescriptorType :: Bip84 , "m/84h/1h/0h" ) ,
1382+ 86 => ( DescriptorType :: Bip86 , "m/86h/1h/0h" ) ,
1383+ _ => return Err ( Error :: UnsupportedScriptType ( r#type) ) ,
1384+ } ;
1385+
1386+ match ( multipath, key. as_ref ( ) ) {
1387+ ( true , Some ( k) ) => generate_multipath_descriptor ( & network, r#type, k) ,
1388+ ( false , Some ( k) ) => {
1389+ if is_mnemonic ( k) {
1390+ generate_descriptor_from_mnemonic_string (
1391+ k,
1392+ network,
1393+ derivation_path_str,
1394+ descriptor_type,
1395+ )
1396+ } else {
1397+ generate_standard_descriptor ( & network, r#type, k)
1398+ }
1399+ }
1400+ ( false , None ) => generate_new_descriptor_with_mnemonic ( network, descriptor_type) ,
1401+ _ => Err ( Error :: InvalidArguments (
1402+ "Provide a key or weak string" . to_string ( ) ,
1403+ ) ) ,
1404+ }
1405+ }
1406+ DescriptorSubCommand :: Info { descriptor } => {
1407+ let parsed: Descriptor < DescriptorPublicKey > = descriptor
1408+ . parse ( )
1409+ . map_err ( |e| Error :: Generic ( format ! ( "Failed to parse descriptor: {}" , e) ) ) ?;
1410+
1411+ let checksum = parsed. to_string ( ) ;
1412+ let script_type = match parsed {
1413+ Descriptor :: Wpkh ( _) => "wpkh" ,
1414+ Descriptor :: Pkh ( _) => "pkh" ,
1415+ Descriptor :: Sh ( _) => "sh" ,
1416+ Descriptor :: Tr ( _) => "tr" ,
1417+ _ => "other" ,
1418+ } ;
1419+
1420+ let json = json ! ( {
1421+ "descriptor" : checksum,
1422+ "type" : script_type,
1423+ "is_multipath" : descriptor. contains( "/*" ) ,
1424+ } ) ;
1425+
1426+ Ok ( json)
1427+ }
1428+ }
1429+ }
1430+
1431+ pub fn generate_standard_descriptor (
1432+ network : & Network ,
1433+ script_type : u8 ,
1434+ key : & str ,
1435+ ) -> Result < Value , Error > {
1436+ let descriptor_type = match script_type {
1437+ 44 => DescriptorType :: Bip44 ,
1438+ 49 => DescriptorType :: Bip49 ,
1439+ 84 => DescriptorType :: Bip84 ,
1440+ 86 => DescriptorType :: Bip86 ,
1441+ _ => return Err ( Error :: UnsupportedScriptType ( script_type) ) ,
1442+ } ;
1443+
1444+ generate_descriptor_from_key_by_type ( network, key, descriptor_type)
1445+ }
1446+
1447+ impl fmt:: Display for DescriptorType {
1448+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
1449+ let s = match self {
1450+ DescriptorType :: Bip44 => "bip44" ,
1451+ DescriptorType :: Bip49 => "bip49" ,
1452+ DescriptorType :: Bip84 => "bip84" ,
1453+ DescriptorType :: Bip86 => "bip86" ,
1454+ } ;
1455+ write ! ( f, "{}" , s)
1456+ }
1457+ }
1458+
1459+ #[ cfg( any(
1460+ feature = "electrum" ,
1461+ feature = "esplora" ,
1462+ feature = "cbf" ,
1463+ feature = "rpc"
1464+ ) ) ]
13361465#[ cfg( test) ]
13371466mod test {
13381467 #[ cfg( any(
0 commit comments