fedimint_wallet_client/
cli.rs1use std::str::FromStr as _;
2use std::{ffi, iter};
3
4use anyhow::bail;
5use bitcoin::address::NetworkUnchecked;
6use clap::Parser;
7use fedimint_core::core::OperationId;
8use serde::Serialize;
9
10use super::WalletClientModule;
11use crate::api::WalletFederationApi;
12use crate::client_db::TweakIdx;
13
14#[derive(Parser, Serialize)]
15enum Opts {
16 AwaitDeposit {
18 addr: Option<String>,
19 #[arg(long)]
20 operation_id: Option<OperationId>,
21 #[arg(long)]
22 tweak_idx: Option<TweakIdx>,
23 #[arg(long, default_value = "1")]
25 num: usize,
26 },
27 GetConsensusBlockCount,
28 GetBitcoinRpcKind {
30 peer_id: u16,
31 },
32 GetBitcoinRpcConfig,
34
35 NewDepositAddress,
36 RecheckDepositAddress {
38 addr: Option<bitcoin::Address<NetworkUnchecked>>,
39 #[arg(long)]
40 operation_id: Option<OperationId>,
41 #[arg(long)]
42 tweak_idx: Option<TweakIdx>,
43 },
44}
45
46pub(crate) async fn handle_cli_command(
47 module: &WalletClientModule,
48 args: &[ffi::OsString],
49) -> anyhow::Result<serde_json::Value> {
50 let opts = Opts::parse_from(iter::once(&ffi::OsString::from("wallet")).chain(args.iter()));
51
52 let res = match opts {
53 Opts::AwaitDeposit {
54 operation_id,
55 num,
56 addr,
57 tweak_idx,
58 } => {
59 if u32::from(addr.is_some())
60 + u32::from(operation_id.is_some())
61 + u32::from(tweak_idx.is_some())
62 != 1
63 {
64 bail!("One and only one of the selector arguments must be set")
65 }
66 if let Some(tweak_idx) = tweak_idx {
67 module.await_num_deposits(tweak_idx, num).await?;
68 } else if let Some(operation_id) = operation_id {
69 module
70 .await_num_deposits_by_operation_id(operation_id, num)
71 .await?;
72 } else if let Some(addr) = addr {
73 if addr.len() == 64 {
74 eprintln!(
75 "Interpreting addr as an operation_id for backward compatibility. Use `--operation-id` from now on."
76 );
77 let operation_id = OperationId::from_str(&addr)?;
78 module
79 .await_num_deposits_by_operation_id(operation_id, num)
80 .await?;
81 } else {
82 let addr = bitcoin::Address::from_str(&addr)?;
83 module.await_num_deposits_by_address(addr, num).await?;
84 }
85 } else {
86 unreachable!()
87 }
88 serde_json::Value::Bool(true)
89 }
90 Opts::GetBitcoinRpcKind { peer_id } => {
91 let kind = module
92 .module_api
93 .fetch_bitcoin_rpc_kind(peer_id.into())
94 .await?;
95
96 serde_json::to_value(kind).expect("JSON serialization failed")
97 }
98 Opts::GetBitcoinRpcConfig => {
99 let auth = module
100 .admin_auth
101 .clone()
102 .ok_or(anyhow::anyhow!("Admin auth not set"))?;
103
104 serde_json::to_value(module.module_api.fetch_bitcoin_rpc_config(auth).await?)
105 .expect("JSON serialization failed")
106 }
107 Opts::GetConsensusBlockCount => {
108 serde_json::to_value(module.module_api.fetch_consensus_block_count().await?)
109 .expect("JSON serialization failed")
110 }
111 Opts::RecheckDepositAddress {
112 addr,
113 operation_id,
114 tweak_idx,
115 } => {
116 if u32::from(addr.is_some())
117 + u32::from(operation_id.is_some())
118 + u32::from(tweak_idx.is_some())
119 != 1
120 {
121 bail!("One and only one of the selector arguments must be set")
122 }
123 if let Some(tweak_idx) = tweak_idx {
124 module.recheck_pegin_address(tweak_idx).await?;
125 } else if let Some(operation_id) = operation_id {
126 module.recheck_pegin_address_by_op_id(operation_id).await?;
127 } else if let Some(addr) = addr {
128 module.recheck_pegin_address_by_address(addr).await?;
129 } else {
130 unreachable!()
131 }
132 serde_json::Value::Bool(true)
133 }
134 Opts::NewDepositAddress => {
135 let (operation_id, address, tweak_idx) =
136 module.allocate_deposit_address_expert_only(()).await?;
137 serde_json::json! {
138 {
139 "address": address,
140 "operation_id": operation_id,
141 "tweak_idx": tweak_idx.0
142 }
143 }
144 }
145 };
146
147 Ok(res)
148}