fedimint_lnv2_client/
cli.rs

1use std::{ffi, iter};
2
3use clap::{Parser, Subcommand};
4use fedimint_core::core::OperationId;
5use fedimint_core::util::SafeUrl;
6use fedimint_core::{Amount, PeerId};
7use lightning_invoice::Bolt11Invoice;
8use serde::Serialize;
9use serde_json::Value;
10
11use crate::api::LightningFederationApi;
12use crate::{Bolt11InvoiceDescription, LightningClientModule};
13
14#[derive(Parser, Serialize)]
15enum Opts {
16    /// Pay an invoice. For  testing  you can optionally specify a gateway to
17    /// route with, otherwise a gateway will be selected automatically.
18    Send {
19        invoice: Bolt11Invoice,
20        #[arg(long)]
21        gateway: Option<SafeUrl>,
22    },
23    /// Await the final state of the send operation.
24    AwaitSend { operation_id: OperationId },
25    /// Request an invoice. For testing you can optionally specify a gateway to
26    /// generate the invoice, otherwise a gateway will be selected
27    /// automatically.
28    Receive {
29        amount: Amount,
30        #[arg(long)]
31        gateway: Option<SafeUrl>,
32    },
33    /// Await the final state of the receive operation.
34    AwaitReceive { operation_id: OperationId },
35    /// Gateway subcommands
36    #[command(subcommand)]
37    Gateways(GatewaysOpts),
38}
39
40#[derive(Clone, Subcommand, Serialize)]
41enum GatewaysOpts {
42    /// Update the mapping from lightning node public keys to gateway api
43    /// endpoints maintained in the module database to optimise gateway
44    /// selection for a given invoice; this command is intended for testing.
45    Map,
46    /// Select an online vetted gateway; this command is intended for testing.
47    Select {
48        #[arg(long)]
49        invoice: Option<Bolt11Invoice>,
50    },
51    /// List all vetted gateways.
52    List {
53        #[arg(long)]
54        peer: Option<PeerId>,
55    },
56    /// Add a vetted gateway.
57    Add { gateway: SafeUrl },
58    /// Remove a vetted gateway.
59    Remove { gateway: SafeUrl },
60}
61
62pub(crate) async fn handle_cli_command(
63    lightning: &LightningClientModule,
64    args: &[ffi::OsString],
65) -> anyhow::Result<serde_json::Value> {
66    let opts = Opts::parse_from(iter::once(&ffi::OsString::from("lnv2")).chain(args.iter()));
67
68    let value = match opts {
69        Opts::Send { gateway, invoice } => {
70            json(lightning.send(invoice, gateway, Value::Null).await?)
71        }
72        Opts::AwaitSend { operation_id } => json(
73            lightning
74                .await_final_send_operation_state(operation_id)
75                .await?,
76        ),
77        Opts::Receive { amount, gateway } => json(
78            lightning
79                .receive(
80                    amount,
81                    3600,
82                    Bolt11InvoiceDescription::Direct(String::new()),
83                    gateway,
84                    Value::Null,
85                )
86                .await?,
87        ),
88        Opts::AwaitReceive { operation_id } => json(
89            lightning
90                .await_final_receive_operation_state(operation_id)
91                .await?,
92        ),
93        Opts::Gateways(gateway_opts) => match gateway_opts {
94            #[allow(clippy::unit_arg)]
95            GatewaysOpts::Map => json(
96                LightningClientModule::update_gateway_map(
97                    &lightning.federation_id,
98                    &lightning.client_ctx,
99                    &lightning.module_api,
100                    &lightning.gateway_conn,
101                )
102                .await,
103            ),
104            GatewaysOpts::Select { invoice } => json(lightning.select_gateway(invoice).await?.0),
105            GatewaysOpts::List { peer } => match peer {
106                Some(peer) => json(lightning.module_api.gateways_from_peer(peer).await?),
107                None => json(lightning.module_api.gateways().await?),
108            },
109            GatewaysOpts::Add { gateway } => {
110                let auth = lightning
111                    .admin_auth
112                    .clone()
113                    .ok_or(anyhow::anyhow!("Admin auth not set"))?;
114
115                json(lightning.module_api.add_gateway(auth, gateway).await?)
116            }
117            GatewaysOpts::Remove { gateway } => {
118                let auth = lightning
119                    .admin_auth
120                    .clone()
121                    .ok_or(anyhow::anyhow!("Admin auth not set"))?;
122
123                json(lightning.module_api.remove_gateway(auth, gateway).await?)
124            }
125        },
126    };
127
128    Ok(value)
129}
130
131fn json<T: Serialize>(value: T) -> Value {
132    serde_json::to_value(value).expect("JSON serialization failed")
133}