Skip to main content

soroban_cli/commands/
mod.rs

1use std::str::FromStr;
2
3use clap::{error::ErrorKind, CommandFactory, FromArgMatches, Parser};
4
5use crate::config;
6
7pub mod cache;
8pub mod cfg;
9pub mod completion;
10pub mod container;
11pub mod contract;
12pub mod doctor;
13pub mod env;
14pub mod events;
15pub mod fee_stats;
16pub mod fees;
17pub mod global;
18pub mod keys;
19pub mod ledger;
20pub mod message;
21pub mod network;
22pub mod plugin;
23pub mod snapshot;
24pub mod token;
25pub mod tx;
26pub mod version;
27
28pub mod txn_result;
29
30pub const HEADING_RPC: &str = "RPC Options";
31pub const HEADING_ARCHIVE: &str = "Archive Options";
32pub const HEADING_GLOBAL: &str = "Global Options";
33pub const HEADING_SIGNING: &str = "Signing Options";
34pub const HEADING_TRANSACTION: &str = "Transaction Options";
35pub const HEADING_CONTAINER: &str = "Container Options";
36const ABOUT: &str =
37    "Work seamlessly with Stellar accounts, contracts, and assets from the command line.
38
39- Generate and manage keys and accounts
40- Build, deploy, and interact with contracts
41- Deploy asset contracts
42- Stream events
43- Start local testnets
44- Decode, encode XDR
45- More!
46
47For additional information see:
48
49- Stellar Docs: https://developers.stellar.org
50- Smart Contract Docs: https://developers.stellar.org/docs/build/smart-contracts/overview
51- CLI Docs: https://developers.stellar.org/docs/tools/developer-tools/cli/stellar-cli";
52
53// long_about is shown when someone uses `--help`; short help when using `-h`
54const LONG_ABOUT: &str = "
55
56To get started generate a new identity:
57
58    stellar keys generate alice
59
60Use keys with the `--source` flag in other commands.
61
62Commands that work with contracts are organized under the `contract` subcommand. List them:
63
64    stellar contract --help
65
66Use contracts like a CLI:
67
68    stellar contract invoke --id CCR6QKTWZQYW6YUJ7UP7XXZRLWQPFRV6SWBLQS4ZQOSAF4BOUD77OTE2 --source alice --network testnet -- --help
69
70Anything after the `--` double dash (the \"slop\") is parsed as arguments to the contract-specific CLI, generated on-the-fly from the contract schema. For the hello world example, with a function called `hello` that takes one string argument `to`, here's how you invoke it:
71
72    stellar contract invoke --id CCR6QKTWZQYW6YUJ7UP7XXZRLWQPFRV6SWBLQS4ZQOSAF4BOUD77OTE2 --source alice --network testnet -- hello --to world
73";
74
75#[derive(Parser, Debug)]
76#[command(
77    name = "stellar",
78    about = ABOUT,
79    version = version::long(),
80    long_about = ABOUT.to_string() + LONG_ABOUT,
81    disable_help_subcommand = true,
82)]
83pub struct Root {
84    #[clap(flatten)]
85    pub global_args: global::Args,
86
87    #[command(subcommand)]
88    pub cmd: Cmd,
89}
90
91impl Root {
92    pub fn new() -> Result<Self, Error> {
93        Self::try_parse().map_err(|e| match e.kind() {
94            ErrorKind::InvalidSubcommand => match plugin::default::run() {
95                Ok(()) => Error::Clap(e),
96                Err(e) => Error::PluginDefault(e),
97            },
98            _ => Error::Clap(e),
99        })
100    }
101
102    pub fn from_arg_matches<I, T>(itr: I) -> Result<Self, clap::Error>
103    where
104        I: IntoIterator<Item = T>,
105        T: Into<std::ffi::OsString> + Clone,
106    {
107        Self::from_arg_matches_mut(&mut Self::command().get_matches_from(itr))
108    }
109
110    pub async fn run(&mut self) -> Result<(), Error> {
111        match &mut self.cmd {
112            Cmd::Completion(completion) => completion.run(),
113            Cmd::Plugin(plugin) => plugin.run(&self.global_args).await?,
114            Cmd::Contract(contract) => contract.run(&self.global_args).await?,
115            Cmd::Doctor(doctor) => doctor.run(&self.global_args).await?,
116            Cmd::Config(config) => config.run()?,
117            Cmd::Events(events) => events.run().await?,
118            Cmd::Xdr(xdr) => xdr.run()?,
119            Cmd::Strkey(strkey) => strkey.run()?,
120            Cmd::Network(network) => network.run(&self.global_args).await?,
121            Cmd::Container(container) => container.run(&self.global_args).await?,
122            Cmd::Snapshot(snapshot) => snapshot.run(&self.global_args).await?,
123            Cmd::Version(version) => version.run(),
124            Cmd::Keys(id) => id.run(&self.global_args).await?,
125            Cmd::Token(token) => token.run(&self.global_args).await?,
126            Cmd::Tx(tx) => tx.run(&self.global_args).await?,
127            Cmd::Ledger(ledger) => ledger.run(&self.global_args).await?,
128            Cmd::Message(message) => message.run(&self.global_args).await?,
129            Cmd::Cache(cache) => cache.run()?,
130            Cmd::Env(env) => env.run(&self.global_args)?,
131            Cmd::Fees(env) => env.run(&self.global_args).await?,
132            Cmd::FeeStats(env) => env.run(&self.global_args).await?,
133        }
134        Ok(())
135    }
136}
137
138impl FromStr for Root {
139    type Err = clap::Error;
140
141    fn from_str(s: &str) -> Result<Self, Self::Err> {
142        Self::from_arg_matches(s.split_whitespace())
143    }
144}
145
146#[derive(Parser, Debug)]
147pub enum Cmd {
148    /// Tools for smart contract developers
149    #[command(subcommand)]
150    Contract(contract::Cmd),
151
152    /// Diagnose and troubleshoot CLI and network issues
153    Doctor(doctor::Cmd),
154
155    /// Watch the network for contract events
156    Events(events::Cmd),
157
158    /// Prints the environment variables
159    ///
160    /// Prints to stdout in a format that can be used as .env file. Environment
161    /// variables have precedence over defaults.
162    ///
163    /// By default, secret values are concealed. To display them, use `--reveal`.
164    ///
165    /// Pass a name to get the value of a single environment variable. Its value is printed without
166    /// shell quoting (control characters are neutralized), suitable for command substitution.
167    /// Concealed variables print nothing unless `--reveal` is passed.
168    ///
169    /// If there are no environment variables in use, prints the defaults.
170    Env(env::Cmd),
171
172    /// Create and manage identities including keys and addresses
173    #[command(subcommand)]
174    Keys(keys::Cmd),
175
176    /// Configure connection to networks
177    #[command(subcommand)]
178    Network(network::Cmd),
179
180    /// Start local networks in containers
181    #[command(subcommand)]
182    Container(container::Cmd),
183
184    /// Manage CLI configuration
185    #[command(subcommand)]
186    Config(cfg::Cmd),
187
188    /// Download a snapshot of a ledger from an archive.
189    #[command(subcommand)]
190    Snapshot(snapshot::Cmd),
191
192    /// Interact with SEP-41 tokens and Stellar Asset Contracts
193    #[command(subcommand)]
194    Token(token::Cmd),
195
196    /// Sign, Simulate, and Send transactions
197    #[command(subcommand)]
198    Tx(tx::Cmd),
199
200    /// Decode and encode XDR
201    Xdr(stellar_xdr::cli::Root),
202
203    /// Decode and encode strkey
204    Strkey(stellar_strkey::cli::Root),
205
206    /// Print shell completion code for the specified shell.
207    #[command(long_about = completion::LONG_ABOUT)]
208    Completion(completion::Cmd),
209
210    /// Cache for transactions and contract specs
211    #[command(subcommand)]
212    Cache(cache::Cmd),
213
214    /// Print version information
215    Version(version::Cmd),
216
217    /// The subcommand for CLI plugins
218    #[command(subcommand)]
219    Plugin(plugin::Cmd),
220
221    /// Fetch ledger information
222    #[command(subcommand)]
223    Ledger(ledger::Cmd),
224
225    /// Sign and verify arbitrary messages using SEP-53
226    #[command(subcommand)]
227    Message(message::Cmd),
228
229    /// ⚠️ Deprecated, use `fees stats` instead. Fetch network feestats
230    FeeStats(fee_stats::Cmd),
231
232    /// Fetch network feestats and configure CLI fee settings
233    #[command(subcommand)]
234    Fees(fees::Cmd),
235}
236
237#[derive(thiserror::Error, Debug)]
238pub enum Error {
239    // TODO: stop using Debug for displaying errors
240    #[error(transparent)]
241    Contract(#[from] contract::Error),
242
243    #[error(transparent)]
244    Doctor(#[from] doctor::Error),
245
246    #[error(transparent)]
247    Events(#[from] events::Error),
248
249    #[error(transparent)]
250    Keys(#[from] keys::Error),
251
252    #[error(transparent)]
253    Xdr(#[from] stellar_xdr::cli::Error),
254
255    #[error(transparent)]
256    Strkey(#[from] stellar_strkey::cli::Error),
257
258    #[error(transparent)]
259    Clap(#[from] clap::error::Error),
260
261    #[error(transparent)]
262    Plugin(#[from] plugin::Error),
263
264    #[error(transparent)]
265    PluginDefault(#[from] plugin::default::Error),
266
267    #[error(transparent)]
268    Network(#[from] network::Error),
269
270    #[error(transparent)]
271    Container(#[from] container::Error),
272
273    #[error(transparent)]
274    Config(#[from] cfg::Error),
275
276    #[error(transparent)]
277    Snapshot(#[from] snapshot::Error),
278
279    #[error(transparent)]
280    Token(#[from] token::Error),
281
282    #[error(transparent)]
283    Tx(#[from] tx::Error),
284
285    #[error(transparent)]
286    Cache(#[from] cache::Error),
287
288    #[error(transparent)]
289    Env(#[from] env::Error),
290
291    #[error(transparent)]
292    Ledger(#[from] ledger::Error),
293
294    #[error(transparent)]
295    Message(#[from] message::Error),
296
297    #[error(transparent)]
298    FeeStats(#[from] fee_stats::Error),
299
300    #[error(transparent)]
301    Fees(#[from] fees::Error),
302}