soroban_cli/commands/
mod.rs1use std::str::FromStr;
2
3use async_trait::async_trait;
4use clap::{command, error::ErrorKind, CommandFactory, FromArgMatches, Parser};
5
6use crate::config;
7
8pub mod cache;
9pub mod completion;
10pub mod container;
11pub mod contract;
12pub mod env;
13pub mod events;
14pub mod global;
15pub mod keys;
16pub mod network;
17pub mod plugin;
18pub mod snapshot;
19pub mod tx;
20pub mod version;
21
22pub mod txn_result;
23
24pub const HEADING_RPC: &str = "Options (RPC)";
25pub const HEADING_GLOBAL: &str = "Options (Global)";
26const ABOUT: &str =
27 "Work seamlessly with Stellar accounts, contracts, and assets from the command line.
28
29- Generate and manage keys and accounts
30- Build, deploy, and interact with contracts
31- Deploy asset contracts
32- Stream events
33- Start local testnets
34- Decode, encode XDR
35- More!
36
37For additional information see:
38
39- Stellar Docs: https://developers.stellar.org
40- Smart Contract Docs: https://developers.stellar.org/docs/build/smart-contracts/overview
41- CLI Docs: https://developers.stellar.org/docs/tools/developer-tools/cli/stellar-cli";
42
43const LONG_ABOUT: &str = "
45
46To get started generate a new identity:
47
48 stellar keys generate alice
49
50Use keys with the `--source` flag in other commands.
51
52Commands that work with contracts are organized under the `contract` subcommand. List them:
53
54 stellar contract --help
55
56Use contracts like a CLI:
57
58 stellar contract invoke --id CCR6QKTWZQYW6YUJ7UP7XXZRLWQPFRV6SWBLQS4ZQOSAF4BOUD77OTE2 --source alice --network testnet -- --help
59
60Anything 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:
61
62 stellar contract invoke --id CCR6QKTWZQYW6YUJ7UP7XXZRLWQPFRV6SWBLQS4ZQOSAF4BOUD77OTE2 --source alice --network testnet -- hello --to world
63";
64
65#[derive(Parser, Debug)]
66#[command(
67 name = "stellar",
68 about = ABOUT,
69 version = version::long(),
70 long_about = ABOUT.to_string() + LONG_ABOUT,
71 disable_help_subcommand = true,
72)]
73pub struct Root {
74 #[clap(flatten)]
75 pub global_args: global::Args,
76
77 #[command(subcommand)]
78 pub cmd: Cmd,
79}
80
81impl Root {
82 pub fn new() -> Result<Self, Error> {
83 Self::try_parse().map_err(|e| {
84 if std::env::args().any(|s| s == "--list") {
85 let plugins = plugin::list().unwrap_or_default();
86 if plugins.is_empty() {
87 println!("No Plugins installed. E.g. soroban-hello");
88 } else {
89 println!("Installed Plugins:\n {}", plugins.join("\n "));
90 }
91 std::process::exit(0);
92 }
93 match e.kind() {
94 ErrorKind::InvalidSubcommand => match plugin::run() {
95 Ok(()) => Error::Clap(e),
96 Err(e) => Error::Plugin(e),
97 },
98 _ => Error::Clap(e),
99 }
100 })
101 }
102
103 pub fn from_arg_matches<I, T>(itr: I) -> Result<Self, clap::Error>
104 where
105 I: IntoIterator<Item = T>,
106 T: Into<std::ffi::OsString> + Clone,
107 {
108 Self::from_arg_matches_mut(&mut Self::command().get_matches_from(itr))
109 }
110 pub async fn run(&mut self) -> Result<(), Error> {
111 match &mut self.cmd {
112 Cmd::Completion(completion) => completion.run(),
113 Cmd::Contract(contract) => contract.run(&self.global_args).await?,
114 Cmd::Events(events) => events.run().await?,
115 Cmd::Xdr(xdr) => xdr.run()?,
116 Cmd::Network(network) => network.run(&self.global_args).await?,
117 Cmd::Container(container) => container.run(&self.global_args).await?,
118 Cmd::Snapshot(snapshot) => snapshot.run(&self.global_args).await?,
119 Cmd::Version(version) => version.run(),
120 Cmd::Keys(id) => id.run(&self.global_args).await?,
121 Cmd::Tx(tx) => tx.run(&self.global_args).await?,
122 Cmd::Cache(cache) => cache.run()?,
123 Cmd::Env(env) => env.run(&self.global_args)?,
124 };
125 Ok(())
126 }
127}
128
129impl FromStr for Root {
130 type Err = clap::Error;
131
132 fn from_str(s: &str) -> Result<Self, Self::Err> {
133 Self::from_arg_matches(s.split_whitespace())
134 }
135}
136
137#[derive(Parser, Debug)]
138pub enum Cmd {
139 #[command(subcommand)]
141 Contract(contract::Cmd),
142
143 Events(events::Cmd),
145
146 Env(env::Cmd),
155
156 #[command(subcommand)]
158 Keys(keys::Cmd),
159
160 #[command(subcommand)]
162 Network(network::Cmd),
163
164 #[command(subcommand)]
166 Container(container::Cmd),
167
168 #[command(subcommand)]
170 Snapshot(snapshot::Cmd),
171
172 #[command(subcommand)]
174 Tx(tx::Cmd),
175
176 Xdr(stellar_xdr::cli::Root),
178
179 #[command(long_about = completion::LONG_ABOUT)]
181 Completion(completion::Cmd),
182
183 #[command(subcommand)]
185 Cache(cache::Cmd),
186
187 Version(version::Cmd),
189}
190
191#[derive(thiserror::Error, Debug)]
192pub enum Error {
193 #[error(transparent)]
195 Contract(#[from] contract::Error),
196
197 #[error(transparent)]
198 Events(#[from] events::Error),
199
200 #[error(transparent)]
201 Keys(#[from] keys::Error),
202
203 #[error(transparent)]
204 Xdr(#[from] stellar_xdr::cli::Error),
205
206 #[error(transparent)]
207 Clap(#[from] clap::error::Error),
208
209 #[error(transparent)]
210 Plugin(#[from] plugin::Error),
211
212 #[error(transparent)]
213 Network(#[from] network::Error),
214
215 #[error(transparent)]
216 Container(#[from] container::Error),
217
218 #[error(transparent)]
219 Snapshot(#[from] snapshot::Error),
220
221 #[error(transparent)]
222 Tx(#[from] tx::Error),
223
224 #[error(transparent)]
225 Cache(#[from] cache::Error),
226
227 #[error(transparent)]
228 Env(#[from] env::Error),
229}
230
231#[async_trait]
232pub trait NetworkRunnable {
233 type Error;
234 type Result;
235
236 async fn run_against_rpc_server(
237 &self,
238 global_args: Option<&global::Args>,
239 config: Option<&config::Args>,
240 ) -> Result<Self::Result, Self::Error>;
241}