Skip to main content

fedimint_cli/
command_encoding.rs

1use std::fs;
2use std::str::FromStr;
3
4use fedimint_core::base32::{self, FEDIMINT_PREFIX};
5use fedimint_core::config::FederationIdPrefix;
6use fedimint_core::db::DatabaseValue;
7use fedimint_core::invite_code::InviteCode;
8use fedimint_mint_client::OOBNotes;
9
10use crate::cli::{DecodeType, EncodeType, OOBNotesJson, Opts};
11use crate::{CliOutput, CliOutputResult, CliResultExt, FedimintCli};
12
13impl FedimintCli {
14    /// Decode local data, opening a client only for transaction module
15    /// decoders.
16    pub(super) async fn handle_decode(
17        &mut self,
18        cli: &Opts,
19        decode_type: DecodeType,
20    ) -> CliOutputResult {
21        match decode_type {
22            DecodeType::InviteCode { invite_code } => Ok(CliOutput::DecodeInviteCode {
23                url: invite_code.url(),
24                federation_id: invite_code.federation_id(),
25            }),
26            DecodeType::Notes { notes, file } => {
27                let notes = if let Some(notes) = notes {
28                    notes
29                } else if let Some(file) = file {
30                    let notes_str =
31                        fs::read_to_string(file).map_err_cli_msg("failed to read file")?;
32                    OOBNotes::from_str(&notes_str).map_err_cli_msg("failed to decode notes")?
33                } else {
34                    unreachable!("Clap enforces either notes or file being set");
35                };
36                let notes_json = notes
37                    .notes_json()
38                    .map_err_cli_msg("failed to decode notes")?;
39                Ok(CliOutput::Raw(notes_json))
40            }
41            DecodeType::Transaction { hex_string } => {
42                let bytes: Vec<u8> = hex::FromHex::from_hex(&hex_string)
43                    .map_err_cli_msg("failed to decode transaction")?;
44                let client = self.client_open(cli).await?;
45                let tx =
46                    fedimint_core::transaction::Transaction::from_bytes(&bytes, client.decoders())
47                        .map_err_cli_msg("failed to decode transaction")?;
48                Ok(CliOutput::DecodeTransaction {
49                    transaction: format!("{tx:?}"),
50                })
51            }
52            DecodeType::SetupCode { setup_code } => {
53                let setup_code = base32::decode_prefixed(FEDIMINT_PREFIX, &setup_code)
54                    .map_err_cli_msg("failed to decode setup code")?;
55                Ok(CliOutput::SetupCode { setup_code })
56            }
57        }
58    }
59}
60
61/// Encode portable client data without opening a database or network
62/// connection.
63pub(super) fn handle_encode(encode_type: EncodeType) -> CliOutputResult {
64    match encode_type {
65        EncodeType::InviteCode {
66            url,
67            federation_id,
68            peer,
69            api_secret,
70        } => Ok(CliOutput::InviteCode {
71            invite_code: InviteCode::new(url, peer, federation_id, api_secret),
72        }),
73        EncodeType::Notes { notes_json } => {
74            let notes = serde_json::from_str::<OOBNotesJson>(&notes_json)
75                .map_err_cli_msg("invalid JSON for notes")?;
76            let prefix = FederationIdPrefix::from_str(&notes.federation_id_prefix).map_err_cli()?;
77            let notes = OOBNotes::new(prefix, notes.notes);
78            Ok(CliOutput::Raw(notes.to_string().into()))
79        }
80    }
81}