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    /// Lnurl subcommands
36    #[command(subcommand)]
37    Lnurl(LnurlOpts),
38    /// Gateway subcommands
39    #[command(subcommand)]
40    Gateways(GatewaysOpts),
41}
42
43#[derive(Clone, Subcommand, Serialize)]
44enum LnurlOpts {
45    /// Generate a new lnurl.
46    Generate {
47        recurringd: SafeUrl,
48        #[arg(long)]
49        gateway: Option<SafeUrl>,
50    },
51}
52
53#[derive(Clone, Subcommand, Serialize)]
54enum GatewaysOpts {
55    /// Update the mapping from lightning node public keys to gateway api
56    /// endpoints maintained in the module database to optimise gateway
57    /// selection for a given invoice; this command is intended for testing.
58    Map,
59    /// Select an online vetted gateway; this command is intended for testing.
60    Select {
61        #[arg(long)]
62        invoice: Option<Bolt11Invoice>,
63    },
64    /// List all vetted gateways.
65    List {
66        #[arg(long)]
67        peer: Option<PeerId>,
68    },
69    /// Add a vetted gateway.
70    Add { gateway: SafeUrl },
71    /// Remove a vetted gateway.
72    Remove { gateway: SafeUrl },
73}
74
75pub(crate) async fn handle_cli_command(
76    lightning: &LightningClientModule,
77    args: &[ffi::OsString],
78) -> anyhow::Result<serde_json::Value> {
79    let opts = Opts::parse_from(iter::once(&ffi::OsString::from("lnv2")).chain(args.iter()));
80
81    let value = match opts {
82        Opts::Send { gateway, invoice } => {
83            json(lightning.send(invoice, gateway, Value::Null).await?)
84        }
85        Opts::AwaitSend { operation_id } => json(
86            lightning
87                .await_final_send_operation_state(operation_id)
88                .await?,
89        ),
90        Opts::Receive { amount, gateway } => json(
91            lightning
92                .receive(
93                    amount,
94                    3600,
95                    Bolt11InvoiceDescription::Direct(String::new()),
96                    gateway,
97                    Value::Null,
98                )
99                .await?,
100        ),
101        Opts::AwaitReceive { operation_id } => json(
102            lightning
103                .await_final_receive_operation_state(operation_id)
104                .await?,
105        ),
106        Opts::Lnurl(lnurl_opts) => match lnurl_opts {
107            LnurlOpts::Generate {
108                recurringd,
109                gateway,
110            } => json(lightning.generate_lnurl(recurringd, gateway).await?),
111        },
112        Opts::Gateways(gateway_opts) => match gateway_opts {
113            #[allow(clippy::unit_arg)]
114            GatewaysOpts::Map => json(lightning.update_gateway_map().await),
115            GatewaysOpts::Select { invoice } => json(lightning.select_gateway(invoice).await?.0),
116            GatewaysOpts::List { peer } => match peer {
117                Some(peer) => json(lightning.module_api.gateways_from_peer(peer).await?),
118                None => json(lightning.module_api.gateways().await?),
119            },
120            GatewaysOpts::Add { gateway } => {
121                let auth = lightning
122                    .admin_auth
123                    .clone()
124                    .ok_or(anyhow::anyhow!("Admin auth not set"))?;
125
126                json(lightning.module_api.add_gateway(auth, gateway).await?)
127            }
128            GatewaysOpts::Remove { gateway } => {
129                let auth = lightning
130                    .admin_auth
131                    .clone()
132                    .ok_or(anyhow::anyhow!("Admin auth not set"))?;
133
134                json(lightning.module_api.remove_gateway(auth, gateway).await?)
135            }
136        },
137    };
138
139    Ok(value)
140}
141
142fn json<T: Serialize>(value: T) -> Value {
143    serde_json::to_value(value).expect("JSON serialization failed")
144}