From 7b6c5cdd1da813fceb1a2b05dd9b0f5874c3c6e6 Mon Sep 17 00:00:00 2001 From: Chad Ostrowski <221614+chadoh@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:32:54 -0500 Subject: [PATCH 1/5] chore: clean up interface for info::shared::fetch (#1802) Follow-up to https://github.com/stellar/stellar-cli/pull/1780, implementing @leighmcculloch's [suggestions]. [suggestions]: https://github.com/stellar/stellar-cli/pull/1780#pullrequestreview-2499059771 --- .../commands/contract/bindings/typescript.rs | 39 +++++---- .../src/commands/contract/info/env_meta.rs | 10 +-- .../src/commands/contract/info/interface.rs | 24 +++--- .../src/commands/contract/info/meta.rs | 11 ++- .../src/commands/contract/info/shared.rs | 82 +++++++++++++++---- 5 files changed, 113 insertions(+), 53 deletions(-) diff --git a/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs b/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs index 5317c81f3..1da64eaa5 100644 --- a/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs +++ b/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs @@ -1,12 +1,12 @@ use std::{ffi::OsString, fmt::Debug, path::PathBuf}; use clap::{command, Parser}; -use soroban_spec_tools::contract as contract_spec; +use soroban_spec_tools::contract as spec_tools; use soroban_spec_typescript::boilerplate::Project; use crate::print::Print; use crate::{ - commands::{contract::info::shared as wasm_or_contract, global, NetworkRunnable}, + commands::{contract::info::shared as contract_spec, global, NetworkRunnable}, config, }; use soroban_spec_tools::contract::Spec; @@ -15,7 +15,7 @@ use soroban_spec_tools::contract::Spec; #[group(skip)] pub struct Cmd { #[command(flatten)] - pub wasm_or_hash_or_contract_id: wasm_or_contract::Args, + pub wasm_or_hash_or_contract_id: contract_spec::Args, /// Where to place generated project #[arg(long)] pub output_dir: PathBuf, @@ -39,11 +39,11 @@ pub enum Error { NotUtf8(OsString), #[error(transparent)] - Spec(#[from] contract_spec::Error), + Spec(#[from] spec_tools::Error), #[error("Failed to get file name from path: {0:?}")] FailedToGetFileName(PathBuf), #[error(transparent)] - WasmOrContract(#[from] wasm_or_contract::Error), + WasmOrContract(#[from] contract_spec::Error), #[error(transparent)] Xdr(#[from] crate::xdr::Error), } @@ -60,13 +60,14 @@ impl NetworkRunnable for Cmd { ) -> Result<(), Error> { let print = Print::new(global_args.is_some_and(|a| a.quiet)); - let (spec, contract_address, network) = - wasm_or_contract::fetch_wasm(&self.wasm_or_hash_or_contract_id, &print).await?; + let contract_spec::Fetched { contract, source } = + contract_spec::fetch(&self.wasm_or_hash_or_contract_id, &print).await?; - let spec = if let Some(spec) = spec { - Spec::new(&spec)?.spec - } else { - soroban_spec::read::parse_raw(&soroban_sdk::token::StellarAssetSpec::spec_xdr())? + let spec = match contract { + contract_spec::Contract::Wasm { wasm_bytes } => Spec::new(&wasm_bytes)?.spec, + contract_spec::Contract::StellarAssetContract => { + soroban_spec::read::parse_raw(&soroban_sdk::token::StellarAssetSpec::spec_xdr())? + } }; if self.output_dir.is_file() { @@ -88,12 +89,20 @@ impl NetworkRunnable for Cmd { let contract_name = &file_name .to_str() .ok_or_else(|| Error::NotUtf8(file_name.to_os_string()))?; - if let Some(contract_address) = contract_address.clone() { - print.infoln(format!("Embedding contract address: {contract_address}")); - } + let (resolved_address, network) = match source { + contract_spec::Source::Contract { + resolved_address, + network, + } => { + print.infoln(format!("Embedding contract address: {resolved_address}")); + (Some(resolved_address), Some(network)) + } + contract_spec::Source::Wasm { network, .. } => (None, Some(network)), + contract_spec::Source::File { .. } => (None, None), + }; p.init( contract_name, - contract_address.as_deref(), + resolved_address.as_deref(), network.as_ref().map(|n| n.rpc_url.as_ref()), network.as_ref().map(|n| n.network_passphrase.as_ref()), &spec, diff --git a/cmd/soroban-cli/src/commands/contract/info/env_meta.rs b/cmd/soroban-cli/src/commands/contract/info/env_meta.rs index f882d2737..02da6f439 100644 --- a/cmd/soroban-cli/src/commands/contract/info/env_meta.rs +++ b/cmd/soroban-cli/src/commands/contract/info/env_meta.rs @@ -9,7 +9,7 @@ use crate::{ commands::{ contract::info::{ env_meta::Error::{NoEnvMetaPresent, NoSACEnvMeta}, - shared::{self, fetch_wasm, MetasInfoOutput}, + shared::{self, fetch, Fetched, MetasInfoOutput}, }, global, }, @@ -43,12 +43,12 @@ pub enum Error { impl Cmd { pub async fn run(&self, global_args: &global::Args) -> Result { let print = Print::new(global_args.quiet); - let (bytes, ..) = fetch_wasm(&self.common, &print).await?; + let Fetched { contract, .. } = fetch(&self.common, &print).await?; - let Some(bytes) = bytes else { - return Err(NoSACEnvMeta()); + let spec = match contract { + shared::Contract::Wasm { wasm_bytes } => Spec::new(&wasm_bytes)?, + shared::Contract::StellarAssetContract => return Err(NoSACEnvMeta()), }; - let spec = Spec::new(&bytes)?; let Some(env_meta_base64) = spec.env_meta_base64 else { return Err(NoEnvMetaPresent()); diff --git a/cmd/soroban-cli/src/commands/contract/info/interface.rs b/cmd/soroban-cli/src/commands/contract/info/interface.rs index dd71150fa..0c896bc3d 100644 --- a/cmd/soroban-cli/src/commands/contract/info/interface.rs +++ b/cmd/soroban-cli/src/commands/contract/info/interface.rs @@ -1,8 +1,7 @@ use std::fmt::Debug; use crate::commands::contract::info::interface::Error::NoInterfacePresent; -use crate::commands::contract::info::shared; -use crate::commands::contract::info::shared::fetch_wasm; +use crate::commands::contract::info::shared::{self, fetch, Fetched}; use crate::commands::global; use crate::print::Print; use clap::{command, Parser}; @@ -47,18 +46,21 @@ pub enum Error { impl Cmd { pub async fn run(&self, global_args: &global::Args) -> Result { let print = Print::new(global_args.quiet); - let (bytes, ..) = fetch_wasm(&self.common, &print).await?; + let Fetched { contract, .. } = fetch(&self.common, &print).await?; - let (base64, spec) = if bytes.is_none() { - Spec::spec_to_base64(&soroban_sdk::token::StellarAssetSpec::spec_xdr())? - } else { - let spec = Spec::new(&bytes.unwrap())?; + let (base64, spec) = match contract { + shared::Contract::Wasm { wasm_bytes } => { + let spec = Spec::new(&wasm_bytes)?; - if spec.env_meta_base64.is_none() { - return Err(NoInterfacePresent()); - } + if spec.env_meta_base64.is_none() { + return Err(NoInterfacePresent()); + } - (spec.spec_base64.unwrap(), spec.spec) + (spec.spec_base64.unwrap(), spec.spec) + } + shared::Contract::StellarAssetContract => { + Spec::spec_to_base64(&soroban_sdk::token::StellarAssetSpec::spec_xdr())? + } }; let res = match self.output { diff --git a/cmd/soroban-cli/src/commands/contract/info/meta.rs b/cmd/soroban-cli/src/commands/contract/info/meta.rs index 4b6fdee3e..736e8f432 100644 --- a/cmd/soroban-cli/src/commands/contract/info/meta.rs +++ b/cmd/soroban-cli/src/commands/contract/info/meta.rs @@ -1,8 +1,7 @@ use std::fmt::Debug; use crate::commands::contract::info::meta::Error::{NoMetaPresent, NoSACMeta}; -use crate::commands::contract::info::shared; -use crate::commands::contract::info::shared::{fetch_wasm, MetasInfoOutput}; +use crate::commands::contract::info::shared::{self, fetch, Fetched, MetasInfoOutput}; use crate::commands::global; use crate::print::Print; use clap::{command, Parser}; @@ -36,12 +35,12 @@ pub enum Error { impl Cmd { pub async fn run(&self, global_args: &global::Args) -> Result { let print = Print::new(global_args.quiet); - let (bytes, ..) = fetch_wasm(&self.common, &print).await?; + let Fetched { contract, .. } = fetch(&self.common, &print).await?; - let Some(bytes) = bytes else { - return Err(NoSACMeta()); + let spec = match contract { + shared::Contract::Wasm { wasm_bytes } => Spec::new(&wasm_bytes)?, + shared::Contract::StellarAssetContract => return Err(NoSACMeta()), }; - let spec = Spec::new(&bytes)?; let Some(meta_base64) = spec.meta_base64 else { return Err(NoMetaPresent()); diff --git a/cmd/soroban-cli/src/commands/contract/info/shared.rs b/cmd/soroban-cli/src/commands/contract/info/shared.rs index 2ee5d018d..6023b03cf 100644 --- a/cmd/soroban-cli/src/commands/contract/info/shared.rs +++ b/cmd/soroban-cli/src/commands/contract/info/shared.rs @@ -76,23 +76,58 @@ pub enum Error { #[error("provided wasm hash is invalid {0:?}")] InvalidWasmHash(String), #[error("must provide one of --wasm, --wasm-hash, or --contract-id")] - MalformedWasmOrWasmHashOrContractId, + MissingArg, #[error(transparent)] Rpc(#[from] soroban_rpc::Error), #[error(transparent)] Locator(#[from] locator::Error), } -pub async fn fetch_wasm( - args: &Args, - print: &Print, -) -> Result<(Option>, Option, Option), Error> { +pub struct Fetched { + pub contract: Contract, + pub source: Source, +} + +pub enum Contract { + Wasm { wasm_bytes: Vec }, + StellarAssetContract, +} + +pub enum Source { + File { + path: PathBuf, + }, + Wasm { + hash: String, + network: Network, + }, + Contract { + resolved_address: String, + network: Network, + }, +} + +impl Source { + pub fn network(&self) -> Option<&Network> { + match self { + Source::File { .. } => None, + Source::Wasm { ref network, .. } | Source::Contract { ref network, .. } => { + Some(network) + } + } + } +} + +pub async fn fetch(args: &Args, print: &Print) -> Result { // Check if a local WASM file path is provided if let Some(path) = &args.wasm { // Read the WASM file and return its contents print.infoln("Loading contract spec from file..."); let wasm_bytes = wasm::Args { wasm: path.clone() }.read()?; - return Ok((Some(wasm_bytes), None, None)); + return Ok(Fetched { + contract: Contract::Wasm { wasm_bytes }, + source: Source::File { path: path.clone() }, + }); } // If no local wasm, then check for wasm_hash and fetch from the network @@ -116,22 +151,37 @@ pub async fn fetch_wasm( print.globeln(format!( "Downloading contract spec for wasm hash: {wasm_hash}" )); - Ok(( - Some(get_remote_wasm_from_hash(&client, &hash).await?), - None, - Some(network.clone()), - )) + let wasm_bytes = get_remote_wasm_from_hash(&client, &hash).await?; + Ok(Fetched { + contract: Contract::Wasm { wasm_bytes }, + source: Source::Wasm { + hash: wasm_hash.clone(), + network: network.clone(), + }, + }) } else if let Some(contract_id) = &args.contract_id { let contract_id = contract_id.resolve_contract_id(&args.locator, &network.network_passphrase)?; - let contract_address = xdr::ScAddress::Contract(xdr::Hash(contract_id.0)).to_string(); - print.globeln(format!("Downloading contract spec: {contract_address}")); + let derived_address = xdr::ScAddress::Contract(xdr::Hash(contract_id.0)).to_string(); + print.globeln(format!("Downloading contract spec: {derived_address}")); let res = wasm::fetch_from_contract(&contract_id, network).await; if let Some(ContractIsStellarAsset) = res.as_ref().err() { - return Ok((None, Some(contract_address), Some(network.clone()))); + return Ok(Fetched { + contract: Contract::StellarAssetContract, + source: Source::Contract { + resolved_address: derived_address, + network: network.clone(), + }, + }); } - Ok((Some(res?), Some(contract_address), Some(network.clone()))) + Ok(Fetched { + contract: Contract::Wasm { wasm_bytes: res? }, + source: Source::Contract { + resolved_address: derived_address, + network: network.clone(), + }, + }) } else { - return Err(Error::MalformedWasmOrWasmHashOrContractId); + return Err(Error::MissingArg); } } From 41050c5281220bfd75da0cbef109e9c549928ce1 Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 20 Dec 2024 08:28:03 +1000 Subject: [PATCH 2/5] keys: tell the user where a key is saved (#1811) --- cmd/soroban-cli/src/commands/keys/add.rs | 16 +++++++++++----- cmd/soroban-cli/src/commands/keys/fund.rs | 15 +++++++++------ cmd/soroban-cli/src/commands/keys/generate.rs | 7 ++++++- cmd/soroban-cli/src/commands/keys/mod.rs | 4 ++-- cmd/soroban-cli/src/commands/network/add.rs | 6 +++--- cmd/soroban-cli/src/config/locator.rs | 12 ++++++++---- 6 files changed, 39 insertions(+), 21 deletions(-) diff --git a/cmd/soroban-cli/src/commands/keys/add.rs b/cmd/soroban-cli/src/commands/keys/add.rs index d8f528bae..af829fe6f 100644 --- a/cmd/soroban-cli/src/commands/keys/add.rs +++ b/cmd/soroban-cli/src/commands/keys/add.rs @@ -1,6 +1,10 @@ use clap::command; -use crate::config::{locator, secret}; +use crate::{ + commands::global, + config::{locator, secret}, + print::Print, +}; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -25,9 +29,11 @@ pub struct Cmd { } impl Cmd { - pub fn run(&self) -> Result<(), Error> { - Ok(self - .config_locator - .write_identity(&self.name, &self.secrets.read_secret()?)?) + pub fn run(&self, global_args: &global::Args) -> Result<(), Error> { + let print = Print::new(global_args.quiet); + let secret = self.secrets.read_secret()?; + let path = self.config_locator.write_identity(&self.name, &secret)?; + print.checkln(format!("Key saved with alias {:?} in {path:?}", self.name)); + Ok(()) } } diff --git a/cmd/soroban-cli/src/commands/keys/fund.rs b/cmd/soroban-cli/src/commands/keys/fund.rs index d7100c6cb..2419c4be2 100644 --- a/cmd/soroban-cli/src/commands/keys/fund.rs +++ b/cmd/soroban-cli/src/commands/keys/fund.rs @@ -1,6 +1,6 @@ use clap::command; -use crate::config::network; +use crate::{commands::global, config::network, print::Print}; use super::address; @@ -23,12 +23,15 @@ pub struct Cmd { } impl Cmd { - pub async fn run(&self) -> Result<(), Error> { + pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> { + let print = Print::new(global_args.quiet); let addr = self.address.public_key()?; - self.network - .get(&self.address.locator)? - .fund_address(&addr) - .await?; + let network = self.network.get(&self.address.locator)?; + network.fund_address(&addr).await?; + print.checkln(format!( + "Account {:?} funded on {:?}", + self.address.name, network.network_passphrase + )); Ok(()) } } diff --git a/cmd/soroban-cli/src/commands/keys/generate.rs b/cmd/soroban-cli/src/commands/keys/generate.rs index c6623386c..fda6a3d98 100644 --- a/cmd/soroban-cli/src/commands/keys/generate.rs +++ b/cmd/soroban-cli/src/commands/keys/generate.rs @@ -96,7 +96,8 @@ impl Cmd { seed_phrase }; - self.config_locator.write_identity(&self.name, &secret)?; + let path = self.config_locator.write_identity(&self.name, &secret)?; + print.checkln(format!("Key saved with alias {:?} in {path:?}", self.name)); if !self.no_fund { let addr = secret.public_key(self.hd_path)?; @@ -108,6 +109,10 @@ impl Cmd { tracing::warn!("fund_address failed: {e}"); }) .unwrap_or_default(); + print.checkln(format!( + "Account {:?} funded on {:?}", + self.name, network.network_passphrase + )); } Ok(()) diff --git a/cmd/soroban-cli/src/commands/keys/mod.rs b/cmd/soroban-cli/src/commands/keys/mod.rs index 8729ee9af..e5409ce37 100644 --- a/cmd/soroban-cli/src/commands/keys/mod.rs +++ b/cmd/soroban-cli/src/commands/keys/mod.rs @@ -70,9 +70,9 @@ pub enum Error { impl Cmd { pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> { match self { - Cmd::Add(cmd) => cmd.run()?, + Cmd::Add(cmd) => cmd.run(global_args)?, Cmd::Address(cmd) => cmd.run()?, - Cmd::Fund(cmd) => cmd.run().await?, + Cmd::Fund(cmd) => cmd.run(global_args).await?, Cmd::Generate(cmd) => cmd.run(global_args).await?, Cmd::Ls(cmd) => cmd.run()?, Cmd::Rm(cmd) => cmd.run()?, diff --git a/cmd/soroban-cli/src/commands/network/add.rs b/cmd/soroban-cli/src/commands/network/add.rs index 20b1afa7b..feeea9030 100644 --- a/cmd/soroban-cli/src/commands/network/add.rs +++ b/cmd/soroban-cli/src/commands/network/add.rs @@ -25,8 +25,8 @@ pub struct Cmd { impl Cmd { pub fn run(&self) -> Result<(), Error> { - Ok(self - .config_locator - .write_network(&self.name, &self.network)?) + self.config_locator + .write_network(&self.name, &self.network)?; + Ok(()) } } diff --git a/cmd/soroban-cli/src/config/locator.rs b/cmd/soroban-cli/src/config/locator.rs index b6f5c75c1..7e97f6796 100644 --- a/cmd/soroban-cli/src/config/locator.rs +++ b/cmd/soroban-cli/src/config/locator.rs @@ -162,11 +162,11 @@ impl Args { ) } - pub fn write_identity(&self, name: &str, secret: &Secret) -> Result<(), Error> { + pub fn write_identity(&self, name: &str, secret: &Secret) -> Result { KeyType::Identity.write(name, secret, &self.config_dir()?) } - pub fn write_network(&self, name: &str, network: &Network) -> Result<(), Error> { + pub fn write_network(&self, name: &str, network: &Network) -> Result { KeyType::Network.write(name, network, &self.config_dir()?) } @@ -441,10 +441,14 @@ impl KeyType { key: &str, value: &T, pwd: &Path, - ) -> Result<(), Error> { + ) -> Result { let filepath = ensure_directory(self.path(pwd, key))?; let data = toml::to_string(value).map_err(|_| Error::ConfigSerialization)?; - std::fs::write(&filepath, data).map_err(|error| Error::IdCreationFailed { filepath, error }) + std::fs::write(&filepath, data).map_err(|error| Error::IdCreationFailed { + filepath: filepath.clone(), + error, + })?; + Ok(filepath) } fn root(&self, pwd: &Path) -> PathBuf { From 2790dc15191743699eabd7b0c9288381bf579eee Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 20 Dec 2024 10:15:48 +1000 Subject: [PATCH 3/5] keys: rename `show` to `secret` (#1807) --- FULL_HELP_DOCS.md | 8 ++++---- .../soroban-spec-typescript/ts-tests/src/util.ts | 2 +- cmd/crates/soroban-test/src/lib.rs | 2 +- cmd/crates/soroban-test/tests/it/config.rs | 4 ++-- .../soroban-test/tests/it/integration/hello_world.rs | 6 +++--- cmd/soroban-cli/src/commands/keys/mod.rs | 10 +++++----- .../src/commands/keys/{show.rs => secret.rs} | 1 + 7 files changed, 17 insertions(+), 16 deletions(-) rename cmd/soroban-cli/src/commands/keys/{show.rs => secret.rs} (95%) diff --git a/FULL_HELP_DOCS.md b/FULL_HELP_DOCS.md index fd1281cf1..208ec1e84 100644 --- a/FULL_HELP_DOCS.md +++ b/FULL_HELP_DOCS.md @@ -944,7 +944,7 @@ Create and manage identities including keys and addresses * `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 +* `secret` — Output an identity's secret key * `use` — Set the default identity that will be used on all commands. This allows you to skip `--source-account` or setting a environment variable, while reusing this value in all commands that require it @@ -1069,11 +1069,11 @@ Remove an identity -## `stellar keys show` +## `stellar keys secret` -Given an identity return its private key +Output an identity's secret key -**Usage:** `stellar keys show [OPTIONS] ` +**Usage:** `stellar keys secret [OPTIONS] ` ###### **Arguments:** diff --git a/cmd/crates/soroban-spec-typescript/ts-tests/src/util.ts b/cmd/crates/soroban-spec-typescript/ts-tests/src/util.ts index 15649b63e..eacedbaec 100644 --- a/cmd/crates/soroban-spec-typescript/ts-tests/src/util.ts +++ b/cmd/crates/soroban-spec-typescript/ts-tests/src/util.ts @@ -3,7 +3,7 @@ import { Address, Keypair } from "@stellar/stellar-sdk"; import { basicNodeSigner } from "@stellar/stellar-sdk/contract"; const rootKeypair = Keypair.fromSecret( - spawnSync("./stellar", ["keys", "show", "root"], { + spawnSync("./soroban", ["keys", "secret", "root"], { shell: true, encoding: "utf8", }).stdout.trim(), diff --git a/cmd/crates/soroban-test/src/lib.rs b/cmd/crates/soroban-test/src/lib.rs index 2c62578ef..492d3bb97 100644 --- a/cmd/crates/soroban-test/src/lib.rs +++ b/cmd/crates/soroban-test/src/lib.rs @@ -285,7 +285,7 @@ impl TestEnv { /// Returns the private key corresponding to the test keys's `hd_path` pub fn test_show(&self, hd_path: usize) -> String { - self.cmd::(&format!("--hd-path={hd_path}")) + self.cmd::(&format!("--hd-path={hd_path}")) .private_key() .unwrap() .to_string() diff --git a/cmd/crates/soroban-test/tests/it/config.rs b/cmd/crates/soroban-test/tests/it/config.rs index b796910a8..e81233b6e 100644 --- a/cmd/crates/soroban-test/tests/it/config.rs +++ b/cmd/crates/soroban-test/tests/it/config.rs @@ -283,7 +283,7 @@ fn use_env() { sandbox .new_assert_cmd("keys") - .arg("show") + .arg("secret") .arg("bob") .assert() .success() @@ -330,7 +330,7 @@ fn config_dirs_precedence() { sandbox .new_assert_cmd("keys") - .arg("show") + .arg("secret") .arg("alice") .arg("--verbose") .assert() diff --git a/cmd/crates/soroban-test/tests/it/integration/hello_world.rs b/cmd/crates/soroban-test/tests/it/integration/hello_world.rs index b9ed0196f..4464e532f 100644 --- a/cmd/crates/soroban-test/tests/it/integration/hello_world.rs +++ b/cmd/crates/soroban-test/tests/it/integration/hello_world.rs @@ -53,7 +53,7 @@ async fn invoke() { let secret_key = sandbox .new_assert_cmd("keys") - .arg("show") + .arg("secret") .arg("test") .assert() .stdout_as_str(); @@ -65,7 +65,7 @@ async fn invoke() { .stdout_as_str(); let secret_key_1 = sandbox .new_assert_cmd("keys") - .arg("show") + .arg("secret") .arg("test") .arg("--hd-path=1") .assert() @@ -115,7 +115,7 @@ async fn invoke() { assert_eq!(sk_from_file, format!("secret_key = \"{secret_key_1}\"\n")); let secret_key_1_readin = sandbox .new_assert_cmd("keys") - .arg("show") + .arg("secret") .arg("testone") .assert() .stdout_as_str(); diff --git a/cmd/soroban-cli/src/commands/keys/mod.rs b/cmd/soroban-cli/src/commands/keys/mod.rs index e5409ce37..b5520abf6 100644 --- a/cmd/soroban-cli/src/commands/keys/mod.rs +++ b/cmd/soroban-cli/src/commands/keys/mod.rs @@ -8,7 +8,7 @@ pub mod fund; pub mod generate; pub mod ls; pub mod rm; -pub mod show; +pub mod secret; #[derive(Debug, Parser)] pub enum Cmd { @@ -30,8 +30,8 @@ pub enum Cmd { /// Remove an identity Rm(rm::Cmd), - /// Given an identity return its private key - Show(show::Cmd), + /// Output an identity's secret key + Secret(secret::Cmd), /// Set the default identity that will be used on all commands. /// This allows you to skip `--source-account` or setting a environment @@ -61,7 +61,7 @@ pub enum Error { Ls(#[from] ls::Error), #[error(transparent)] - Show(#[from] show::Error), + Show(#[from] secret::Error), #[error(transparent)] Default(#[from] default::Error), @@ -76,7 +76,7 @@ impl Cmd { Cmd::Generate(cmd) => cmd.run(global_args).await?, Cmd::Ls(cmd) => cmd.run()?, Cmd::Rm(cmd) => cmd.run()?, - Cmd::Show(cmd) => cmd.run()?, + Cmd::Secret(cmd) => cmd.run()?, Cmd::Default(cmd) => cmd.run(global_args)?, }; Ok(()) diff --git a/cmd/soroban-cli/src/commands/keys/show.rs b/cmd/soroban-cli/src/commands/keys/secret.rs similarity index 95% rename from cmd/soroban-cli/src/commands/keys/show.rs rename to cmd/soroban-cli/src/commands/keys/secret.rs index 58c47740c..d28445247 100644 --- a/cmd/soroban-cli/src/commands/keys/show.rs +++ b/cmd/soroban-cli/src/commands/keys/secret.rs @@ -16,6 +16,7 @@ pub enum Error { #[derive(Debug, clap::Parser, Clone)] #[group(skip)] +#[command(name = "secret", alias = "show")] pub struct Cmd { /// Name of identity to lookup, default is test identity pub name: String, From a5f02595a434e168c443fbb7147264a6e180821b Mon Sep 17 00:00:00 2001 From: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> Date: Fri, 20 Dec 2024 18:39:35 +1000 Subject: [PATCH 4/5] keys: valid keys when added (#1812) Co-authored-by: Willem Wyndham Co-authored-by: Elizabeth Engelman <4752801+elizabethengelman@users.noreply.github.com> --- FULL_HELP_DOCS.md | 4 +-- cmd/soroban-cli/src/config/secret.rs | 45 ++++++++-------------------- 2 files changed, 14 insertions(+), 35 deletions(-) diff --git a/FULL_HELP_DOCS.md b/FULL_HELP_DOCS.md index 208ec1e84..6b67e32a0 100644 --- a/FULL_HELP_DOCS.md +++ b/FULL_HELP_DOCS.md @@ -961,8 +961,8 @@ Add a new identity (keypair, ledger, macOS keychain) ###### **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` +* `--secret-key` — (deprecated) Enter secret (S) key when prompted +* `--seed-phrase` — (deprecated) Enter key using 12-24 word seed phrase * `--global` — Use global config * `--config-dir ` — Location of config directory, default is "." diff --git a/cmd/soroban-cli/src/config/secret.rs b/cmd/soroban-cli/src/config/secret.rs index d6de1b6ea..00cec12f6 100644 --- a/cmd/soroban-cli/src/config/secret.rs +++ b/cmd/soroban-cli/src/config/secret.rs @@ -11,8 +11,6 @@ use crate::{ #[derive(thiserror::Error, Debug)] pub enum Error { - #[error("invalid secret key")] - InvalidSecretKey, // #[error("seed_phrase must be 12 words long, found {len}")] // InvalidSeedPhrase { len: usize }, #[error("secret input error")] @@ -23,8 +21,8 @@ pub enum Error { SeedPhrase(#[from] sep5::error::Error), #[error(transparent)] Ed25519(#[from] ed25519_dalek::SignatureError), - #[error("Invalid address {0}")] - InvalidAddress(String), + #[error("cannot parse secret (S) or seed phrase (12 or 24 word)")] + InvalidSecretOrSeedPhrase, #[error(transparent)] Signer(#[from] signer::Error), } @@ -32,12 +30,11 @@ pub enum Error { #[derive(Debug, clap::Args, Clone)] #[group(skip)] pub struct Args { - /// Add using `secret_key` - /// Can provide with `SOROBAN_SECRET_KEY` - #[arg(long, conflicts_with = "seed_phrase")] + /// (deprecated) Enter secret (S) key when prompted + #[arg(long)] pub secret_key: bool, - /// Add using 12 word seed phrase to generate `secret_key` - #[arg(long, conflicts_with = "secret_key")] + /// (deprecated) Enter key using 12-24 word seed phrase + #[arg(long)] pub seed_phrase: bool, } @@ -45,30 +42,12 @@ impl Args { pub fn read_secret(&self) -> Result { if let Ok(secret_key) = std::env::var("SOROBAN_SECRET_KEY") { Ok(Secret::SecretKey { secret_key }) - } else if self.secret_key { - println!("Type a secret key: "); - let secret_key = read_password()?; - let secret_key = PrivateKey::from_string(&secret_key) - .map_err(|_| Error::InvalidSecretKey)? - .to_string(); - Ok(Secret::SecretKey { secret_key }) - } else if self.seed_phrase { - println!("Type a 12 word seed phrase: "); - let seed_phrase = read_password()?; - let seed_phrase: Vec<&str> = seed_phrase.split_whitespace().collect(); - // if seed_phrase.len() != 12 { - // let len = seed_phrase.len(); - // return Err(Error::InvalidSeedPhrase { len }); - // } - Ok(Secret::SeedPhrase { - seed_phrase: seed_phrase - .into_iter() - .map(ToString::to_string) - .collect::>() - .join(" "), - }) } else { - Err(Error::PasswordRead {}) + println!("Type a secret key or 12/24 word seed phrase:"); + let secret_key = read_password()?; + secret_key + .parse() + .map_err(|_| Error::InvalidSecretOrSeedPhrase) } } } @@ -93,7 +72,7 @@ impl FromStr for Secret { seed_phrase: s.to_string(), }) } else { - Err(Error::InvalidAddress(s.to_string())) + Err(Error::InvalidSecretOrSeedPhrase) } } } From 1c0d4e6e528452d7a7d020ef12ce39e475434f4a Mon Sep 17 00:00:00 2001 From: Elizabeth Engelman <4752801+elizabethengelman@users.noreply.github.com> Date: Fri, 20 Dec 2024 13:00:39 -0500 Subject: [PATCH 5/5] Fix/rpc header (#1799) * Use network.rpc_client() to get a contract's spec this will make sure that we're adding the necessary rpc provider headers, if they are required for the given provider * Use self.rpc_client() in network for creating a new rpc client * Refactor TestEnv to have a network field * Test that rpc_headers are being passed on rpc provider requests * Fix operations int test * Clippy * Add CC-1.0 to allowed licenses in deny.toml https://stellarfoundation.slack.com/archives/C92PPVBPT/p1734657921992129 * fix * Use workspace httpmock dep also - move soroban-test httpmock dep to dev-dependencies - use workspace dep for stellar-ledger test --------- Co-authored-by: Leigh McCulloch <351529+leighmcculloch@users.noreply.github.com> --- Cargo.lock | 1 + Cargo.toml | 1 + cmd/crates/soroban-test/Cargo.toml | 2 +- cmd/crates/soroban-test/src/lib.rs | 45 ++++++--- .../tests/it/integration/bindings.rs | 4 +- .../tests/it/integration/hello_world.rs | 4 +- .../tests/it/integration/tx/operations.rs | 24 ++--- cmd/crates/soroban-test/tests/it/main.rs | 1 + .../soroban-test/tests/it/rpc_provider.rs | 97 +++++++++++++++++++ cmd/crates/stellar-ledger/Cargo.toml | 2 +- cmd/soroban-cli/src/config/network.rs | 2 +- cmd/soroban-cli/src/get_spec.rs | 2 +- deny.toml | 1 + 13 files changed, 155 insertions(+), 31 deletions(-) create mode 100644 cmd/crates/soroban-test/tests/it/rpc_provider.rs diff --git a/Cargo.lock b/Cargo.lock index cbe1678d6..d69fbaa51 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4601,6 +4601,7 @@ dependencies = [ "ed25519-dalek", "fs_extra", "hex", + "httpmock", "predicates", "sep5", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index 839ca9cd0..702de93c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -105,6 +105,7 @@ toml_edit = "0.22.20" toml = "0.8.19" reqwest = "0.12.7" predicates = "3.1.2" +httpmock = "0.7.0" [profile.test-wasms] inherits = "release" diff --git a/cmd/crates/soroban-test/Cargo.toml b/cmd/crates/soroban-test/Cargo.toml index d035652d1..ddb10d5f7 100644 --- a/cmd/crates/soroban-test/Cargo.toml +++ b/cmd/crates/soroban-test/Cargo.toml @@ -33,7 +33,6 @@ predicates = { workspace = true } fs_extra = "1.3.0" toml = { workspace = true } - [dev-dependencies] serde_json = "1.0.93" which = { workspace = true } @@ -42,6 +41,7 @@ walkdir = "2.4.0" ulid.workspace = true ed25519-dalek = { workspace = true } hex = { workspace = true } +httpmock = { workspace = true } [features] it = [] diff --git a/cmd/crates/soroban-test/src/lib.rs b/cmd/crates/soroban-test/src/lib.rs index 492d3bb97..4f36a0b33 100644 --- a/cmd/crates/soroban-test/src/lib.rs +++ b/cmd/crates/soroban-test/src/lib.rs @@ -58,8 +58,7 @@ pub enum Error { /// its own `TempDir` where it will save test-specific configuration. pub struct TestEnv { pub temp_dir: TempDir, - pub rpc_url: String, - pub network_passphrase: String, + pub network: network::Network, } impl Default for TestEnv { @@ -67,8 +66,11 @@ impl Default for TestEnv { let temp_dir = TempDir::new().unwrap(); Self { temp_dir, - rpc_url: "http://localhost:8889/soroban/rpc".to_string(), - network_passphrase: LOCAL_NETWORK_PASSPHRASE.to_string(), + network: network::Network { + rpc_url: "http://localhost:8889/soroban/rpc".to_string(), + network_passphrase: LOCAL_NETWORK_PASSPHRASE.to_string(), + rpc_headers: [].to_vec(), + }, } } } @@ -102,12 +104,21 @@ impl TestEnv { } pub fn with_rpc_url(rpc_url: &str) -> TestEnv { - let mut env = TestEnv { - rpc_url: rpc_url.to_string(), - ..Default::default() + let mut env = TestEnv::default(); + env.network.rpc_url = rpc_url.to_string(); + if let Ok(network_passphrase) = std::env::var("STELLAR_NETWORK_PASSPHRASE") { + env.network.network_passphrase = network_passphrase; }; + env.generate_account("test", None).assert().success(); + env + } + + pub fn with_rpc_provider(rpc_url: &str, rpc_headers: Vec<(String, String)>) -> TestEnv { + let mut env = TestEnv::default(); + env.network.rpc_url = rpc_url.to_string(); + env.network.rpc_headers = rpc_headers; if let Ok(network_passphrase) = std::env::var("STELLAR_NETWORK_PASSPHRASE") { - env.network_passphrase = network_passphrase; + env.network.network_passphrase = network_passphrase; }; env.generate_account("test", None).assert().success(); env @@ -131,13 +142,25 @@ impl TestEnv { /// to be the internal `temp_dir`. pub fn new_assert_cmd(&self, subcommand: &str) -> Command { let mut cmd: Command = self.bin(); + cmd.arg(subcommand) .env("SOROBAN_ACCOUNT", TEST_ACCOUNT) - .env("SOROBAN_RPC_URL", &self.rpc_url) + .env("SOROBAN_RPC_URL", &self.network.rpc_url) .env("SOROBAN_NETWORK_PASSPHRASE", LOCAL_NETWORK_PASSPHRASE) .env("XDG_CONFIG_HOME", self.temp_dir.join("config").as_os_str()) .env("XDG_DATA_HOME", self.temp_dir.join("data").as_os_str()) .current_dir(&self.temp_dir); + + if !self.network.rpc_headers.is_empty() { + cmd.env( + "STELLAR_RPC_HEADERS", + format!( + "{}:{}", + &self.network.rpc_headers[0].0, &self.network.rpc_headers[0].1 + ), + ); + } + cmd } @@ -234,7 +257,7 @@ impl TestEnv { let config_dir = Some(self.dir().to_path_buf()); config::Args { network: network::Args { - rpc_url: Some(self.rpc_url.clone()), + rpc_url: Some(self.network.rpc_url.clone()), rpc_headers: [].to_vec(), network_passphrase: Some(LOCAL_NETWORK_PASSPHRASE.to_string()), network: None, @@ -305,7 +328,7 @@ impl TestEnv { } pub fn client(&self) -> soroban_rpc::Client { - soroban_rpc::Client::new(&self.rpc_url).unwrap() + self.network.rpc_client().unwrap() } } diff --git a/cmd/crates/soroban-test/tests/it/integration/bindings.rs b/cmd/crates/soroban-test/tests/it/integration/bindings.rs index feb7f2ef8..4080cc110 100644 --- a/cmd/crates/soroban-test/tests/it/integration/bindings.rs +++ b/cmd/crates/soroban-test/tests/it/integration/bindings.rs @@ -13,7 +13,7 @@ async fn invoke_test_generate_typescript_bindings() { "--network-passphrase", LOCAL_NETWORK_PASSPHRASE, "--rpc-url", - &sandbox.rpc_url, + &sandbox.network.rpc_url, "--output-dir", &outdir.display().to_string(), "--overwrite", @@ -43,7 +43,7 @@ async fn invoke_test_bindings_context_failure() { "--network-passphrase", LOCAL_NETWORK_PASSPHRASE, "--rpc-url", - &sandbox.rpc_url, + &sandbox.network.rpc_url, "--output-dir", &outdir.display().to_string(), "--overwrite", diff --git a/cmd/crates/soroban-test/tests/it/integration/hello_world.rs b/cmd/crates/soroban-test/tests/it/integration/hello_world.rs index 4464e532f..e63fdd4b4 100644 --- a/cmd/crates/soroban-test/tests/it/integration/hello_world.rs +++ b/cmd/crates/soroban-test/tests/it/integration/hello_world.rs @@ -27,7 +27,7 @@ async fn invoke_view_with_non_existent_source_account() { #[allow(clippy::too_many_lines)] async fn invoke() { let sandbox = &TestEnv::new(); - let c = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let c = sandbox.network.rpc_client().unwrap(); let GetLatestLedgerResponse { sequence, .. } = c.get_latest_ledger().await.unwrap(); sandbox .new_assert_cmd("keys") @@ -365,7 +365,7 @@ async fn fetch(sandbox: &TestEnv, id: &str) { let f = sandbox.dir().join("contract.wasm"); let cmd = sandbox.cmd_arr::(&[ "--rpc-url", - &sandbox.rpc_url, + &sandbox.network.rpc_url, "--network-passphrase", LOCAL_NETWORK_PASSPHRASE, "--id", diff --git a/cmd/crates/soroban-test/tests/it/integration/tx/operations.rs b/cmd/crates/soroban-test/tests/it/integration/tx/operations.rs index 1ce1f06c9..d9bc2ac63 100644 --- a/cmd/crates/soroban-test/tests/it/integration/tx/operations.rs +++ b/cmd/crates/soroban-test/tests/it/integration/tx/operations.rs @@ -66,7 +66,7 @@ async fn create_account() { .success() .stdout_as_str(); let test = test_address(sandbox); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let test_account = client.get_account(&test).await.unwrap(); println!("test account has a balance of {}", test_account.balance); let starting_balance = ONE_XLM * 100; @@ -92,7 +92,7 @@ async fn create_account() { #[tokio::test] async fn payment() { let sandbox = &TestEnv::new(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let (test, test1) = setup_accounts(sandbox); let test_account = client.get_account(&test).await.unwrap(); println!("test account has a balance of {}", test_account.balance); @@ -125,7 +125,7 @@ async fn payment() { #[tokio::test] async fn bump_sequence() { let sandbox = &TestEnv::new(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let test = test_address(sandbox); let before = client.get_account(&test).await.unwrap(); let amount = 50; @@ -148,7 +148,7 @@ async fn bump_sequence() { #[tokio::test] async fn account_merge() { let sandbox = &TestEnv::new(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let (test, test1) = setup_accounts(sandbox); let before = client.get_account(&test).await.unwrap(); let before1 = client.get_account(&test1).await.unwrap(); @@ -188,7 +188,7 @@ async fn set_trustline_flags() { .success(); let id = contract_id_hash_from_asset( asset.parse::().unwrap(), - &sandbox.network_passphrase, + &sandbox.network.network_passphrase, ); // sandbox // .new_assert_cmd("contract") @@ -224,7 +224,7 @@ async fn set_trustline_flags() { #[tokio::test] async fn set_options_add_signer() { let sandbox = &TestEnv::new(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let (test, test1) = setup_accounts(sandbox); let before = client.get_account(&test).await.unwrap(); sandbox @@ -286,7 +286,7 @@ fn build_and_run(sandbox: &TestEnv, cmd: &str, args: &[&str]) -> String { #[tokio::test] async fn set_options() { let sandbox = &TestEnv::new(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let (test, alice) = setup_accounts(sandbox); let before = client.get_account(&test).await.unwrap(); assert!(before.inflation_dest.is_none()); @@ -356,7 +356,7 @@ async fn set_options() { #[tokio::test] async fn set_some_options() { let sandbox = &TestEnv::new(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let test = test_address(sandbox); let before = client.get_account(&test).await.unwrap(); assert!(before.inflation_dest.is_none()); @@ -451,7 +451,7 @@ async fn change_trust() { // wrap_cmd(&asset).run().await.unwrap(); let id = contract_id_hash_from_asset( asset.parse::().unwrap(), - &sandbox.network_passphrase, + &sandbox.network.network_passphrase, ); sandbox .new_assert_cmd("contract") @@ -529,7 +529,7 @@ async fn change_trust() { async fn manage_data() { let sandbox = &TestEnv::new(); let (test, _) = setup_accounts(sandbox); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let key = "test"; let value = "beefface"; sandbox @@ -573,7 +573,7 @@ async fn manage_data() { } async fn issue_asset(sandbox: &TestEnv, test: &str, asset: &str, limit: u64, initial_balance: u64) { - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let test_before = client.get_account(test).await.unwrap(); sandbox .new_assert_cmd("tx") @@ -633,7 +633,7 @@ async fn issue_asset(sandbox: &TestEnv, test: &str, asset: &str, limit: u64, ini #[tokio::test] async fn multi_create_accounts() { let sandbox = &TestEnv::new(); - let client = soroban_rpc::Client::new(&sandbox.rpc_url).unwrap(); + let client = sandbox.network.rpc_client().unwrap(); let nums: Vec = (1..=3).collect(); let mut accounts: Vec<(String, String)> = nums .iter() diff --git a/cmd/crates/soroban-test/tests/it/main.rs b/cmd/crates/soroban-test/tests/it/main.rs index e06c1a47d..4dc54a194 100644 --- a/cmd/crates/soroban-test/tests/it/main.rs +++ b/cmd/crates/soroban-test/tests/it/main.rs @@ -6,5 +6,6 @@ mod init; // #[cfg(feature = "it")] mod integration; mod plugin; +mod rpc_provider; mod util; mod version; diff --git a/cmd/crates/soroban-test/tests/it/rpc_provider.rs b/cmd/crates/soroban-test/tests/it/rpc_provider.rs new file mode 100644 index 000000000..04c4c1bdc --- /dev/null +++ b/cmd/crates/soroban-test/tests/it/rpc_provider.rs @@ -0,0 +1,97 @@ +use httpmock::{prelude::*, Mock}; +use serde_json::json; +use soroban_rpc::{GetEventsResponse, GetNetworkResponse}; +use soroban_test::{TestEnv, LOCAL_NETWORK_PASSPHRASE}; + +#[tokio::test] +async fn test_use_rpc_provider_with_auth_header() { + // mock out http request to rpc provider + let server = MockServer::start(); + let generate_account_mock = mock_generate_account(&server); + let get_network_mock = mock_get_network(&server); + let get_events_mock = mock_get_events(&server); + + // create a new test environment with the mock server + let rpc_url = server.url(""); + let rpc_headers = vec![("Authorization".to_string(), "Bearer test-token".to_string())]; + let sandbox = &TestEnv::with_rpc_provider(&rpc_url, rpc_headers); + + sandbox + .new_assert_cmd("events") + .arg("--start-ledger") + .arg("1000") + .assert() + .success(); + + // generate account is being called in `with_rpc_provider` + generate_account_mock.assert(); + // get_network and get_events are being called in the `stellar events` command + get_network_mock.assert(); + get_events_mock.assert(); +} + +fn mock_generate_account(server: &MockServer) -> Mock { + server.mock(|when, then| { + when.method(GET) + .path("/friendbot") + .header("accept", "*/*") + .header("user-agent", "soroban-cli/22.0.1"); //update this to be future proof + then.status(200); + }) +} + +fn mock_get_network(server: &MockServer) -> Mock { + server.mock(|when, then| { + when.method(POST) + .path("/") + .header("authorization", "Bearer test-token") + .json_body(json!({ + "jsonrpc": "2.0", + "id": 0, + "method": "getNetwork" + })); + + then.status(200).json_body(json!({ + "jsonrpc": "2.0", + "id": 0, + "result": GetNetworkResponse { + friendbot_url: None, + passphrase: LOCAL_NETWORK_PASSPHRASE.to_string(), + protocol_version: 22} + })); + }) +} + +fn mock_get_events(server: &MockServer) -> Mock { + server.mock(|when, then| { + when.method(POST) + .path("/") + .header("authorization", "Bearer test-token") + .json_body(json!({ + "jsonrpc": "2.0", + "id": 1, + "method": "getEvents", + "params": { + "startLedger": 1000, + "filters": [ + { + "contractIds": [], + "topics": [] + } + ], + "pagination": { + "limit": 10 + } + } + })); + + then.status(200).json_body(json!({ + "jsonrpc": "2.0", + "id": 1, + "result": GetEventsResponse { + events: vec![], + latest_ledger: 1000 + } + })); + }) +} diff --git a/cmd/crates/stellar-ledger/Cargo.toml b/cmd/crates/stellar-ledger/Cargo.toml index b3d6318a4..f06d17a2b 100644 --- a/cmd/crates/stellar-ledger/Cargo.toml +++ b/cmd/crates/stellar-ledger/Cargo.toml @@ -51,7 +51,7 @@ log = "0.4.21" once_cell = "1.19.0" pretty_assertions = "1.2.1" serial_test = "3.0.0" -httpmock = "0.7.0-rc.1" +httpmock = { workspace = true } test-case = "3.3.1" testcontainers = "0.20.1" diff --git a/cmd/soroban-cli/src/config/network.rs b/cmd/soroban-cli/src/config/network.rs index 829716753..e64a0ee77 100644 --- a/cmd/soroban-cli/src/config/network.rs +++ b/cmd/soroban-cli/src/config/network.rs @@ -170,7 +170,7 @@ impl Network { local_url.set_query(Some(&format!("addr={addr}"))); Ok(local_url) } else { - let client = Client::new(&self.rpc_url)?; + let client = self.rpc_client()?; let network = client.get_network().await?; tracing::debug!("network {network:?}"); let url = client.friendbot_url().await?; diff --git a/cmd/soroban-cli/src/get_spec.rs b/cmd/soroban-cli/src/get_spec.rs index 26e609543..f2da15863 100644 --- a/cmd/soroban-cli/src/get_spec.rs +++ b/cmd/soroban-cli/src/get_spec.rs @@ -44,7 +44,7 @@ pub async fn get_remote_contract_spec( |c| c.get_network().map_err(Error::from), )?; tracing::trace!(?network); - let client = rpc::Client::new(&network.rpc_url)?; + let client = network.rpc_client()?; // Get contract data let r = client.get_contract_data(contract_id).await?; tracing::trace!("{r:?}"); diff --git a/deny.toml b/deny.toml index 9817c3e79..600bfec02 100644 --- a/deny.toml +++ b/deny.toml @@ -110,6 +110,7 @@ allow = [ "Unicode-DFS-2016", "ISC", "BSD-2-Clause", + "CC0-1.0", ] # List of explicitly disallowed licenses # See https://spdx.org/licenses/ for list of possible licenses