gateway_cli/
general_commands.rs

1use std::time::{Duration, UNIX_EPOCH};
2
3use clap::Subcommand;
4use fedimint_core::config::FederationId;
5use fedimint_core::fedimint_build_code_version_env;
6use fedimint_core::time::now;
7use fedimint_core::util::SafeUrl;
8use fedimint_eventlog::{EventKind, EventLogId};
9use fedimint_gateway_client::{
10    connect_federation, get_balances, get_info, get_invite_codes, get_mnemonic, leave_federation,
11    payment_log, payment_summary, stop,
12};
13use fedimint_gateway_common::{
14    ConnectFedPayload, LeaveFedPayload, PaymentLogPayload, PaymentSummaryPayload,
15};
16use fedimint_ln_common::client::GatewayApi;
17
18use crate::print_response;
19
20#[derive(Subcommand)]
21pub enum GeneralCommands {
22    /// Display the version hash of the CLI.
23    VersionHash,
24    /// Display high-level information about the gateway.
25    Info,
26    /// Get the total on-chain, lightning, and eCash balances of the gateway.
27    GetBalances,
28    /// Register the gateway with a federation.
29    ConnectFed {
30        /// Invite code to connect to the federation
31        invite_code: String,
32        /// Activate usage of Tor (or not) as the connector for the federation
33        /// client
34        #[cfg(feature = "tor")]
35        use_tor: Option<bool>,
36        /// Indicates if the client should be recovered from a mnemonic
37        #[clap(long)]
38        recover: Option<bool>,
39    },
40    /// Leave a federation.
41    LeaveFed {
42        #[clap(long)]
43        federation_id: FederationId,
44    },
45    /// Prints the seed phrase for the gateway
46    Seed,
47    /// Safely stop the gateway
48    Stop,
49    /// List the fedimint transactions that the gateway has processed
50    PaymentLog {
51        #[clap(long)]
52        end_position: Option<EventLogId>,
53
54        #[clap(long, default_value_t = 25)]
55        pagination_size: usize,
56
57        #[clap(long)]
58        federation_id: FederationId,
59
60        #[clap(long)]
61        event_kinds: Vec<EventKind>,
62    },
63    /// Create a bcrypt hash of a password, for use in gateway deployment
64    CreatePasswordHash {
65        password: String,
66
67        /// The bcrypt cost factor to use when hashing the password
68        #[clap(long)]
69        cost: Option<u32>,
70    },
71    /// List a payment summary for the last day
72    PaymentSummary {
73        #[clap(long)]
74        start: Option<u64>,
75
76        #[clap(long)]
77        end: Option<u64>,
78    },
79    /// List all invite codes of each federation the gateway has joined
80    InviteCodes,
81}
82
83impl GeneralCommands {
84    #[allow(clippy::too_many_lines)]
85    pub async fn handle(self, client: &GatewayApi, base_url: &SafeUrl) -> anyhow::Result<()> {
86        match self {
87            Self::VersionHash => {
88                println!("{}", fedimint_build_code_version_env!());
89            }
90            Self::Info => {
91                let response = get_info(client, base_url).await?;
92                print_response(response);
93            }
94            Self::GetBalances => {
95                let response = get_balances(client, base_url).await?;
96                print_response(response);
97            }
98            Self::ConnectFed {
99                invite_code,
100                #[cfg(feature = "tor")]
101                use_tor,
102                recover,
103            } => {
104                let response = connect_federation(
105                    client,
106                    base_url,
107                    ConnectFedPayload {
108                        invite_code,
109                        #[cfg(feature = "tor")]
110                        use_tor,
111                        #[cfg(not(feature = "tor"))]
112                        use_tor: None,
113                        recover,
114                    },
115                )
116                .await?;
117
118                print_response(response);
119            }
120            Self::LeaveFed { federation_id } => {
121                let response =
122                    leave_federation(client, base_url, LeaveFedPayload { federation_id }).await?;
123                print_response(response);
124            }
125            Self::Seed => {
126                let response = get_mnemonic(client, base_url).await?;
127                print_response(response);
128            }
129            Self::Stop => {
130                stop(client, base_url).await?;
131            }
132            Self::PaymentLog {
133                end_position,
134                pagination_size,
135                federation_id,
136                event_kinds,
137            } => {
138                let payment_log = payment_log(
139                    client,
140                    base_url,
141                    PaymentLogPayload {
142                        end_position,
143                        pagination_size,
144                        federation_id,
145                        event_kinds,
146                    },
147                )
148                .await?;
149                print_response(payment_log);
150            }
151            Self::CreatePasswordHash { password, cost } => print_response(
152                bcrypt::hash(password, cost.unwrap_or(bcrypt::DEFAULT_COST))
153                    .expect("Unable to create bcrypt hash"),
154            ),
155            Self::PaymentSummary { start, end } => {
156                let now = now();
157                let now_millis = now
158                    .duration_since(UNIX_EPOCH)
159                    .expect("Before unix epoch")
160                    .as_millis()
161                    .try_into()?;
162                let one_day_ago = now
163                    .checked_sub(Duration::from_secs(60 * 60 * 24))
164                    .expect("Before unix epoch");
165                let one_day_ago_millis = one_day_ago
166                    .duration_since(UNIX_EPOCH)
167                    .expect("Before unix epoch")
168                    .as_millis()
169                    .try_into()?;
170                let end_millis = end.unwrap_or(now_millis);
171                let start_millis = start.unwrap_or(one_day_ago_millis);
172                let payment_summary = payment_summary(
173                    client,
174                    base_url,
175                    PaymentSummaryPayload {
176                        start_millis,
177                        end_millis,
178                    },
179                )
180                .await?;
181                print_response(payment_summary);
182            }
183            Self::InviteCodes => {
184                let invite_codes = get_invite_codes(client, base_url).await?;
185                print_response(invite_codes);
186            }
187        }
188
189        Ok(())
190    }
191}