Skip to main content

fedimint_walletv2_client/
cli.rs

1use std::{ffi, iter};
2
3use bitcoin::Address;
4use bitcoin::address::NetworkUnchecked;
5use clap::{Parser, Subcommand};
6use fedimint_eventlog::EventLogId;
7use serde::Serialize;
8use serde_json::Value;
9
10use crate::WalletClientModule;
11
12#[derive(Parser, Serialize)]
13enum Opts {
14    /// Subcommands for operator to retrieve information about the wallet state.
15    #[command(subcommand)]
16    Info(InfoOpts),
17    /// Fetch the current fee required to send an onchain payment.
18    SendFee,
19    /// Fetch the current fee required to claim an onchain deposit (peg-in).
20    ReceiveFee,
21    /// Send an onchain payment.
22    Send {
23        address: Address<NetworkUnchecked>,
24        value: bitcoin::Amount,
25        #[arg(long)]
26        fee: Option<bitcoin::Amount>,
27    },
28    /// Return the next unused receive address.
29    ///
30    /// To wait for a payment to this address, read the current event log
31    /// position with `dev next-event-log-id` *before* running this, then pass
32    /// that position to `await-receive`.
33    Receive,
34    /// Block until the next payment is received, starting from the given event
35    /// log position. Returns the receive's final state and the event log
36    /// position to pass to the following `await-receive`.
37    AwaitReceive {
38        /// Event log position to start scanning from, as returned by
39        /// `dev next-event-log-id` or a prior `await-receive`.
40        position: EventLogId,
41    },
42}
43
44#[derive(Clone, Subcommand, Serialize)]
45enum InfoOpts {
46    /// Fetch the total value of bitcoin controlled by the federation.
47    TotalValue,
48    /// Fetch the consensus block count of the federation.
49    BlockCount,
50    /// Fetch the current consensus feerate.
51    Feerate,
52    /// Display the chain of pending bitcoin transactions.
53    PendingTxChain,
54    /// Display the chain of bitcoin transactions.
55    TxChain,
56}
57
58pub(crate) async fn handle_cli_command(
59    wallet: &WalletClientModule,
60    args: &[ffi::OsString],
61) -> anyhow::Result<Value> {
62    let opts = Opts::parse_from(iter::once(&ffi::OsString::from("walletv2")).chain(args.iter()));
63
64    let value = match opts {
65        Opts::Info(subcommand) => match subcommand {
66            InfoOpts::TotalValue => json(wallet.total_value().await?),
67            InfoOpts::BlockCount => json(wallet.block_count().await?),
68            InfoOpts::Feerate => json(wallet.feerate().await?),
69            InfoOpts::PendingTxChain => json(wallet.pending_tx_chain().await?),
70            InfoOpts::TxChain => json(wallet.tx_chain().await?),
71        },
72        Opts::SendFee => json(wallet.send_fee().await?),
73        Opts::ReceiveFee => json(wallet.receive_fee().await?),
74        Opts::Send {
75            address,
76            value,
77            fee,
78        } => json(
79            wallet
80                .await_final_send_operation_state(
81                    wallet
82                        .send(address, value, fee, serde_json::Value::Null)
83                        .await?,
84                )
85                .await?,
86        ),
87        Opts::Receive => json(wallet.receive().await),
88        Opts::AwaitReceive { position } => json(wallet.await_receive(position).await?),
89    };
90
91    Ok(value)
92}
93
94fn json<T: Serialize>(value: T) -> Value {
95    serde_json::to_value(value).expect("JSON serialization failed")
96}