Skip to main content

soroban_cli/commands/contract/info/
meta.rs

1use std::fmt::Debug;
2use std::fmt::Write;
3
4use crate::commands::contract::info::meta::Error::{NoMetaPresent, NoSACMeta};
5use crate::commands::contract::info::shared::{self, fetch, Fetched, MetasInfoOutput};
6use crate::commands::global;
7use crate::print::Print;
8use clap::Parser;
9use soroban_spec_tools::contract;
10use soroban_spec_tools::contract::Spec;
11use soroban_spec_tools::sanitize;
12use stellar_xdr::curr::{ScMetaEntry, ScMetaV0};
13
14#[derive(Parser, Debug, Clone)]
15pub struct Cmd {
16    #[command(flatten)]
17    pub common: shared::Args,
18    /// Format of the output
19    #[arg(long, default_value = "text")]
20    pub output: MetasInfoOutput,
21}
22
23#[derive(thiserror::Error, Debug)]
24pub enum Error {
25    #[error(transparent)]
26    Wasm(#[from] shared::Error),
27    #[error(transparent)]
28    Spec(#[from] contract::Error),
29    #[error("Stellar asset contract doesn't contain meta information")]
30    NoSACMeta(),
31    #[error("no meta present in provided WASM file")]
32    NoMetaPresent(),
33    #[error(transparent)]
34    Json(#[from] serde_json::Error),
35}
36
37impl Cmd {
38    pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> {
39        let print = Print::new(global_args.quiet);
40        let Fetched { contract, .. } = fetch(&self.common, &print).await?;
41
42        let spec = match contract {
43            shared::Contract::Wasm { wasm_bytes } => Spec::new(&wasm_bytes)?,
44            shared::Contract::StellarAssetContract => return Err(NoSACMeta()),
45        };
46
47        let Some(meta_base64) = spec.meta_base64 else {
48            return Err(NoMetaPresent());
49        };
50
51        let res = match self.output {
52            MetasInfoOutput::XdrBase64 => meta_base64,
53            MetasInfoOutput::Json => serde_json::to_string(&spec.meta)?,
54            MetasInfoOutput::JsonFormatted => serde_json::to_string_pretty(&spec.meta)?,
55            MetasInfoOutput::Text => {
56                let mut meta_str = "Contract meta:\n".to_string();
57
58                for meta_entry in &spec.meta {
59                    match meta_entry {
60                        ScMetaEntry::ScMetaV0(ScMetaV0 { key, val }) => {
61                            let key = sanitize(&key.to_utf8_string_lossy());
62                            let val = match key.as_str() {
63                                "rsver" => format!(
64                                    "{} (Rust version)",
65                                    sanitize(&val.to_utf8_string_lossy())
66                                ),
67                                "rssdkver" => format!(
68                                    "{} (Soroban SDK version and its commit hash)",
69                                    sanitize(&val.to_utf8_string_lossy())
70                                ),
71                                _ => sanitize(&val.to_utf8_string_lossy()),
72                            };
73                            let _ = writeln!(meta_str, " • {key}: {val}");
74                        }
75                    }
76                }
77
78                meta_str
79            }
80        };
81
82        println!("{res}");
83
84        Ok(())
85    }
86}