From 89b8a61e205430db7137a10f5d94e488f2dcbfeb Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Wed, 3 Jan 2024 16:22:40 -0500 Subject: [PATCH] feat: add back previous commands with deprecation warning --- .../fixtures/test-wasms/swap/src/test.rs | 6 +- .../fixtures/test-wasms/token/src/test.rs | 34 +- .../soroban-test/tests/it/integration/util.rs | 1 + .../soroban-test/tests/it/integration/wrap.rs | 6 +- cmd/crates/soroban-test/tests/it/lab.rs | 27 -- cmd/crates/soroban-test/tests/it/main.rs | 1 - cmd/soroban-cli/src/commands/config/mod.rs | 7 +- .../wrap.rs => contract/deploy/asset.rs} | 15 - .../src/commands/contract/deploy/wasm.rs | 228 ++++++++++ cmd/soroban-cli/src/commands/contract/id.rs | 28 ++ .../{lab/token/id.rs => contract/id/asset.rs} | 0 .../src/commands/contract/id/wasm.rs | 72 +++ cmd/soroban-cli/src/commands/contract/mod.rs | 8 + cmd/soroban-cli/src/commands/lab/mod.rs | 5 +- cmd/soroban-cli/src/commands/lab/token/mod.rs | 14 +- cmd/soroban-cli/src/commands/mod.rs | 4 + cmd/soroban-rpc/internal/test/cli_test.go | 20 +- docs/soroban-cli-full-docs.md | 421 ++++++++++++++++-- 18 files changed, 766 insertions(+), 131 deletions(-) delete mode 100644 cmd/crates/soroban-test/tests/it/lab.rs rename cmd/soroban-cli/src/commands/{lab/token/wrap.rs => contract/deploy/asset.rs} (92%) create mode 100644 cmd/soroban-cli/src/commands/contract/deploy/wasm.rs create mode 100644 cmd/soroban-cli/src/commands/contract/id.rs rename cmd/soroban-cli/src/commands/{lab/token/id.rs => contract/id/asset.rs} (100%) create mode 100644 cmd/soroban-cli/src/commands/contract/id/wasm.rs diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/src/test.rs b/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/src/test.rs index 4f38453311..cf7929ef3e 100644 --- a/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/src/test.rs +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/swap/src/test.rs @@ -27,10 +27,10 @@ fn test_atomic_swap() { let env = Env::default(); env.mock_all_auths(); - let a = Address::random(&env); - let b = Address::random(&env); + let a = Address::generate(&env); + let b = Address::generate(&env); - let token_admin = Address::random(&env); + let token_admin = Address::generate(&env); let (token_a, token_a_admin) = create_token_contract(&env, &token_admin); let (token_b, token_b_admin) = create_token_contract(&env, &token_admin); diff --git a/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/test.rs b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/test.rs index 9aae46eba3..dbdb17a335 100644 --- a/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/test.rs +++ b/cmd/crates/soroban-test/tests/fixtures/test-wasms/token/src/test.rs @@ -19,11 +19,11 @@ fn test() { let e = Env::default(); e.mock_all_auths(); - let admin1 = Address::random(&e); - let admin2 = Address::random(&e); - let user1 = Address::random(&e); - let user2 = Address::random(&e); - let user3 = Address::random(&e); + let admin1 = Address::generate(&e); + let admin2 = Address::generate(&e); + let user1 = Address::generate(&e); + let user2 = Address::generate(&e); + let user3 = Address::generate(&e); let token = create_token(&e, &admin1); token.mint(&user1, &1000); @@ -142,9 +142,9 @@ fn test_burn() { let e = Env::default(); e.mock_all_auths(); - let admin = Address::random(&e); - let user1 = Address::random(&e); - let user2 = Address::random(&e); + let admin = Address::generate(&e); + let user1 = Address::generate(&e); + let user2 = Address::generate(&e); let token = create_token(&e, &admin); token.mint(&user1, &1000); @@ -199,9 +199,9 @@ fn transfer_insufficient_balance() { let e = Env::default(); e.mock_all_auths(); - let admin = Address::random(&e); - let user1 = Address::random(&e); - let user2 = Address::random(&e); + let admin = Address::generate(&e); + let user1 = Address::generate(&e); + let user2 = Address::generate(&e); let token = create_token(&e, &admin); token.mint(&user1, &1000); @@ -216,10 +216,10 @@ fn transfer_from_insufficient_allowance() { let e = Env::default(); e.mock_all_auths(); - let admin = Address::random(&e); - let user1 = Address::random(&e); - let user2 = Address::random(&e); - let user3 = Address::random(&e); + let admin = Address::generate(&e); + let user1 = Address::generate(&e); + let user2 = Address::generate(&e); + let user3 = Address::generate(&e); let token = create_token(&e, &admin); token.mint(&user1, &1000); @@ -235,7 +235,7 @@ fn transfer_from_insufficient_allowance() { #[should_panic(expected = "already initialized")] fn initialize_already_initialized() { let e = Env::default(); - let admin = Address::random(&e); + let admin = Address::generate(&e); let token = create_token(&e, &admin); token.initialize(&admin, &10, &"name".into_val(&e), &"symbol".into_val(&e)); @@ -245,7 +245,7 @@ fn initialize_already_initialized() { #[should_panic(expected = "Decimal must fit in a u8")] fn decimal_is_over_max() { let e = Env::default(); - let admin = Address::random(&e); + let admin = Address::generate(&e); let token = TokenClient::new(&e, &e.register_contract(None, Token {})); token.initialize( &admin, diff --git a/cmd/crates/soroban-test/tests/it/integration/util.rs b/cmd/crates/soroban-test/tests/it/integration/util.rs index ea27680b76..3a8fba8c77 100644 --- a/cmd/crates/soroban-test/tests/it/integration/util.rs +++ b/cmd/crates/soroban-test/tests/it/integration/util.rs @@ -77,6 +77,7 @@ pub fn deploy_contract(sandbox: &TestEnv, wasm: &Wasm) -> String { sandbox .new_assert_cmd("contract") .arg("deploy") + .arg("wasm") .arg("--wasm-hash") .arg(&format!("{hash}")) .arg("--salt") diff --git a/cmd/crates/soroban-test/tests/it/integration/wrap.rs b/cmd/crates/soroban-test/tests/it/integration/wrap.rs index e8f7aedf31..a69e70c7c6 100644 --- a/cmd/crates/soroban-test/tests/it/integration/wrap.rs +++ b/cmd/crates/soroban-test/tests/it/integration/wrap.rs @@ -1,6 +1,6 @@ use soroban_cli::CommandParser; use soroban_cli::{ - commands::{keys, lab::token::wrap}, + commands::{contract::deploy::asset, keys}, utils::contract_id_hash_from_asset, }; use soroban_test::TestEnv; @@ -92,6 +92,6 @@ async fn burn() { ); } -fn wrap_cmd(asset: &str) -> wrap::Cmd { - wrap::Cmd::parse_arg_vec(&["--source=test", &format!("--asset={asset}")]).unwrap() +fn wrap_cmd(asset: &str) -> asset::Cmd { + asset::Cmd::parse_arg_vec(&["--source=test", &format!("--asset={asset}")]).unwrap() } diff --git a/cmd/crates/soroban-test/tests/it/lab.rs b/cmd/crates/soroban-test/tests/it/lab.rs deleted file mode 100644 index 85d8dc6507..0000000000 --- a/cmd/crates/soroban-test/tests/it/lab.rs +++ /dev/null @@ -1,27 +0,0 @@ -use soroban_test::TestEnv; -use std::path::PathBuf; - -#[test] -#[cfg_attr(target_os = "windows", ignore)] -fn lab_xdr_decode() { - let sandbox = TestEnv::default(); - let cargo_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let ref_xdr_filename = cargo_dir.join("tests/it/lab_test_transaction_envelope.txt"); - let ref_xdr = std::fs::read_to_string(ref_xdr_filename.clone()).unwrap(); - - let cmd = sandbox - .new_assert_cmd("lab") - .arg("xdr") - .arg("dec") - .arg("--type") - .arg("TransactionEnvelope") - .arg("--xdr") - .arg("AAAAAgAAAABzdv3ojkzWHMD7KUoXhrPx0GH18vHKV0ZfqpMiEblG1gAAAGQAAAAAAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAADRjwIQ/2zB8tzxMB+71MMO4RoHWCBoTUcd+J0PEBHqKAAAAOjUpRAAAAAAAAAAAAERuUbWAAAAQKAEpum2TGh/P2K0/eOxeXw1eGEG5fl/Ft2a/j7YUN+H3XNjkFAfYnJvfpmvTsNYqPsoHKufgRpDmJuAhd0xJgk=") - .assert() - .success(); - let stdout = String::from_utf8(cmd.get_output().clone().stdout).unwrap(); - if ref_xdr.is_empty() { - std::fs::write(ref_xdr_filename, stdout.clone()).unwrap(); - } - assert_eq!(stdout, ref_xdr); -} diff --git a/cmd/crates/soroban-test/tests/it/main.rs b/cmd/crates/soroban-test/tests/it/main.rs index 3077d2fa01..a6b18cb22f 100644 --- a/cmd/crates/soroban-test/tests/it/main.rs +++ b/cmd/crates/soroban-test/tests/it/main.rs @@ -3,7 +3,6 @@ mod config; mod help; #[cfg(feature = "integration")] mod integration; -mod lab; mod plugin; mod util; mod version; diff --git a/cmd/soroban-cli/src/commands/config/mod.rs b/cmd/soroban-cli/src/commands/config/mod.rs index eaa63aa587..1d0cd8678c 100644 --- a/cmd/soroban-cli/src/commands/config/mod.rs +++ b/cmd/soroban-cli/src/commands/config/mod.rs @@ -7,16 +7,19 @@ use crate::Pwd; use self::{network::Network, secret::Secret}; -use super::network; +use super::{keys, network}; pub mod locator; pub mod secret; #[derive(Debug, Parser)] pub enum Cmd { - /// Configure different networks + /// Configure different networks. Depraecated, use `soroban network` instead. #[command(subcommand)] Network(network::Cmd), + /// Identity management. Deprecated use `soroban keys` instead. + #[command(subcommand)] + Identity(keys::Cmd), } #[derive(thiserror::Error, Debug)] diff --git a/cmd/soroban-cli/src/commands/lab/token/wrap.rs b/cmd/soroban-cli/src/commands/contract/deploy/asset.rs similarity index 92% rename from cmd/soroban-cli/src/commands/lab/token/wrap.rs rename to cmd/soroban-cli/src/commands/contract/deploy/asset.rs index 2b6f4dd4f5..c10bf81646 100644 --- a/cmd/soroban-cli/src/commands/lab/token/wrap.rs +++ b/cmd/soroban-cli/src/commands/contract/deploy/asset.rs @@ -99,21 +99,6 @@ impl Cmd { } } -/// # Errors -/// -/// Might return an error -pub fn vec_to_hash(res: &ScVal) -> Result { - if let ScVal::Address(ScAddress::Contract(res_contract)) = &res { - let mut hash_bytes: [u8; 32] = [0; 32]; - for (i, b) in res_contract.0.iter().enumerate() { - hash_bytes[i] = *b; - } - Ok(Hash(hash_bytes)) - } else { - Err(XdrError::Invalid) - } -} - fn build_wrap_token_tx( asset: &Asset, contract_id: &Hash, diff --git a/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs b/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs new file mode 100644 index 0000000000..76c1301733 --- /dev/null +++ b/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs @@ -0,0 +1,228 @@ +use std::array::TryFromSliceError; +use std::fmt::Debug; +use std::num::ParseIntError; + +use clap::{arg, command, Parser}; +use rand::Rng; +use soroban_env_host::{ + xdr::{ + AccountId, ContractExecutable, ContractIdPreimage, ContractIdPreimageFromAddress, + CreateContractArgs, Error as XdrError, Hash, HostFunction, InvokeHostFunctionOp, Memo, + MuxedAccount, Operation, OperationBody, Preconditions, PublicKey, ScAddress, + SequenceNumber, Transaction, TransactionExt, Uint256, VecM, + }, + HostError, +}; + +use crate::commands::contract::{self, id::wasm::get_contract_id}; +use crate::{ + commands::{config, contract::install, HEADING_RPC}, + rpc::{self, Client}, + utils, wasm, +}; + +#[derive(Parser, Debug, Clone)] +#[command(group( + clap::ArgGroup::new("wasm_src") + .required(true) + .args(&["wasm", "wasm_hash"]), +))] +#[group(skip)] +pub struct Cmd { + /// WASM file to deploy + #[arg(long, group = "wasm_src")] + wasm: Option, + /// Hash of the already installed/deployed WASM file + #[arg(long = "wasm-hash", conflicts_with = "wasm", group = "wasm_src")] + wasm_hash: Option, + /// Custom salt 32-byte salt for the token id + #[arg( + long, + help_heading = HEADING_RPC, + )] + salt: Option, + #[command(flatten)] + config: config::Args, + #[command(flatten)] + pub fee: crate::fee::Args, + #[arg(long, short = 'i', default_value = "false")] + /// Whether to ignore safety checks when deploying contracts + pub ignore_checks: bool, +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Install(#[from] install::Error), + #[error(transparent)] + Host(#[from] HostError), + #[error("error parsing int: {0}")] + ParseIntError(#[from] ParseIntError), + #[error("internal conversion error: {0}")] + TryFromSliceError(#[from] TryFromSliceError), + #[error("xdr processing error: {0}")] + Xdr(#[from] XdrError), + #[error("jsonrpc error: {0}")] + JsonRpc(#[from] jsonrpsee_core::Error), + #[error("cannot parse salt: {salt}")] + CannotParseSalt { salt: String }, + #[error("cannot parse contract ID {contract_id}: {error}")] + CannotParseContractId { + contract_id: String, + error: stellar_strkey::DecodeError, + }, + #[error("cannot parse WASM hash {wasm_hash}: {error}")] + CannotParseWasmHash { + wasm_hash: String, + error: stellar_strkey::DecodeError, + }, + #[error("Must provide either --wasm or --wash-hash")] + WasmNotProvided, + #[error(transparent)] + Rpc(#[from] rpc::Error), + #[error(transparent)] + Config(#[from] config::Error), + #[error(transparent)] + StrKey(#[from] stellar_strkey::DecodeError), + #[error(transparent)] + Infallible(#[from] std::convert::Infallible), + #[error(transparent)] + WasmId(#[from] contract::id::wasm::Error), +} + +impl Cmd { + pub async fn run(&self) -> Result<(), Error> { + let res_str = self.run_and_get_contract_id().await?; + println!("{res_str}"); + Ok(()) + } + + pub async fn run_and_get_contract_id(&self) -> Result { + let wasm_hash = if let Some(wasm) = &self.wasm { + let hash = install::Cmd { + wasm: wasm::Args { wasm: wasm.clone() }, + config: self.config.clone(), + fee: self.fee.clone(), + ignore_checks: self.ignore_checks, + } + .run_and_get_hash() + .await?; + hex::encode(hash) + } else { + self.wasm_hash + .as_ref() + .ok_or(Error::WasmNotProvided)? + .to_string() + }; + + let hash = Hash(utils::contract_id_from_str(&wasm_hash).map_err(|e| { + Error::CannotParseWasmHash { + wasm_hash: wasm_hash.clone(), + error: e, + } + })?); + + self.run_against_rpc_server(hash).await + } + + async fn run_against_rpc_server(&self, wasm_hash: Hash) -> Result { + let network = self.config.get_network()?; + let salt: [u8; 32] = match &self.salt { + Some(h) => soroban_spec_tools::utils::padded_hex_from_str(h, 32) + .map_err(|_| Error::CannotParseSalt { salt: h.clone() })? + .try_into() + .map_err(|_| Error::CannotParseSalt { salt: h.clone() })?, + None => rand::thread_rng().gen::<[u8; 32]>(), + }; + + let client = Client::new(&network.rpc_url)?; + client + .verify_network_passphrase(Some(&network.network_passphrase)) + .await?; + let key = self.config.key_pair()?; + + // Get the account sequence number + let public_strkey = + stellar_strkey::ed25519::PublicKey(key.verifying_key().to_bytes()).to_string(); + + let account_details = client.get_account(&public_strkey).await?; + let sequence: i64 = account_details.seq_num.into(); + let (tx, contract_id) = build_create_contract_tx( + wasm_hash, + sequence + 1, + self.fee.fee, + &network.network_passphrase, + salt, + &key, + )?; + client + .prepare_and_send_transaction(&tx, &key, &[], &network.network_passphrase, None, None) + .await?; + Ok(stellar_strkey::Contract(contract_id.0).to_string()) + } +} + +fn build_create_contract_tx( + hash: Hash, + sequence: i64, + fee: u32, + network_passphrase: &str, + salt: [u8; 32], + key: &ed25519_dalek::SigningKey, +) -> Result<(Transaction, Hash), Error> { + let source_account = AccountId(PublicKey::PublicKeyTypeEd25519( + key.verifying_key().to_bytes().into(), + )); + + let contract_id_preimage = ContractIdPreimage::Address(ContractIdPreimageFromAddress { + address: ScAddress::Account(source_account), + salt: Uint256(salt), + }); + let contract_id = get_contract_id(contract_id_preimage.clone(), network_passphrase)?; + + let op = Operation { + source_account: None, + body: OperationBody::InvokeHostFunction(InvokeHostFunctionOp { + host_function: HostFunction::CreateContract(CreateContractArgs { + contract_id_preimage, + executable: ContractExecutable::Wasm(hash), + }), + auth: VecM::default(), + }), + }; + let tx = Transaction { + source_account: MuxedAccount::Ed25519(Uint256(key.verifying_key().to_bytes())), + fee, + seq_num: SequenceNumber(sequence), + cond: Preconditions::None, + memo: Memo::None, + operations: vec![op].try_into()?, + ext: TransactionExt::V0, + }; + + Ok((tx, Hash(contract_id.into()))) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_build_create_contract() { + let hash = hex::decode("0000000000000000000000000000000000000000000000000000000000000000") + .unwrap() + .try_into() + .unwrap(); + let result = build_create_contract_tx( + Hash(hash), + 300, + 1, + "Public Global Stellar Network ; September 2015", + [0u8; 32], + &utils::parse_secret_key("SBFGFF27Y64ZUGFAIG5AMJGQODZZKV2YQKAVUUN4HNE24XZXD2OEUVUP") + .unwrap(), + ); + + assert!(result.is_ok()); + } +} diff --git a/cmd/soroban-cli/src/commands/contract/id.rs b/cmd/soroban-cli/src/commands/contract/id.rs new file mode 100644 index 0000000000..bb8744d516 --- /dev/null +++ b/cmd/soroban-cli/src/commands/contract/id.rs @@ -0,0 +1,28 @@ +pub mod asset; +pub mod wasm; + +#[derive(Debug, clap::Subcommand)] +pub enum Cmd { + /// Deploy builtin Soroban Asset Contract + Asset(asset::Cmd), + /// Deploy normal Wasm Contract + Wasm(wasm::Cmd), +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Asset(#[from] asset::Error), + #[error(transparent)] + Wasm(#[from] wasm::Error), +} + +impl Cmd { + pub fn run(&self) -> Result<(), Error> { + match &self { + Cmd::Asset(asset) => asset.run()?, + Cmd::Wasm(wasm) => wasm.run()?, + } + Ok(()) + } +} diff --git a/cmd/soroban-cli/src/commands/lab/token/id.rs b/cmd/soroban-cli/src/commands/contract/id/asset.rs similarity index 100% rename from cmd/soroban-cli/src/commands/lab/token/id.rs rename to cmd/soroban-cli/src/commands/contract/id/asset.rs diff --git a/cmd/soroban-cli/src/commands/contract/id/wasm.rs b/cmd/soroban-cli/src/commands/contract/id/wasm.rs new file mode 100644 index 0000000000..4097e7bbf8 --- /dev/null +++ b/cmd/soroban-cli/src/commands/contract/id/wasm.rs @@ -0,0 +1,72 @@ +use clap::{arg, command, Parser}; +use sha2::{Digest, Sha256}; +use soroban_env_host::xdr::{ + self, AccountId, ContractIdPreimage, ContractIdPreimageFromAddress, Hash, HashIdPreimage, + HashIdPreimageContractId, Limits, PublicKey, ScAddress, Uint256, WriteXdr, +}; + +use crate::commands::config; + +#[derive(Parser, Debug, Clone)] +#[group(skip)] +pub struct Cmd { + /// ID of the Soroban contract + #[arg(long)] + pub salt: String, + + #[command(flatten)] + pub config: config::Args, +} +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + ParseError(#[from] crate::utils::parsing::Error), + #[error(transparent)] + ConfigError(#[from] crate::commands::config::Error), + #[error(transparent)] + Xdr(#[from] xdr::Error), + #[error("cannot parse salt {0}")] + CannotParseSalt(String), +} +impl Cmd { + pub fn run(&self) -> Result<(), Error> { + let salt: [u8; 32] = soroban_spec_tools::utils::padded_hex_from_str(&self.salt, 32) + .map_err(|_| Error::CannotParseSalt(self.salt.clone()))? + .try_into() + .map_err(|_| Error::CannotParseSalt(self.salt.clone()))?; + let contract_id_preimage = + contract_preimage(&self.config.key_pair()?.verifying_key(), salt); + let contract_id = get_contract_id( + contract_id_preimage.clone(), + &self.config.get_network()?.network_passphrase, + )?; + let strkey_contract_id = stellar_strkey::Contract(contract_id.0).to_string(); + println!("{strkey_contract_id}"); + Ok(()) + } +} + +pub fn contract_preimage(key: &ed25519_dalek::VerifyingKey, salt: [u8; 32]) -> ContractIdPreimage { + let source_account = AccountId(PublicKey::PublicKeyTypeEd25519(key.to_bytes().into())); + ContractIdPreimage::Address(ContractIdPreimageFromAddress { + address: ScAddress::Account(source_account), + salt: Uint256(salt), + }) +} + +pub fn get_contract_id( + contract_id_preimage: ContractIdPreimage, + network_passphrase: &str, +) -> Result { + let network_id = Hash( + Sha256::digest(network_passphrase.as_bytes()) + .try_into() + .unwrap(), + ); + let preimage = HashIdPreimage::ContractId(HashIdPreimageContractId { + network_id, + contract_id_preimage, + }); + let preimage_xdr = preimage.to_xdr(Limits::none())?; + Ok(Hash(Sha256::digest(preimage_xdr).into())) +} diff --git a/cmd/soroban-cli/src/commands/contract/mod.rs b/cmd/soroban-cli/src/commands/contract/mod.rs index d94e8da5b2..db450f611c 100644 --- a/cmd/soroban-cli/src/commands/contract/mod.rs +++ b/cmd/soroban-cli/src/commands/contract/mod.rs @@ -3,6 +3,7 @@ pub mod build; pub mod deploy; pub mod extend; pub mod fetch; +pub mod id; pub mod inspect; pub mod install; pub mod invoke; @@ -32,6 +33,10 @@ pub enum Cmd { /// Fetch a contract's Wasm binary Fetch(fetch::Cmd), + /// Generate the contract id for a given contract or asset + #[command(subcommand)] + Id(id::Cmd), + /// Inspect a WASM file listing contract functions, meta, etc Inspect(inspect::Cmd), @@ -76,6 +81,8 @@ pub enum Error { #[error(transparent)] Fetch(#[from] fetch::Error), + #[error(transparent)] + Id(#[from] id::Error), #[error(transparent)] Inspect(#[from] inspect::Error), @@ -103,6 +110,7 @@ impl Cmd { Cmd::Build(build) => build.run()?, Cmd::Extend(extend) => extend.run().await?, Cmd::Deploy(deploy) => deploy.run().await?, + Cmd::Id(id) => id.run()?, Cmd::Inspect(inspect) => inspect.run()?, Cmd::Install(install) => install.run().await?, Cmd::Invoke(invoke) => invoke.run(global_args).await?, diff --git a/cmd/soroban-cli/src/commands/lab/mod.rs b/cmd/soroban-cli/src/commands/lab/mod.rs index 96d64094d9..f405efe6d7 100644 --- a/cmd/soroban-cli/src/commands/lab/mod.rs +++ b/cmd/soroban-cli/src/commands/lab/mod.rs @@ -1,4 +1,5 @@ use clap::Subcommand; +use stellar_xdr::cli as xdr; pub mod token; @@ -8,7 +9,7 @@ pub enum Cmd { Token(token::Root), /// Decode xdr - Xdr(stellar_xdr::cli::Root), + Xdr(xdr::Root), } #[derive(thiserror::Error, Debug)] @@ -16,7 +17,7 @@ pub enum Error { #[error(transparent)] Token(#[from] token::Error), #[error(transparent)] - Xdr(#[from] stellar_xdr::cli::Error), + Xdr(#[from] xdr::Error), } impl Cmd { diff --git a/cmd/soroban-cli/src/commands/lab/token/mod.rs b/cmd/soroban-cli/src/commands/lab/token/mod.rs index ab6eb71171..bd7eacf36e 100644 --- a/cmd/soroban-cli/src/commands/lab/token/mod.rs +++ b/cmd/soroban-cli/src/commands/lab/token/mod.rs @@ -1,10 +1,8 @@ use std::fmt::Debug; +use crate::commands::contract::{deploy, id}; use clap::{Parser, Subcommand}; -pub mod id; -pub mod wrap; - #[derive(Parser, Debug)] pub struct Root { #[clap(subcommand)] @@ -14,17 +12,19 @@ pub struct Root { #[derive(Subcommand, Debug)] enum Cmd { /// Deploy a token contract to wrap an existing Stellar classic asset for smart contract usage - Wrap(wrap::Cmd), + /// Deprecated, use `soroban contract deploy asset` instead + Wrap(deploy::asset::Cmd), /// Compute the expected contract id for the given asset - Id(id::Cmd), + /// Deprecated, use `soroban contract id asset` instead + Id(id::asset::Cmd), } #[derive(thiserror::Error, Debug)] pub enum Error { #[error(transparent)] - Wrap(#[from] wrap::Error), + Wrap(#[from] deploy::asset::Error), #[error(transparent)] - Id(#[from] id::Error), + Id(#[from] id::asset::Error), } impl Root { diff --git a/cmd/soroban-cli/src/commands/mod.rs b/cmd/soroban-cli/src/commands/mod.rs index e4d823ce20..0179d6a917 100644 --- a/cmd/soroban-cli/src/commands/mod.rs +++ b/cmd/soroban-cli/src/commands/mod.rs @@ -98,6 +98,7 @@ impl Root { Cmd::Network(network) => network.run()?, Cmd::Version(version) => version.run(), Cmd::Keys(id) => id.run().await?, + Cmd::Config(_) => todo!(), }; Ok(()) } @@ -116,6 +117,9 @@ pub enum Cmd { /// Print shell completion code for the specified shell. #[command(long_about = completion::LONG_ABOUT)] Completion(completion::Cmd), + /// Deprecated, use `soroban keys` and `soroban network` instead + #[command(subcommand)] + Config(config::Cmd), /// Tools for smart contract developers #[command(subcommand)] Contract(contract::Cmd), diff --git a/cmd/soroban-rpc/internal/test/cli_test.go b/cmd/soroban-rpc/internal/test/cli_test.go index 8488ea2e38..fbffc660bf 100644 --- a/cmd/soroban-rpc/internal/test/cli_test.go +++ b/cmd/soroban-rpc/internal/test/cli_test.go @@ -51,7 +51,7 @@ func TestCLIWrapCustom(t *testing.T) { it := NewCLITest(t) assetCode := "deadbeef" issuerAccount := getCLIDefaultAccount(t) - strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("lab token wrap --asset=%s:%s", assetCode, issuerAccount)) + strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy asset --asset=%s:%s", assetCode, issuerAccount)) require.Equal(t, "true", runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id=%s -- authorized --id=%s", strkeyContractID, issuerAccount))) asset := txnbuild.CreditAsset{ Code: assetCode, @@ -65,7 +65,7 @@ func TestCLIWrapCustom(t *testing.T) { func TestCLIWrapNative(t *testing.T) { NewCLITest(t) testAccount := getCLIDefaultAccount(t) - strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("lab token wrap --asset=native:%s", testAccount)) + strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy asset --asset=native:%s", testAccount)) require.Equal(t, "CAMTHSPKXZJIRTUXQP5QWJIFH3XIDMKLFAWVQOFOXPTKAW5GKV37ZC4N", strkeyContractID) require.Equal(t, "true", runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id=%s -- authorized --id=%s", strkeyContractID, testAccount))) require.Equal(t, "\"9223372036854775807\"", runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id=%s -- balance --id %s", strkeyContractID, testAccount))) @@ -84,13 +84,13 @@ func TestCLIContractInstallAndDeploy(t *testing.T) { runSuccessfulCLICmd(t, fmt.Sprintf("contract install --wasm %s --ignore-checks", helloWorldContractPath)) wasm := getHelloWorldContract(t) contractHash := xdr.Hash(sha256.Sum256(wasm)) - output := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy --salt %s --wasm-hash %s --ignore-checks", hex.EncodeToString(testSalt[:]), contractHash.HexString())) + output := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy wasm --salt %s --wasm-hash %s --ignore-checks", hex.EncodeToString(testSalt[:]), contractHash.HexString())) outputsContractIDInLastLine(t, output) } func TestCLIContractDeploy(t *testing.T) { NewCLITest(t) - output := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy --salt %s --wasm %s --ignore-checks", hex.EncodeToString(testSalt[:]), helloWorldContractPath)) + output := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy wasm --salt %s --wasm %s --ignore-checks", hex.EncodeToString(testSalt[:]), helloWorldContractPath)) outputsContractIDInLastLine(t, output) } @@ -110,14 +110,14 @@ func outputsContractIDInLastLine(t *testing.T, output string) { func TestCLIContractDeployAndInvoke(t *testing.T) { NewCLITest(t) - contractID := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy --salt=%s --wasm %s --ignore-checks", hex.EncodeToString(testSalt[:]), helloWorldContractPath)) + contractID := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy wasm --salt=%s --wasm %s --ignore-checks", hex.EncodeToString(testSalt[:]), helloWorldContractPath)) output := runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id %s -- hello --world=world", contractID)) require.Contains(t, output, `["Hello","world"]`) } func TestCLIRestorePreamble(t *testing.T) { test := NewCLITest(t) - strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy --salt=%s --wasm %s --ignore-checks", hex.EncodeToString(testSalt[:]), helloWorldContractPath)) + strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy wasm --salt=%s --wasm %s --ignore-checks", hex.EncodeToString(testSalt[:]), helloWorldContractPath)) count := runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id %s -- inc", strkeyContractID)) require.Equal(t, "1", count) count = runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id %s -- inc", strkeyContractID)) @@ -135,7 +135,7 @@ func TestCLIRestorePreamble(t *testing.T) { func TestCLIExtend(t *testing.T) { test := NewCLITest(t) - strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy --salt=%s --wasm %s --ignore-checks", hex.EncodeToString(testSalt[:]), helloWorldContractPath)) + strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy wasm --salt=%s --wasm %s --ignore-checks", hex.EncodeToString(testSalt[:]), helloWorldContractPath)) count := runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id %s -- inc", strkeyContractID)) require.Equal(t, "1", count) @@ -159,7 +159,7 @@ func TestCLIExtend(t *testing.T) { } func TestCLIExtendTooLow(t *testing.T) { test := NewCLITest(t) - strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy --salt=%s --wasm %s --ignore-checks", hex.EncodeToString(testSalt[:]), helloWorldContractPath)) + strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy wasm --salt=%s --wasm %s --ignore-checks", hex.EncodeToString(testSalt[:]), helloWorldContractPath)) count := runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id %s -- inc", strkeyContractID)) require.Equal(t, "1", count) @@ -181,7 +181,7 @@ func TestCLIExtendTooLow(t *testing.T) { func TestCLIExtendTooHigh(t *testing.T) { test := NewCLITest(t) - strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy --salt=%s --wasm %s --ignore-checks", hex.EncodeToString(testSalt[:]), helloWorldContractPath)) + strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy wasm --salt=%s --wasm %s --ignore-checks", hex.EncodeToString(testSalt[:]), helloWorldContractPath)) count := runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id %s -- inc", strkeyContractID)) require.Equal(t, "1", count) @@ -200,7 +200,7 @@ func TestCLIExtendTooHigh(t *testing.T) { func TestCLIRestore(t *testing.T) { test := NewCLITest(t) - strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy --salt=%s --wasm %s --ignore-checks", hex.EncodeToString(testSalt[:]), helloWorldContractPath)) + strkeyContractID := runSuccessfulCLICmd(t, fmt.Sprintf("contract deploy wasm --salt=%s --wasm %s --ignore-checks", hex.EncodeToString(testSalt[:]), helloWorldContractPath)) count := runSuccessfulCLICmd(t, fmt.Sprintf("contract invoke --id %s -- inc", strkeyContractID)) require.Equal(t, "1", count) diff --git a/docs/soroban-cli-full-docs.md b/docs/soroban-cli-full-docs.md index 746433fd2b..44ab4e1b98 100644 --- a/docs/soroban-cli-full-docs.md +++ b/docs/soroban-cli-full-docs.md @@ -6,6 +6,19 @@ This document contains the help content for the `soroban` command-line program. * [`soroban`↴](#soroban) * [`soroban completion`↴](#soroban-completion) +* [`soroban config`↴](#soroban-config) +* [`soroban config network`↴](#soroban-config-network) +* [`soroban config network add`↴](#soroban-config-network-add) +* [`soroban config network rm`↴](#soroban-config-network-rm) +* [`soroban config network ls`↴](#soroban-config-network-ls) +* [`soroban config identity`↴](#soroban-config-identity) +* [`soroban config identity add`↴](#soroban-config-identity-add) +* [`soroban config identity address`↴](#soroban-config-identity-address) +* [`soroban config identity fund`↴](#soroban-config-identity-fund) +* [`soroban config identity generate`↴](#soroban-config-identity-generate) +* [`soroban config identity ls`↴](#soroban-config-identity-ls) +* [`soroban config identity rm`↴](#soroban-config-identity-rm) +* [`soroban config identity show`↴](#soroban-config-identity-show) * [`soroban contract`↴](#soroban-contract) * [`soroban contract bindings`↴](#soroban-contract-bindings) * [`soroban contract bindings json`↴](#soroban-contract-bindings-json) @@ -14,7 +27,12 @@ This document contains the help content for the `soroban` command-line program. * [`soroban contract build`↴](#soroban-contract-build) * [`soroban contract extend`↴](#soroban-contract-extend) * [`soroban contract deploy`↴](#soroban-contract-deploy) +* [`soroban contract deploy asset`↴](#soroban-contract-deploy-asset) +* [`soroban contract deploy wasm`↴](#soroban-contract-deploy-wasm) * [`soroban contract fetch`↴](#soroban-contract-fetch) +* [`soroban contract id`↴](#soroban-contract-id) +* [`soroban contract id asset`↴](#soroban-contract-id-asset) +* [`soroban contract id wasm`↴](#soroban-contract-id-wasm) * [`soroban contract inspect`↴](#soroban-contract-inspect) * [`soroban contract install`↴](#soroban-contract-install) * [`soroban contract invoke`↴](#soroban-contract-invoke) @@ -79,6 +97,7 @@ Full CLI reference: https://github.com/stellar/soroban-tools/tree/main/docs/soro ###### **Subcommands:** * `completion` — Print shell completion code for the specified shell +* `config` — Deprecated, use `soroban keys` and `soroban network` instead * `contract` — Tools for smart contract developers * `events` — Watch the network for contract events * `keys` — Create and manage identities including keys and addresses @@ -122,6 +141,233 @@ To enable autocomplete permanently, run: +## `soroban config` + +Deprecated, use `soroban keys` and `soroban network` instead + +**Usage:** `soroban config ` + +###### **Subcommands:** + +* `network` — Configure different networks. Depraecated, use `soroban network` instead +* `identity` — Identity management. Deprecated use `soroban keys` instead + + + +## `soroban config network` + +Configure different networks. Depraecated, use `soroban network` instead + +**Usage:** `soroban config network ` + +###### **Subcommands:** + +* `add` — Add a new network +* `rm` — Remove a network +* `ls` — List networks + + + +## `soroban config network add` + +Add a new network + +**Usage:** `soroban config network add [OPTIONS] --rpc-url --network-passphrase ` + +###### **Arguments:** + +* `` — Name of network + +###### **Options:** + +* `--rpc-url ` — RPC server endpoint +* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server +* `--global` — Use global config +* `--config-dir ` + + + +## `soroban config network rm` + +Remove a network + +**Usage:** `soroban config network rm [OPTIONS] ` + +###### **Arguments:** + +* `` — Network to remove + +###### **Options:** + +* `--global` — Use global config +* `--config-dir ` + + + +## `soroban config network ls` + +List networks + +**Usage:** `soroban config network ls [OPTIONS]` + +###### **Options:** + +* `--global` — Use global config +* `--config-dir ` +* `-l`, `--long` — Get more info about the networks + + + +## `soroban config identity` + +Identity management. Deprecated use `soroban keys` instead + +**Usage:** `soroban config identity ` + +###### **Subcommands:** + +* `add` — Add a new identity (keypair, ledger, macOS keychain) +* `address` — Given an identity return its address (public key) +* `fund` — Fund an identity on a test network +* `generate` — Generate a new identity with a seed phrase, currently 12 words +* `ls` — List identities +* `rm` — Remove an identity +* `show` — Given an identity return its private key + + + +## `soroban config identity add` + +Add a new identity (keypair, ledger, macOS keychain) + +**Usage:** `soroban config identity add [OPTIONS] ` + +###### **Arguments:** + +* `` — Name of identity + +###### **Options:** + +* `--secret-key` — Add using secret_key Can provide with SOROBAN_SECRET_KEY +* `--seed-phrase` — Add using 12 word seed phrase to generate secret_key +* `--global` — Use global config +* `--config-dir ` + + + +## `soroban config identity address` + +Given an identity return its address (public key) + +**Usage:** `soroban config identity address [OPTIONS] ` + +###### **Arguments:** + +* `` — Name of identity to lookup, default test identity used if not provided + +###### **Options:** + +* `--hd-path ` — If identity is a seed phrase use this hd path, default is 0 +* `--global` — Use global config +* `--config-dir ` + + + +## `soroban config identity fund` + +Fund an identity on a test network + +**Usage:** `soroban config identity fund [OPTIONS] ` + +###### **Arguments:** + +* `` — Name of identity to lookup, default test identity used if not provided + +###### **Options:** + +* `--rpc-url ` — RPC server endpoint +* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server +* `--network ` — Name of network to use from config +* `--hd-path ` — If identity is a seed phrase use this hd path, default is 0 +* `--global` — Use global config +* `--config-dir ` + + + +## `soroban config identity generate` + +Generate a new identity with a seed phrase, currently 12 words + +**Usage:** `soroban config identity generate [OPTIONS] ` + +###### **Arguments:** + +* `` — Name of identity + +###### **Options:** + +* `--no-fund` — Do not fund address +* `--seed ` — Optional seed to use when generating seed phrase. Random otherwise +* `-s`, `--as-secret` — Output the generated identity as a secret key +* `--global` — Use global config +* `--config-dir ` +* `--hd-path ` — When generating a secret key, which hd_path should be used from the original seed_phrase +* `-d`, `--default-seed` — Generate the default seed phrase. Useful for testing. Equivalent to --seed 0000000000000000 +* `--rpc-url ` — RPC server endpoint +* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server +* `--network ` — Name of network to use from config + + + +## `soroban config identity ls` + +List identities + +**Usage:** `soroban config identity ls [OPTIONS]` + +###### **Options:** + +* `--global` — Use global config +* `--config-dir ` +* `-l`, `--long` + + + +## `soroban config identity rm` + +Remove an identity + +**Usage:** `soroban config identity rm [OPTIONS] ` + +###### **Arguments:** + +* `` — Identity to remove + +###### **Options:** + +* `--global` — Use global config +* `--config-dir ` + + + +## `soroban config identity show` + +Given an identity return its private key + +**Usage:** `soroban config identity show [OPTIONS] ` + +###### **Arguments:** + +* `` — Name of identity to lookup, default is test identity + +###### **Options:** + +* `--hd-path ` — If identity is a seed phrase use this hd path, default is 0 +* `--global` — Use global config +* `--config-dir ` + + + ## `soroban contract` Tools for smart contract developers @@ -133,8 +379,9 @@ Tools for smart contract developers * `bindings` — Generate code client bindings for a contract * `build` — Build a contract from source * `extend` — Extend the time to live ledger of a contract-data ledger entry -* `deploy` — Deploy a contract +* `deploy` — Deploy a contract or Soroban Asset Contract * `fetch` — Fetch a contract's Wasm binary +* `id` — Generate the contract id for a given contract or asset * `inspect` — Inspect a WASM file listing contract functions, meta, etc * `install` — Install a WASM file to the ledger without creating a contract instance * `invoke` — Invoke a contract function @@ -269,9 +516,44 @@ If no keys are specified the contract itself is extended. ## `soroban contract deploy` -Deploy a contract +Deploy a contract or Soroban Asset Contract + +**Usage:** `soroban contract deploy ` + +###### **Subcommands:** + +* `asset` — Deploy builtin Soroban Asset Contract +* `wasm` — Deploy normal Wasm Contract + + + +## `soroban contract deploy asset` + +Deploy builtin Soroban Asset Contract + +**Usage:** `soroban contract deploy asset [OPTIONS] --asset --source-account ` + +###### **Options:** + +* `--asset ` — ID of the Stellar classic asset to wrap, e.g. "USDC:G...5" +* `--rpc-url ` — RPC server endpoint +* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server +* `--network ` — Name of network to use from config +* `--source-account ` — Account that signs the final transaction. Alias `source`. Can be an identity (--source alice), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). Default: `identity generate --default-seed` +* `--hd-path ` — If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` +* `--global` — Use global config +* `--config-dir ` +* `--fee ` — fee amount for transaction, in stroops. 1 stroop = 0.0000001 xlm + + Default value: `100` + + -**Usage:** `soroban contract deploy [OPTIONS] --source-account <--wasm |--wasm-hash >` +## `soroban contract deploy wasm` + +Deploy normal Wasm Contract + +**Usage:** `soroban contract deploy wasm [OPTIONS] --source-account <--wasm |--wasm-hash >` ###### **Options:** @@ -312,6 +594,57 @@ Fetch a contract's Wasm binary +## `soroban contract id` + +Generate the contract id for a given contract or asset + +**Usage:** `soroban contract id ` + +###### **Subcommands:** + +* `asset` — Deploy builtin Soroban Asset Contract +* `wasm` — Deploy normal Wasm Contract + + + +## `soroban contract id asset` + +Deploy builtin Soroban Asset Contract + +**Usage:** `soroban contract id asset [OPTIONS] --asset --source-account ` + +###### **Options:** + +* `--asset ` — ID of the Stellar classic asset to wrap, e.g. "USDC:G...5" +* `--rpc-url ` — RPC server endpoint +* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server +* `--network ` — Name of network to use from config +* `--source-account ` — Account that signs the final transaction. Alias `source`. Can be an identity (--source alice), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). Default: `identity generate --default-seed` +* `--hd-path ` — If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` +* `--global` — Use global config +* `--config-dir ` + + + +## `soroban contract id wasm` + +Deploy normal Wasm Contract + +**Usage:** `soroban contract id wasm [OPTIONS] --salt --source-account ` + +###### **Options:** + +* `--salt ` — ID of the Soroban contract +* `--rpc-url ` — RPC server endpoint +* `--network-passphrase ` — Network passphrase to sign the transaction sent to the rpc server +* `--network ` — Name of network to use from config +* `--source-account ` — Account that signs the final transaction. Alias `source`. Can be an identity (--source alice), a secret key (--source SC36…), or a seed phrase (--source "kite urban…"). Default: `identity generate --default-seed` +* `--hd-path ` — If using a seed phrase, which hierarchical deterministic path to use, e.g. `m/44'/148'/{hd_path}`. Example: `--hd-path 1`. Default: `0` +* `--global` — Use global config +* `--config-dir ` + + + ## `soroban contract inspect` Inspect a WASM file listing contract functions, meta, etc @@ -700,14 +1033,14 @@ Wrap, create, and manage token contracts ###### **Subcommands:** -* `wrap` — Deploy a token contract to wrap an existing Stellar classic asset for smart contract usage -* `id` — Compute the expected contract id for the given asset +* `wrap` — Deploy a token contract to wrap an existing Stellar classic asset for smart contract usage Deprecated, use `soroban contract deploy asset` instead +* `id` — Compute the expected contract id for the given asset Deprecated, use `soroban contract id asset` instead ## `soroban lab token wrap` -Deploy a token contract to wrap an existing Stellar classic asset for smart contract usage +Deploy a token contract to wrap an existing Stellar classic asset for smart contract usage Deprecated, use `soroban contract deploy asset` instead **Usage:** `soroban lab token wrap [OPTIONS] --asset --source-account ` @@ -729,7 +1062,7 @@ Deploy a token contract to wrap an existing Stellar classic asset for smart cont ## `soroban lab token id` -Compute the expected contract id for the given asset +Compute the expected contract id for the given asset Deprecated, use `soroban contract id asset` instead **Usage:** `soroban lab token id [OPTIONS] --asset --source-account ` @@ -855,6 +1188,43 @@ Decode XDR + +## `soroban lab xdr encode` + +Encode XDR + +**Usage:** `soroban lab xdr encode [OPTIONS] --type [FILES]...` + +###### **Arguments:** + +* `` — Files to encode, or stdin if omitted + +###### **Options:** + +* `--type ` — XDR type to encode +* `--input ` + + Default value: `json` + + Possible values: `json` + +* `--output ` + + Default value: `single-base64` + + Possible values: `single`, `single-base64` + + + + +## `soroban lab xdr version` + +Print version information + +**Usage:** `soroban lab xdr version` + + + ## `soroban network` Start and configure networks @@ -919,43 +1289,6 @@ List networks - -## `soroban lab xdr encode` - -Encode XDR - -**Usage:** `soroban lab xdr encode [OPTIONS] --type [FILES]...` - -###### **Arguments:** - -* `` — Files to encode, or stdin if omitted - -###### **Options:** - -* `--type ` — XDR type to encode -* `--input ` - - Default value: `json` - - Possible values: `json` - -* `--output ` - - Default value: `single-base64` - - Possible values: `single`, `single-base64` - - - - -## `soroban lab xdr version` - -Print version information - -**Usage:** `soroban lab xdr version` - - - ## `soroban version` Print version information