fedimint_walletv2_client/
cli.rs1use std::{ffi, iter};
2
3use bitcoin::Address;
4use bitcoin::address::NetworkUnchecked;
5use clap::{Parser, Subcommand};
6use fedimint_api_client::api::FederationError;
7use fedimint_client_module::error::{ModuleLookupError, OperationLookupError};
8use fedimint_core::BitcoinAmountOrAll;
9use fedimint_eventlog::EventLogId;
10use serde::Serialize;
11use serde_json::Value;
12
13use crate::{AwaitReceiveError, ReceiveError, SendError, WalletClientModule};
14
15#[derive(Parser, Serialize)]
16enum Opts {
17 #[command(subcommand)]
19 Info(InfoOpts),
20 SendFee,
22 ReceiveFee,
24 Send {
26 address: Address<NetworkUnchecked>,
27 value: BitcoinAmountOrAll,
29 #[arg(long)]
30 fee: Option<bitcoin::Amount>,
31 },
32 Receive,
38 AwaitReceive {
42 position: EventLogId,
45 },
46}
47
48#[derive(Clone, Subcommand, Serialize)]
49enum InfoOpts {
50 TotalValue,
52 BlockCount,
54 Feerate,
56 PendingTxChain,
58 TxChain,
60}
61
62pub(crate) async fn handle_cli_command(
63 wallet: &WalletClientModule,
64 args: &[ffi::OsString],
65) -> Result<Value, CliCommandError> {
66 let opts = Opts::parse_from(iter::once(&ffi::OsString::from("walletv2")).chain(args.iter()));
67
68 let value = match opts {
69 Opts::Info(subcommand) => match subcommand {
70 InfoOpts::TotalValue => json(wallet.total_value().await?),
71 InfoOpts::BlockCount => json(wallet.block_count().await?),
72 InfoOpts::Feerate => json(wallet.feerate().await?),
73 InfoOpts::PendingTxChain => json(wallet.pending_tx_chain().await?),
74 InfoOpts::TxChain => json(wallet.tx_chain().await?),
75 },
76 Opts::SendFee => json(wallet.send_fee().await?),
77 Opts::ReceiveFee => json(wallet.receive_fee().await?),
78 Opts::Send {
79 address,
80 value,
81 fee,
82 } => {
83 let fee = match fee {
88 Some(fee) => fee,
89 None => wallet.send_fee().await?,
90 };
91
92 let value = match value {
93 BitcoinAmountOrAll::All => {
97 let balance = wallet.client_ctx.get_balance_for_btc().await?;
98 wallet.max_sendable_amount(balance, fee).await?
99 }
100 BitcoinAmountOrAll::Amount(value) => value,
101 };
102
103 json(
104 wallet
105 .await_final_send_operation_state(
106 wallet
107 .send(address, value, Some(fee), serde_json::Value::Null)
108 .await?,
109 )
110 .await?,
111 )
112 }
113 Opts::Receive => json(wallet.receive().await),
114 Opts::AwaitReceive { position } => json(wallet.await_receive(position).await?),
115 };
116
117 Ok(value)
118}
119
120fn json<T: Serialize>(value: T) -> Value {
121 serde_json::to_value(value).expect("JSON serialization failed")
122}
123
124#[derive(Debug, thiserror::Error)]
126pub(crate) enum CliCommandError {
127 #[error(transparent)]
129 Federation(#[from] FederationError),
130
131 #[error(transparent)]
133 Send(#[from] SendError),
134
135 #[error(transparent)]
137 Receive(#[from] ReceiveError),
138
139 #[error(transparent)]
141 Balance(#[from] ModuleLookupError),
142
143 #[error(transparent)]
145 OperationLookup(#[from] OperationLookupError),
146
147 #[error(transparent)]
149 AwaitReceive(#[from] AwaitReceiveError),
150}