1use std::path::PathBuf;
2
3use clap::{Args, Parser, Subcommand};
4use fedimint_core::config::FederationId;
5use fedimint_core::core::OperationId;
6use fedimint_core::invite_code::InviteCode;
7use fedimint_core::util::SafeUrl;
8use fedimint_core::{Amount, PeerId, TieredMulti};
9use fedimint_eventlog::EventLogId;
10use fedimint_mint_client::{OOBNotes, SpendableNote};
11use serde::{Deserialize, Serialize};
12
13use crate::client::{ClientCmd, ModuleSelector};
14#[cfg(feature = "tor")]
15use crate::envs::FM_USE_TOR_ENV;
16use crate::envs::{
17 FM_API_SECRET_ENV, FM_CLIENT_DIR_ENV, FM_DB_BACKEND_ENV, FM_FEDERATION_SECRET_HEX_ENV,
18 FM_IROH_ENABLE_DHT_ENV, FM_IROH_ENABLE_NEXT_ENV, FM_OUR_ID_ENV, FM_PASSWORD_ENV,
19};
20use crate::utils::parse_peer_id;
21
22#[derive(Debug, Clone, Copy, clap::ValueEnum)]
23pub(crate) enum DatabaseBackend {
24 #[value(name = "rocksdb")]
26 RocksDb,
27 #[value(name = "cursed-redb")]
29 CursedRedb,
30}
31
32#[derive(Parser, Clone)]
33#[command(version)]
34pub(crate) struct Opts {
35 #[arg(long = "data-dir", env = FM_CLIENT_DIR_ENV)]
37 pub data_dir: Option<PathBuf>,
38
39 #[arg(env = FM_OUR_ID_ENV, long, value_parser = parse_peer_id)]
41 pub our_id: Option<PeerId>,
42
43 #[arg(long, env = FM_PASSWORD_ENV)]
45 pub password: Option<String>,
46
47 #[arg(long, env = FM_FEDERATION_SECRET_HEX_ENV)]
49 pub federation_secret_hex: Option<String>,
50
51 #[cfg(feature = "tor")]
52 #[arg(long, env = FM_USE_TOR_ENV)]
54 pub use_tor: bool,
55
56 #[arg(long, env = FM_IROH_ENABLE_DHT_ENV)]
58 pub iroh_enable_dht: Option<bool>,
59
60 #[arg(long, env = FM_IROH_ENABLE_NEXT_ENV)]
62 pub iroh_enable_next: Option<bool>,
63
64 #[arg(long, env = FM_DB_BACKEND_ENV, value_enum, default_value = "rocksdb")]
66 pub db_backend: DatabaseBackend,
67
68 #[arg(short = 'v', long)]
71 pub verbose: bool,
72
73 #[clap(subcommand)]
74 pub command: Command,
75}
76
77#[derive(Subcommand, Clone)]
78pub(crate) enum Command {
79 VersionHash,
81
82 #[clap(flatten)]
83 Client(ClientCmd),
84
85 #[clap(subcommand)]
86 Admin(AdminCmd),
87
88 #[clap(subcommand)]
89 Dev(DevCmd),
90
91 InviteCode {
93 peer: PeerId,
94 },
95
96 #[clap(alias = "join-federation")]
98 Join {
99 invite_code: String,
100 },
101
102 Completion {
103 shell: clap_complete::Shell,
104 },
105}
106
107#[allow(clippy::large_enum_variant)]
108#[derive(Debug, Clone, Subcommand)]
109pub(crate) enum AdminCmd {
110 Auth {
118 #[arg(long, env = FM_OUR_ID_ENV)]
120 peer_id: u16,
121 #[arg(long, env = FM_PASSWORD_ENV)]
123 password: String,
124 #[arg(long)]
126 no_verify: bool,
127 #[arg(long)]
129 force: bool,
130 },
131
132 Status,
134
135 Audit,
137
138 GuardianConfigBackup,
140
141 Setup(SetupAdminArgs),
142 SignApiAnnouncement {
145 api_url: SafeUrl,
147 #[clap(long)]
150 override_url: Option<SafeUrl>,
151 },
152 SignGuardianMetadata {
154 #[clap(long, value_delimiter = ',')]
156 api_urls: Vec<SafeUrl>,
157 #[clap(long)]
159 pkarr_id: String,
160 },
161 Shutdown {
163 session_idx: u64,
165 },
166 BackupStatistics,
168 ChangePassword {
171 new_password: String,
173 },
174}
175
176#[derive(Debug, Clone, Args)]
177pub(crate) struct SetupAdminArgs {
178 pub endpoint: SafeUrl,
179
180 #[clap(subcommand)]
181 pub subcommand: SetupAdminCmd,
182}
183
184#[derive(Debug, Clone, Subcommand)]
185pub(crate) enum SetupAdminCmd {
186 Status,
187 SetLocalParams {
188 name: String,
189 #[clap(long)]
190 federation_name: Option<String>,
191 #[clap(long)]
192 federation_size: Option<u32>,
193 },
194 AddPeer {
195 info: String,
196 },
197 StartDkg,
198}
199
200#[derive(Debug, Clone, Subcommand)]
201pub(crate) enum DecodeType {
202 InviteCode { invite_code: InviteCode },
204 #[group(required = true, multiple = false)]
206 Notes {
207 notes: Option<OOBNotes>,
209 #[arg(long)]
211 file: Option<PathBuf>,
212 },
213 Transaction { hex_string: String },
215 SetupCode { setup_code: String },
218}
219
220#[derive(Debug, Clone, Deserialize, Serialize)]
221pub(crate) struct OOBNotesJson {
222 pub federation_id_prefix: String,
223 pub notes: TieredMulti<SpendableNote>,
224}
225
226#[derive(Debug, Clone, Subcommand)]
227pub(crate) enum EncodeType {
228 InviteCode {
230 #[clap(long)]
231 url: SafeUrl,
232 #[clap(long = "federation_id")]
233 federation_id: FederationId,
234 #[clap(long = "peer")]
235 peer: PeerId,
236 #[arg(env = FM_API_SECRET_ENV)]
237 api_secret: Option<String>,
238 },
239
240 Notes { notes_json: String },
242}
243
244#[derive(Debug, Clone, Subcommand)]
245pub(crate) enum DevCmd {
246 #[command(after_long_help = r#"
250Examples:
251
252 fedimint-cli dev api --peer-id 0 config '"fed114znk7uk7ppugdjuytr8venqf2tkywd65cqvg3u93um64tu5cw4yr0n3fvn7qmwvm4g48cpndgnm4gqq4waen5te0xyerwt3s9cczuvf6xyurzde597s7crdvsk2vmyarjw9gwyqjdzj"'
253 "#)]
254 Api {
255 method: String,
257 #[clap(default_value = "null")]
262 params: String,
263 #[clap(long = "peer-id")]
265 peer_id: Option<u16>,
266
267 #[clap(long = "module")]
269 module: Option<ModuleSelector>,
270
271 #[clap(long, requires = "peer_id")]
274 password: Option<String>,
275 },
276
277 ApiAnnouncements,
278
279 GuardianMetadata,
280
281 AdvanceNoteIdx {
283 #[clap(long, default_value = "1")]
284 count: usize,
285
286 #[clap(long)]
287 amount: Amount,
288 },
289
290 WaitBlockCount {
292 count: u64,
293 },
294
295 Wait {
297 seconds: Option<f32>,
299 },
300
301 WaitComplete,
303
304 Decode {
306 #[clap(subcommand)]
307 decode_type: DecodeType,
308 },
309
310 Encode {
312 #[clap(subcommand)]
313 encode_type: EncodeType,
314 },
315
316 SessionCount,
318
319 Config,
321
322 ConfigDecrypt {
323 #[arg(long = "in-file")]
325 in_file: PathBuf,
326 #[arg(long = "out-file")]
328 out_file: PathBuf,
329 #[arg(long = "salt-file")]
332 salt_file: Option<PathBuf>,
333 #[arg(env = FM_PASSWORD_ENV)]
335 password: String,
336 },
337
338 ConfigEncrypt {
339 #[arg(long = "in-file")]
341 in_file: PathBuf,
342 #[arg(long = "out-file")]
344 out_file: PathBuf,
345 #[arg(long = "salt-file")]
348 salt_file: Option<PathBuf>,
349 #[arg(env = FM_PASSWORD_ENV)]
351 password: String,
352 },
353
354 ListOperationStates {
357 operation_id: OperationId,
358 },
359 MetaFields,
363 PeerVersion {
365 #[clap(long)]
366 peer_id: u16,
367 },
368 ShowEventLog {
370 #[arg(long)]
371 pos: Option<EventLogId>,
372 #[arg(long, default_value = "10")]
373 limit: u64,
374 },
375 ShowEventLogTrimable {
377 #[arg(long)]
378 pos: Option<EventLogId>,
379 #[arg(long, default_value = "10")]
380 limit: u64,
381 },
382 TestEventLogHandling,
385 SubmitTransaction {
390 transaction: String,
392 },
393 ChainId,
396}