Skip to main content

soroban_cli/commands/token/
args.rs

1use crate::{
2    commands::contract::invoke, config::token::ResolvedToken, get_spec, output::Format, rpc,
3};
4
5/// Output format shared by the `stellar token` subcommands.
6#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, clap::ValueEnum, Default)]
7pub enum OutputFormat {
8    /// Human-readable text.
9    #[default]
10    Text,
11    /// Compact, single-line JSON receipt.
12    Json,
13    /// Formatted (multiline) JSON receipt.
14    JsonFormatted,
15}
16
17impl From<OutputFormat> for Format {
18    fn from(value: OutputFormat) -> Self {
19        match value {
20            OutputFormat::Text => Format::Readable,
21            OutputFormat::Json => Format::Json,
22            OutputFormat::JsonFormatted => Format::JsonFormatted,
23        }
24    }
25}
26
27#[derive(thiserror::Error, Debug)]
28pub enum Error {
29    #[error(
30        "the Stellar Asset Contract {0} is not deployed on this network.\n\
31         Deploy it first with `stellar contract asset deploy --asset <ASSET>`, then retry."
32    )]
33    SacNotDeployed(String),
34
35    #[error("contract {0} was not found on this network")]
36    ContractNotFound(String),
37}
38
39impl Error {
40    /// Machine-readable discriminator for the JSON error envelope's `type` field.
41    #[must_use]
42    pub fn error_type(&self) -> &'static str {
43        match self {
44            Error::SacNotDeployed(_) => "sac_not_deployed",
45            Error::ContractNotFound(_) => "contract_not_found",
46        }
47    }
48}
49
50/// If `err` is a "contract not found" failure raised while fetching the contract
51/// spec, translate it into a token-aware error keyed off what `token` resolved
52/// to: a missing SAC (pointing at `contract asset deploy`), or a missing
53/// contract for a direct id/alias. Returns `None` for any other failure so the
54/// caller can surface the underlying invoke error unchanged.
55#[must_use]
56pub fn not_deployed_error(token: &ResolvedToken, err: &invoke::Error) -> Option<Error> {
57    let invoke::Error::GetSpecError(get_spec::Error::Rpc(rpc::Error::NotFound(kind, _))) = err
58    else {
59        return None;
60    };
61    if kind != "Contract" {
62        return None;
63    }
64    let contract_id = token.contract_id;
65    Some(if token.is_sac() {
66        Error::SacNotDeployed(format!("{contract_id}"))
67    } else {
68        Error::ContractNotFound(format!("{contract_id}"))
69    })
70}