Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ page. See [DEVELOPMENT_CYCLE.md](DEVELOPMENT_CYCLE.md) for more details.
## [Unreleased]

- Added support for Multipath (two-paths) descriptors.

- Support for JSON and TOML format through `--format` flag.

## [4.0.0]

Expand Down
12 changes: 12 additions & 0 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,23 @@ pub struct CliOpts {
/// Default value : ~/.bdk-bitcoin
#[arg(env = "DATADIR", short = 'd', long = "datadir")]
pub datadir: Option<std::path::PathBuf>,
/// Sets the output format.
#[arg(env = "FORMAT", short = 'f', long = "format", default_value = "json")]
pub format: OutputFormatType,
/// Top level cli sub-commands.
#[command(subcommand)]
pub subcommand: CliSubCommand,
}

/// Supported output formats.
#[derive(Clone, Debug, PartialEq, Eq, clap::ValueEnum)]
pub enum OutputFormatType {
/// JSON output.
Json,
/// TOML output.
Toml,
}

/// Top level cli sub-commands.
#[derive(Debug, Subcommand, Clone, PartialEq)]
#[command(rename_all = "snake")]
Expand Down
14 changes: 9 additions & 5 deletions src/handlers/key.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::commands::KeySubCommand;
use crate::commands::{KeySubCommand, OutputFormatType};
use crate::error::BDKCliError as Error;
use crate::handlers::{AppCommand, AppContext, Init};
use crate::utils::{output::FormatOutput, types::KeyResult};
Expand All @@ -12,17 +12,21 @@ use bdk_wallet::miniscript::{self, Segwitv0};
use clap::Parser;

impl KeySubCommand {
pub fn execute(&self, ctx: &mut AppContext<Init>) -> Result<(), Error> {
pub fn execute(
&self,
ctx: &mut AppContext<Init>,
format: OutputFormatType,
) -> Result<(), Error> {
match self {
KeySubCommand::Generate(generate_key_command) => generate_key_command
.execute(ctx)?
.write_out(std::io::stdout()),
.write_out(std::io::stdout(), format),
KeySubCommand::Restore(restore_key_command) => restore_key_command
.execute(ctx)?
.write_out(std::io::stdout()),
.write_out(std::io::stdout(), format),
KeySubCommand::Derive(derive_key_command) => derive_key_command
.execute(ctx)?
.write_out(std::io::stdout()),
.write_out(std::io::stdout(), format),
}
}
}
Expand Down
72 changes: 42 additions & 30 deletions src/handlers/offline.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::commands::OfflineWalletSubCommand;
use crate::commands::{OfflineWalletSubCommand, OutputFormatType};
use crate::error::BDKCliError as Error;
use crate::handlers::{AppCommand, AppContext, OfflineOperations};
use crate::utils::output::{FormatOutput, ListResult};
Expand Down Expand Up @@ -36,56 +36,68 @@ use {
};

impl OfflineWalletSubCommand {
pub fn execute(&self, ctx: &mut AppContext<OfflineOperations<'_>>) -> Result<(), Error> {
pub fn execute(
&self,
ctx: &mut AppContext<OfflineOperations<'_>>,
format: OutputFormatType,
) -> Result<(), Error> {
match self {
Self::NewAddress(new_address) => new_address.execute(ctx)?.write_out(std::io::stdout()),
Self::Balance(balance) => balance.execute(ctx)?.write_out(std::io::stdout()),
Self::NewAddress(new_address) => new_address
.execute(ctx)?
.write_out(std::io::stdout(), format),
Self::Balance(balance) => balance.execute(ctx)?.write_out(std::io::stdout(), format),
Self::UnusedAddress(unused_address_command) => unused_address_command
.execute(ctx)?
.write_out(std::io::stdout()),
Self::Unspent(unspent_command) => {
unspent_command.execute(ctx)?.write_out(std::io::stdout())
}
.write_out(std::io::stdout(), format),
Self::Unspent(unspent_command) => unspent_command
.execute(ctx)?
.write_out(std::io::stdout(), format),
Self::Transactions(transactions_command) => transactions_command
.execute(ctx)?
.write_out(std::io::stdout()),
Self::CreateTx(createtx_command) => {
createtx_command.execute(ctx)?.write_out(std::io::stdout())
}
.write_out(std::io::stdout(), format),
Self::CreateTx(createtx_command) => createtx_command
.execute(ctx)?
.write_out(std::io::stdout(), format),
#[cfg(feature = "silent-payments")]
Self::CreateSpTx(cmd) => cmd.execute(ctx)?.write_out(std::io::stdout()),
Self::BumpFee(bumpfee_command) => {
bumpfee_command.execute(ctx)?.write_out(std::io::stdout())
}
Self::Policies(policies_command) => {
policies_command.execute(ctx)?.write_out(std::io::stdout())
}
Self::CreateSpTx(cmd) => cmd.execute(ctx)?.write_out(std::io::stdout(), format),
Self::BumpFee(bumpfee_command) => bumpfee_command
.execute(ctx)?
.write_out(std::io::stdout(), format),
Self::Policies(policies_command) => policies_command
.execute(ctx)?
.write_out(std::io::stdout(), format),
Self::PublicDescriptor(public_descriptor_command) => public_descriptor_command
.execute(ctx)?
.write_out(std::io::stdout()),
Self::Sign(sign_command) => sign_command.execute(ctx)?.write_out(std::io::stdout()),
.write_out(std::io::stdout(), format),
Self::Sign(sign_command) => sign_command
.execute(ctx)?
.write_out(std::io::stdout(), format),
Self::ExtractPsbt(extract_psbt_command) => extract_psbt_command
.execute(ctx)?
.write_out(std::io::stdout()),
.write_out(std::io::stdout(), format),
Self::FinalizePsbt(finalize_psbt_command) => finalize_psbt_command
.execute(ctx)?
.write_out(std::io::stdout()),
.write_out(std::io::stdout(), format),
Self::CombinePsbt(combine_psbt_command) => combine_psbt_command
.execute(ctx)?
.write_out(std::io::stdout()),
.write_out(std::io::stdout(), format),
#[cfg(feature = "message_signer")]
Self::SignMessage(sign_message_command) => sign_message_command
.execute(ctx)?
.write_out(std::io::stdout()),
.write_out(std::io::stdout(), format),
#[cfg(feature = "message_signer")]
Self::VerifyMessage(verify_message_command) => verify_message_command
.execute(ctx)?
.write_out(std::io::stdout()),
Self::LockUtxo(lock_utxo) => lock_utxo.execute(ctx)?.write_out(std::io::stdout()),
Self::UnlockUtxo(unlock_utxo) => unlock_utxo.execute(ctx)?.write_out(std::io::stdout()),
Self::LockedUtxos(locked_utxos) => {
locked_utxos.execute(ctx)?.write_out(std::io::stdout())
.write_out(std::io::stdout(), format),
Self::LockUtxo(lock_utxo) => {
lock_utxo.execute(ctx)?.write_out(std::io::stdout(), format)
}
Self::UnlockUtxo(unlock_utxo) => unlock_utxo
.execute(ctx)?
.write_out(std::io::stdout(), format),
Self::LockedUtxos(locked_utxos) => locked_utxos
.execute(ctx)?
.write_out(std::io::stdout(), format),
#[cfg(feature = "dns_payment")]
Self::CreateDnsTx(_) => Err(Error::Generic(
"CreateDnsTx is dispatched asynchronously through main".to_string(),
Expand Down
27 changes: 19 additions & 8 deletions src/handlers/online.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ use clap::Parser;
use crate::client::BlockchainClient::Electrum;
#[cfg(feature = "cbf")]
use crate::client::{BlockchainClient::KyotoClient, sync_kyoto_client};
#[cfg(any(
feature = "electrum",
feature = "esplora",
feature = "cbf",
feature = "rpc"
))]
use crate::commands::OutputFormatType;
#[cfg(feature = "esplora")]
use {crate::client::BlockchainClient::Esplora, bdk_esplora::EsploraAsyncExt};
#[cfg(feature = "rpc")]
Expand Down Expand Up @@ -44,35 +51,39 @@ use {
feature = "rpc"
))]
impl OnlineWalletSubCommand {
pub async fn execute(&self, ctx: &mut AppContext<OnlineOperations<'_>>) -> Result<(), Error> {
pub async fn execute(
&self,
ctx: &mut AppContext<OnlineOperations<'_>>,
format: OutputFormatType,
) -> Result<(), Error> {
match self {
OnlineWalletSubCommand::FullScan(full_scan_command) => {
let response: StatusResult = full_scan_command.execute(ctx).await?;
response.write_out(std::io::stdout())
response.write_out(std::io::stdout(), format)
}
OnlineWalletSubCommand::Sync(sync_command) => {
let response: StatusResult = sync_command.execute(ctx).await?;
response.write_out(std::io::stdout())
response.write_out(std::io::stdout(), format)
}
OnlineWalletSubCommand::Broadcast(broadcast_command) => {
let response: TransactionResult = broadcast_command.execute(ctx).await?;
response.write_out(std::io::stdout())
response.write_out(std::io::stdout(), format)
}
OnlineWalletSubCommand::ReceivePayjoin(receive_payjoin_command) => {
let response: StatusResult = receive_payjoin_command.execute(ctx).await?;
response.write_out(std::io::stdout())
response.write_out(std::io::stdout(), format)
}
OnlineWalletSubCommand::SendPayjoin(send_payjoin_command) => {
let response: StatusResult = send_payjoin_command.execute(ctx).await?;
response.write_out(std::io::stdout())
response.write_out(std::io::stdout(), format)
}
OnlineWalletSubCommand::ResumePayjoin(resume_payjoin_command) => {
let response: StatusResult = resume_payjoin_command.execute(ctx).await?;
response.write_out(std::io::stdout())
response.write_out(std::io::stdout(), format)
}
OnlineWalletSubCommand::PayjoinHistory(payjoin_history_command) => {
let response: StatusResult = payjoin_history_command.execute(ctx).await?;
response.write_out(std::io::stdout())
response.write_out(std::io::stdout(), format)
}
}
}
Expand Down
15 changes: 11 additions & 4 deletions src/handlers/repl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use {
))]
use crate::client::BlockchainClient;
#[cfg(feature = "repl")]
use crate::commands::OutputFormatType;
#[cfg(feature = "repl")]
use {crate::commands::WalletSubCommand, crate::error::BDKCliError as Error, std::io::Write};

#[cfg(feature = "repl")]
Expand All @@ -40,6 +42,7 @@ pub(crate) async fn respond(
feature = "cbf"
))]
wallet_name: &str,
format: OutputFormatType,
) -> Result<bool, String> {
let args = shlex::split(line).ok_or("error: Invalid quoting".to_string())?;

Expand All @@ -55,7 +58,7 @@ pub(crate) async fn respond(
ReplSubCommand::Wallet { subcommand } => match subcommand {
WalletSubCommand::OfflineWalletSubCommand(cmd) => {
let mut ctx = AppContext::new_offline_wallet(network, datadir, wallet);
cmd.execute(&mut ctx).map_err(|e| e.to_string())?;
cmd.execute(&mut ctx, format).map_err(|e| e.to_string())?;
Some(())
}
#[cfg(any(
Expand All @@ -74,7 +77,9 @@ pub(crate) async fn respond(
wallet_name.to_string(),
);

cmd.execute(&mut ctx).await.map_err(|e| e.to_string())?;
cmd.execute(&mut ctx, format)
.await
.map_err(|e| e.to_string())?;
Some(())
}
WalletSubCommand::Config(_) => {
Expand All @@ -92,14 +97,16 @@ pub(crate) async fn respond(
let mut ctx = AppContext::new(network, datadir);
cmd.execute(&mut ctx)
.map_err(|e| e.to_string())?
.write_out(std::io::stdout())
.write_out(std::io::stdout(), format)
.map_err(|e| e.to_string())?;
Some(())
}

ReplSubCommand::Key { subcommand } => {
let mut ctx = AppContext::new(network, datadir);
subcommand.execute(&mut ctx).map_err(|e| e.to_string())?;
subcommand
.execute(&mut ctx, format)
.map_err(|e| e.to_string())?;
Some(())
}

Expand Down
29 changes: 19 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ async fn run(cli_opts: CliOpts) -> Result<(), Error> {
runtime.wallet_name.clone(),
);

cmd.execute(&mut ctx).await?;
cmd.execute(&mut ctx, cli_opts.format).await?;
}
wallet.persist()?;
}
Expand All @@ -100,9 +100,9 @@ async fn run(cli_opts: CliOpts) -> Result<(), Error> {
dns_cmd
.execute(&mut ctx)
.await?
.write_out(std::io::stdout())?;
.write_out(std::io::stdout(), cli_opts.format)?;
}
other => other.execute(&mut ctx)?,
other => other.execute(&mut ctx, cli_opts.format)?,
}
}
wallet.persist()?;
Expand All @@ -113,26 +113,30 @@ async fn run(cli_opts: CliOpts) -> Result<(), Error> {

let mut ctx = AppContext::new(cli_opts.network, home_dir);

config_cmd.execute(&mut ctx)?.write_out(std::io::stdout())?;
config_cmd
.execute(&mut ctx)?
.write_out(std::io::stdout(), cli_opts.format)?;
}
},

CliSubCommand::Key { subcommand } => {
let mut ctx = AppContext::new(cli_opts.network, home_dir);

subcommand.execute(&mut ctx)?;
subcommand.execute(&mut ctx, cli_opts.format)?;
}

CliSubCommand::Descriptor(cmd) => {
let mut ctx = AppContext::new(cli_opts.network, home_dir);

cmd.execute(&mut ctx)?.write_out(std::io::stdout())?;
cmd.execute(&mut ctx)?
.write_out(std::io::stdout(), cli_opts.format)?;
}

CliSubCommand::Wallets(cmd) => {
let mut ctx = AppContext::new(cli_opts.network, home_dir);

cmd.execute(&mut ctx)?.write_out(std::io::stdout())?;
cmd.execute(&mut ctx)?
.write_out(std::io::stdout(), cli_opts.format)?;
}

#[cfg(feature = "repl")]
Expand Down Expand Up @@ -183,6 +187,7 @@ async fn run(cli_opts: CliOpts) -> Result<(), Error> {
feature = "cbf"
))]
&wallet_name,
cli_opts.format.clone(),
)
.await
.map_err(Error::Generic)?;
Expand All @@ -197,7 +202,8 @@ async fn run(cli_opts: CliOpts) -> Result<(), Error> {
CliSubCommand::Compile(cmd) => {
let mut ctx = AppContext::new(cli_opts.network, home_dir);

cmd.execute(&mut ctx)?.write_out(std::io::stdout())?;
cmd.execute(&mut ctx)?
.write_out(std::io::stdout(), cli_opts.format)?;
}
CliSubCommand::Completions { shell } => {
clap_complete::generate(
Expand All @@ -211,12 +217,15 @@ async fn run(cli_opts: CliOpts) -> Result<(), Error> {
CliSubCommand::SilentPaymentCode(cmd) => {
let mut ctx = AppContext::new(cli_opts.network, home_dir);

cmd.execute(&mut ctx)?.write_out(std::io::stdout())?;
cmd.execute(&mut ctx)?
.write_out(std::io::stdout(), cli_opts.format)?;
}
#[cfg(feature = "dns_payment")]
CliSubCommand::ResolveDnsRecipient(cmd) => {
let mut ctx = AppContext::new(cli_opts.network, home_dir);
cmd.execute(&mut ctx).await?.write_out(std::io::stdout())?;
cmd.execute(&mut ctx)
.await?
.write_out(std::io::stdout(), cli_opts.format)?;
}
}

Expand Down
Loading