))]
use crate::{
client::ClientType,
- online::{
+ handlers::online::{
BroadcastCommand, FullScanCommand, ReceivePayjoinCommand, SendPayjoinCommand, SyncCommand,
},
};
impl KeySubCommand {
pub fn execute(&self, ctx: &mut AppContext) -> Result<(), Error> {
match self {
- KeySubCommand::Generate(generate_key_command) => {
- generate_key_command.execute(ctx)?.print()
- }
- KeySubCommand::Restore(restore_key_command) => {
- restore_key_command.execute(ctx)?.print()
- }
- KeySubCommand::Derive(derive_key_command) => derive_key_command.execute(ctx)?.print(),
+ KeySubCommand::Generate(generate_key_command) => generate_key_command
+ .execute(ctx)?
+ .write_out(std::io::stdout()),
+ KeySubCommand::Restore(restore_key_command) => restore_key_command
+ .execute(ctx)?
+ .write_out(std::io::stdout()),
+ KeySubCommand::Derive(derive_key_command) => derive_key_command
+ .execute(ctx)?
+ .write_out(std::io::stdout()),
}
}
}
use crate::commands::OfflineWalletSubCommand;
use crate::error::BDKCliError as Error;
use crate::handlers::{AppCommand, AppContext};
-use crate::utils::output::FormatOutput;
+use crate::utils::output::{FormatOutput, ListResult};
use crate::utils::parse_address;
use crate::utils::types::{
AddressResult, BalanceResult, KeychainPair, PsbtResult, RawPsbt, TransactionDetails,
- TransactionListResult, UnspentDetails, UnspentListResult,
+ UnspentDetails,
};
use crate::utils::{parse_outpoint, parse_recipient};
use bdk_wallet::bitcoin::base64::Engine;
impl OfflineWalletSubCommand {
pub fn execute(&self, ctx: &mut AppContext<'_>) -> Result<(), Error> {
match self {
- Self::NewAddress(new_address) => new_address.execute(ctx)?.print(),
- Self::Balance(balance) => balance.execute(ctx)?.print(),
- Self::UnusedAddress(unused_address_command) => {
- unused_address_command.execute(ctx)?.print()
+ 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::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())
}
- Self::Unspent(unspent_command) => unspent_command.execute(ctx)?.print(),
- Self::Transactions(transactions_command) => transactions_command.execute(ctx)?.print(),
- Self::CreateTx(createtx_command) => createtx_command.execute(ctx)?.print(),
- Self::BumpFee(bumpfee_command) => bumpfee_command.execute(ctx)?.print(),
- Self::Policies(policies_command) => policies_command.execute(ctx)?.print(),
- Self::PublicDescriptor(public_descriptor_command) => {
- public_descriptor_command.execute(ctx)?.print()
+ 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())
}
- Self::Sign(sign_command) => sign_command.execute(ctx)?.print(),
- Self::ExtractPsbt(extract_psbt_command) => extract_psbt_command.execute(ctx)?.print(),
- Self::FinalizePsbt(finalize_psbt_command) => {
- finalize_psbt_command.execute(ctx)?.print()
+ Self::BumpFee(bumpfee_command) => {
+ bumpfee_command.execute(ctx)?.write_out(std::io::stdout())
}
- Self::CombinePsbt(combine_psbt_command) => combine_psbt_command.execute(ctx)?.print(),
+ Self::Policies(policies_command) => {
+ policies_command.execute(ctx)?.write_out(std::io::stdout())
+ }
+ 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()),
+ Self::ExtractPsbt(extract_psbt_command) => extract_psbt_command
+ .execute(ctx)?
+ .write_out(std::io::stdout()),
+ Self::FinalizePsbt(finalize_psbt_command) => finalize_psbt_command
+ .execute(ctx)?
+ .write_out(std::io::stdout()),
+ Self::CombinePsbt(combine_psbt_command) => combine_psbt_command
+ .execute(ctx)?
+ .write_out(std::io::stdout()),
#[cfg(feature = "bip322")]
- Self::SignMessage(sign_message_command) => sign_message_command.execute(ctx)?.print(),
+ Self::SignMessage(sign_message_command) => sign_message_command
+ .execute(ctx)?
+ .write_out(std::io::stdout()),
#[cfg(feature = "bip322")]
- Self::VerifyMessage(verify_message_command) => {
- verify_message_command.execute(ctx)?.print()
- }
+ Self::VerifyMessage(verify_message_command) => verify_message_command
+ .execute(ctx)?
+ .write_out(std::io::stdout()),
}
}
}
pub struct UnspentCommand {}
impl AppCommand for UnspentCommand {
- type Output = UnspentListResult;
+ type Output = ListResult<UnspentDetails>;
fn execute(&self, ctx: &mut AppContext) -> Result<Self::Output, Error> {
let wallet = ctx
.map(|utxo| UnspentDetails::from_local_output(&utxo, ctx.network))
.collect();
- Ok(UnspentListResult(utxos))
+ Ok(ListResult::new(utxos))
}
}
pub struct TransactionsCommand {}
impl AppCommand for TransactionsCommand {
- type Output = TransactionListResult;
+ type Output = ListResult<TransactionDetails>;
fn execute(&self, ctx: &mut AppContext) -> Result<Self::Output, Error> {
let wallet = ctx
})
.collect();
- Ok(TransactionListResult(txns))
+ Ok(ListResult::new(txns))
}
}
pub async fn execute(&self, ctx: &mut AppContext<'_>) -> Result<(), Error> {
match self {
OnlineWalletSubCommand::FullScan(full_scan_command) => {
- full_scan_command.execute(ctx).await?.print()
+ let response: StatusResult = full_scan_command.execute(ctx).await?;
+ response.write_out(std::io::stdout())
+ }
+ OnlineWalletSubCommand::Sync(sync_command) => {
+ let response: StatusResult = sync_command.execute(ctx).await?;
+ response.write_out(std::io::stdout())
}
- OnlineWalletSubCommand::Sync(sync_command) => sync_command.execute(ctx).await?.print(),
OnlineWalletSubCommand::Broadcast(broadcast_command) => {
- broadcast_command.execute(ctx).await?.print()
+ let response: TransactionResult = broadcast_command.execute(ctx).await?;
+ response.write_out(std::io::stdout())
}
OnlineWalletSubCommand::ReceivePayjoin(receive_payjoin_command) => {
- receive_payjoin_command.execute(ctx).await?.print()
+ let response: StatusResult = receive_payjoin_command.execute(ctx).await?;
+ response.write_out(std::io::stdout())
}
OnlineWalletSubCommand::SendPayjoin(send_payjoin_command) => {
- send_payjoin_command.execute(ctx).await?.print()
+ let response: StatusResult = send_payjoin_command.execute(ctx).await?;
+ response.write_out(std::io::stdout())
}
}
}
feature = "cbf",
feature = "rpc"
))]
-
impl AsyncCommand for BroadcastCommand {
type Output = TransactionResult;
use bdk_wallet::{Wallet, bitcoin::Network};
-// #[cfg(feature = "repl")]
+#[cfg(feature = "repl")]
use crate::handlers::{AppCommand, AppContext};
use crate::utils::output::FormatOutput;
}
WalletSubCommand::Config(config_cmd) => {
let mut ctx = AppContext::new(network, datadir);
- let res = config_cmd
+ let _ = config_cmd
.execute(&mut ctx)
.map_err(|e| e.to_string())?
- .print();
+ .write_out(std::io::stdout());
Some(())
}
},
// Assuming your REPL Descriptor command is an inline struct based on commands.rs
ReplSubCommand::Descriptor(cmd) => {
- let value = cmd.execute(&mut ctx).map_err(|e| e.to_string())?.print();
+ let value = cmd
+ .execute(&mut ctx)
+ .map_err(|e| e.to_string())?
+ .write_out(std::io::stdout());
Some(())
}
let mut ctx = AppContext::new(cli_opts.network, home_dir);
- config_cmd.execute(&mut ctx)?.print()?;
+ config_cmd.execute(&mut ctx)?.write_out(std::io::stdout())?;
}
},
}
CliSubCommand::Descriptor(descriptor_command) => {
let mut ctx = AppContext::new(cli_opts.network, home_dir);
- descriptor_command.execute(&mut ctx)?.print()?;
+ descriptor_command
+ .execute(&mut ctx)?
+ .write_out(std::io::stdout())?;
}
CliSubCommand::Wallets(cmd) => {
let mut ctx = AppContext::new(cli_opts.network, home_dir);
- cmd.execute(&mut ctx)?.print()?;
+ cmd.execute(&mut ctx)?.write_out(std::io::stdout())?;
}
CliSubCommand::Repl { wallet: _ } => todo!(),
CliSubCommand::Completions { shell } => {
#[cfg(feature = "compiler")]
CliSubCommand::Compile(cmd) => {
let mut ctx = AppContext::new(cli_opts.network, home_dir);
- cmd.execute(&mut ctx)?.print()?;
+ cmd.execute(&mut ctx)?.write_out(std::io::stdout())?;
}
};
+use std::io::Write;
+
use crate::error::BDKCliError as Error;
use serde::Serialize;
.map_err(|e| Error::Generic(format!("JSON serialization failed: {e}")))
}
- fn print(&self) -> Result<(), Error> {
+ fn write_out<W: Write>(&self, mut writer: W) -> Result<(), Error> {
let output = self.format()?;
- println!("{}", output);
- Ok(())
+
+ writeln!(writer, "{}", output)
+ .map_err(|e| Error::Generic(format!("Failed to write output: {e}")))
+ }
+}
+
+impl<T: Serialize> FormatOutput for T {}
+
+/// A generic wrapper for commands that return a list of items.
+#[derive(Serialize)]
+pub struct ListResult<T> {
+ pub count: usize,
+ pub items: Vec<T>,
+}
+
+impl<T> ListResult<T> {
+ pub fn new(items: Vec<T>) -> Self {
+ Self {
+ count: items.len(),
+ items,
+ }
}
}
use std::collections::HashMap;
use crate::config::WalletConfigInner;
-use crate::utils::output::FormatOutput;
use crate::utils::shorten;
use bdk_wallet::Balance;
use bdk_wallet::bitcoin::{
}
}
-impl FormatOutput for AddressResult {}
-
/// Represents the data for a single transaction
#[derive(Serialize)]
pub struct TransactionDetails {
pub total_value: u64,
}
-/// A wrapper type for a list of transactions.
-#[derive(Serialize)]
-#[serde(transparent)]
-pub struct TransactionListResult(pub Vec<TransactionDetails>);
-
-impl FormatOutput for TransactionListResult {}
-
/// single UTXO
#[derive(Serialize)]
pub struct UnspentDetails {
}
}
-/// Wrapper for the list of UTXOs
-#[derive(Serialize)]
-#[serde(transparent)]
-pub struct UnspentListResult(pub Vec<UnspentDetails>);
-
-impl FormatOutput for UnspentListResult {}
-
#[derive(Serialize)]
pub struct PsbtResult {
pub psbt: String,
}
}
-impl FormatOutput for PsbtResult {}
-
#[derive(Serialize)]
pub struct RawPsbt {
pub raw_tx: String,
}
}
-impl FormatOutput for RawPsbt {}
-
#[derive(Serialize)]
pub struct KeychainPair<T> {
pub external: T,
pub internal: T,
}
-impl FormatOutput for KeychainPair<String> {}
-
-// Table formatting for JSON value pairs (used by Policies)
-impl FormatOutput for KeychainPair<serde_json::Value> {}
-
#[derive(Serialize, Debug, Default)]
pub struct MessageResult {
#[serde(skip_serializing_if = "Option::is_none")]
pub proven_amount: Option<u64>,
}
-impl FormatOutput for MessageResult {}
-
#[derive(Serialize, Debug)]
pub struct StatusResult {
pub message: String,
}
}
-impl FormatOutput for StatusResult {}
-
#[derive(Serialize, Debug)]
pub struct TransactionResult {
pub txid: String,
}
-impl FormatOutput for TransactionResult {}
-
/// Return type definition
#[derive(Serialize)]
#[serde(transparent)]
pub struct WalletsListResult(pub HashMap<String, WalletConfigInner>);
-impl FormatOutput for WalletsListResult {}
-
/// return type
#[derive(Serialize)]
pub struct DescriptorResult {
pub fingerprint: Option<String>,
}
-impl FormatOutput for DescriptorResult {}
-
#[derive(Serialize)]
pub struct KeyResult {
pub xprv: String,
pub fingerprint: Option<String>,
}
-impl FormatOutput for KeyResult {}
-
/// Balance representation
#[derive(Serialize)]
pub struct BalanceResult {
}
}
}
-
-impl FormatOutput for BalanceResult {}