diff --git a/Cargo.lock b/Cargo.lock index e043b4f8e2..9ffab2eb45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4599,6 +4599,7 @@ dependencies = [ "assert_cmd", "assert_fs", "ed25519-dalek", + "either", "fs_extra", "hex", "predicates", diff --git a/cmd/crates/soroban-test/Cargo.toml b/cmd/crates/soroban-test/Cargo.toml index f694ec533c..3d137d1588 100644 --- a/cmd/crates/soroban-test/Cargo.toml +++ b/cmd/crates/soroban-test/Cargo.toml @@ -25,6 +25,7 @@ sep5 = { workspace = true } soroban-cli = { workspace = true } soroban-rpc = { workspace = true } +either = "1.13.0" thiserror = "1.0.31" sha2 = "0.10.6" assert_cmd = "2.0.4" diff --git a/cmd/crates/soroban-test/src/lib.rs b/cmd/crates/soroban-test/src/lib.rs index 2c62578ef5..3a16b63ca0 100644 --- a/cmd/crates/soroban-test/src/lib.rs +++ b/cmd/crates/soroban-test/src/lib.rs @@ -27,6 +27,7 @@ use std::{ffi::OsString, fmt::Display, path::Path}; use assert_cmd::{assert::Assert, Command}; use assert_fs::{fixture::FixtureError, prelude::PathChild, TempDir}; +use either::Either; use fs_extra::dir::CopyOptions; use soroban_cli::{ @@ -202,9 +203,10 @@ impl TestEnv { source: &str, ) -> Result { let cmd = self.cmd_with_config::(command_str, None); - self.run_cmd_with(cmd, source) - .await - .map(|r| r.into_result().unwrap()) + self.run_cmd_with(cmd, source).await.map(|r| match r { + Either::Left(help) => help, + Either::Right(tx) => tx.into_result().unwrap(), + }) } /// A convenience method for using the invoke command. diff --git a/cmd/crates/soroban-test/tests/fixtures/workspace/Cargo.lock b/cmd/crates/soroban-test/tests/fixtures/workspace/Cargo.lock index cc4bfbb58d..fb7a3d15c2 100644 --- a/cmd/crates/soroban-test/tests/fixtures/workspace/Cargo.lock +++ b/cmd/crates/soroban-test/tests/fixtures/workspace/Cargo.lock @@ -355,7 +355,6 @@ dependencies = [ "elliptic-curve", "rfc6979", "signature", - "spki", ] [[package]] @@ -370,15 +369,16 @@ dependencies = [ [[package]] name = "ed25519-dalek" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", "rand_core", "serde", "sha2", + "subtle", "zeroize", ] @@ -400,7 +400,6 @@ dependencies = [ "ff", "generic-array", "group", - "pkcs8", "rand_core", "sec1", "subtle", @@ -614,9 +613,7 @@ dependencies = [ "cfg-if", "ecdsa", "elliptic-curve", - "once_cell", "sha2", - "signature", ] [[package]] @@ -717,6 +714,18 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "paste" version = "1.0.14" @@ -761,6 +770,15 @@ dependencies = [ "syn", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro2" version = "1.0.69" @@ -849,7 +867,6 @@ dependencies = [ "base16ct", "der", "generic-array", - "pkcs8", "subtle", "zeroize", ] @@ -959,9 +976,9 @@ checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" [[package]] name = "soroban-builtin-sdk-macros" -version = "20.3.0" +version = "21.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc32c6e817f3ca269764ec0d7d14da6210b74a5bf14d4e745aa3ee860558900" +checksum = "2f57a68ef8777e28e274de0f3a88ad9a5a41d9a2eb461b4dd800b086f0e83b80" dependencies = [ "itertools", "proc-macro2", @@ -971,9 +988,9 @@ dependencies = [ [[package]] name = "soroban-env-common" -version = "20.3.0" +version = "21.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c14e18d879c520ff82612eaae0590acaf6a7f3b977407e1abb1c9e31f94c7814" +checksum = "2fd1c89463835fe6da996318156d39f424b4f167c725ec692e5a7a2d4e694b3d" dependencies = [ "arbitrary", "crate-git-revision", @@ -985,13 +1002,14 @@ dependencies = [ "soroban-wasmi", "static_assertions", "stellar-xdr", + "wasmparser", ] [[package]] name = "soroban-env-guest" -version = "20.3.0" +version = "21.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5122ca2abd5ebcc1e876a96b9b44f87ce0a0e06df8f7c09772ddb58b159b7454" +checksum = "6bfb2536811045d5cd0c656a324cbe9ce4467eb734c7946b74410d90dea5d0ce" dependencies = [ "soroban-env-common", "static_assertions", @@ -999,13 +1017,16 @@ dependencies = [ [[package]] name = "soroban-env-host" -version = "20.3.0" +version = "21.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "114a0fa0d0cc39d0be16b1ee35b6e5f4ee0592ddcf459bde69391c02b03cf520" +checksum = "2b7a32c28f281c423189f1298960194f0e0fc4eeb72378028171e556d8cd6160" dependencies = [ "backtrace", "curve25519-dalek", + "ecdsa", "ed25519-dalek", + "elliptic-curve", + "generic-array", "getrandom", "hex-literal", "hmac", @@ -1013,8 +1034,10 @@ dependencies = [ "num-derive", "num-integer", "num-traits", + "p256", "rand", "rand_chacha", + "sec1", "sha2", "sha3", "soroban-builtin-sdk-macros", @@ -1022,13 +1045,14 @@ dependencies = [ "soroban-wasmi", "static_assertions", "stellar-strkey", + "wasmparser", ] [[package]] name = "soroban-env-macros" -version = "20.3.0" +version = "21.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b13e3f8c86f812e0669e78fcb3eae40c385c6a9dd1a4886a1de733230b4fcf27" +checksum = "242926fe5e0d922f12d3796cd7cd02dd824e5ef1caa088f45fce20b618309f64" dependencies = [ "itertools", "proc-macro2", @@ -1041,9 +1065,9 @@ dependencies = [ [[package]] name = "soroban-ledger-snapshot" -version = "20.5.0" +version = "21.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61a54708f44890e0546180db6b4f530e2a88d83b05a9b38a131caa21d005e25a" +checksum = "e6edf92749fd8399b417192d301c11f710b9cdce15789a3d157785ea971576fa" dependencies = [ "serde", "serde_json", @@ -1055,9 +1079,9 @@ dependencies = [ [[package]] name = "soroban-sdk" -version = "20.5.0" +version = "21.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84fc8be9068dd4e0212d8b13ad61089ea87e69ac212c262914503a961c8dc3a3" +checksum = "69e39bf9e8ab05579c836e8e5be5f2f4c5ba75e7337ece20e975e82fc3a9d41e" dependencies = [ "arbitrary", "bytes-lit", @@ -1075,9 +1099,9 @@ dependencies = [ [[package]] name = "soroban-sdk-macros" -version = "20.5.0" +version = "21.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db20def4ead836663633f58d817d0ed8e1af052c9650a04adf730525af85b964" +checksum = "0974e413731aeff2443f2305b344578b3f1ffd18335a7ba0f0b5d2eb4e94c9ce" dependencies = [ "crate-git-revision", "darling", @@ -1095,9 +1119,9 @@ dependencies = [ [[package]] name = "soroban-spec" -version = "20.5.0" +version = "21.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eefeb5d373b43f6828145d00f0c5cc35e96db56a6671ae9614f84beb2711cab" +checksum = "c2c70b20e68cae3ef700b8fa3ae29db1c6a294b311fba66918f90cb8f9fd0a1a" dependencies = [ "base64 0.13.1", "stellar-xdr", @@ -1107,9 +1131,9 @@ dependencies = [ [[package]] name = "soroban-spec-rust" -version = "20.5.0" +version = "21.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3152bca4737ef734ac37fe47b225ee58765c9095970c481a18516a2b287c7a33" +checksum = "a2dafbde981b141b191c6c036abc86097070ddd6eaaa33b273701449501e43d3" dependencies = [ "prettyplease", "proc-macro2", @@ -1169,9 +1193,9 @@ dependencies = [ [[package]] name = "stellar-xdr" -version = "20.1.0" +version = "21.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e59cdf3eb4467fb5a4b00b52e7de6dca72f67fac6f9b700f55c95a5d86f09c9d" +checksum = "2675a71212ed39a806e415b0dbf4702879ff288ec7f5ee996dda42a135512b50" dependencies = [ "arbitrary", "base64 0.13.1", @@ -1353,11 +1377,12 @@ dependencies = [ [[package]] name = "wasmparser" -version = "0.88.0" +version = "0.116.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb8cf7dd82407fe68161bedcd57fde15596f32ebf6e9b3bdbf3ae1da20e38e5e" +checksum = "a58e28b80dd8340cb07b8242ae654756161f6fc8d0038123d679b7b99964fa50" dependencies = [ - "indexmap 1.9.3", + "indexmap 2.1.0", + "semver", ] [[package]] diff --git a/cmd/crates/soroban-test/tests/it/help.rs b/cmd/crates/soroban-test/tests/it/help.rs index ef84a361b6..12db8b9bda 100644 --- a/cmd/crates/soroban-test/tests/it/help.rs +++ b/cmd/crates/soroban-test/tests/it/help.rs @@ -35,6 +35,7 @@ async fn tuple_help() { #[tokio::test] async fn strukt_help() { let output = invoke_custom("strukt", "--help").await.unwrap(); + println!("{output}"); assert!(output.contains("--strukt '{ \"a\": 1, \"b\": true, \"c\": \"hello\" }'",)); assert!(output.contains("This is from the rust doc above the struct Test",)); } diff --git a/cmd/crates/soroban-test/tests/it/util.rs b/cmd/crates/soroban-test/tests/it/util.rs index a744286665..7923f74297 100644 --- a/cmd/crates/soroban-test/tests/it/util.rs +++ b/cmd/crates/soroban-test/tests/it/util.rs @@ -1,10 +1,10 @@ -use std::path::Path; - +use either::Either; use soroban_cli::{ commands::contract, config::{locator::KeyType, secret::Secret}, }; use soroban_test::{TestEnv, Wasm, TEST_ACCOUNT}; +use std::path::Path; pub const CUSTOM_TYPES: &Wasm = &Wasm::Custom("test-wasms", "test_custom_types"); @@ -54,10 +54,11 @@ pub async fn invoke_custom( let mut i: contract::invoke::Cmd = sandbox.cmd_with_config(&["--id", id, "--", func, arg], None); i.wasm = Some(wasm.to_path_buf()); - sandbox - .run_cmd_with(i, TEST_ACCOUNT) - .await - .map(|r| r.into_result().unwrap()) + let s = sandbox.run_cmd_with(i, TEST_ACCOUNT).await; + s.map(|r| match r { + Either::Left(help) => help, + Either::Right(tx) => tx.into_result().unwrap(), + }) } pub const DEFAULT_CONTRACT_ID: &str = "CDR6QKTWZQYW6YUJ7UP7XXZRLWQPFRV6SWBLQS4ZQOSAF4BOUD77OO5Z"; diff --git a/cmd/soroban-cli/src/commands/contract/arg_parsing.rs b/cmd/soroban-cli/src/commands/contract/arg_parsing.rs index 21fa2f383d..9f04e44278 100644 --- a/cmd/soroban-cli/src/commands/contract/arg_parsing.rs +++ b/cmd/soroban-cli/src/commands/contract/arg_parsing.rs @@ -1,18 +1,18 @@ +use crate::xdr::{ + self, Hash, InvokeContractArgs, ScAddress, ScSpecEntry, ScSpecFunctionV0, ScSpecTypeDef, ScVal, + ScVec, +}; +use clap::error::ErrorKind::DisplayHelp; +use clap::value_parser; +use ed25519_dalek::SigningKey; +use heck::ToKebabCase; use std::collections::HashMap; use std::convert::TryInto; use std::ffi::OsString; use std::fmt::Debug; use std::path::PathBuf; -use clap::value_parser; -use ed25519_dalek::SigningKey; -use heck::ToKebabCase; - -use crate::xdr::{ - self, Hash, InvokeContractArgs, ScAddress, ScSpecEntry, ScSpecFunctionV0, ScSpecTypeDef, ScVal, - ScVec, -}; - +use crate::commands::contract::arg_parsing::HostFunctionParameters::{HelpMessage, Params}; use crate::commands::txn_result::TxnResult; use crate::config::{self}; use soroban_spec_tools::Spec; @@ -45,12 +45,17 @@ pub enum Error { MissingFileArg(PathBuf), } +pub enum HostFunctionParameters { + Params((String, Spec, InvokeContractArgs, Vec)), + HelpMessage(String), +} + pub fn build_host_function_parameters( contract_id: &stellar_strkey::Contract, slop: &[OsString], spec_entries: &[ScSpecEntry], config: &config::Args, -) -> Result<(String, Spec, InvokeContractArgs, Vec), Error> { +) -> Result { let spec = Spec(Some(spec_entries.to_vec())); let mut cmd = clap::Command::new(contract_id.to_string()) .no_binary_name(true) @@ -63,12 +68,20 @@ pub fn build_host_function_parameters( cmd.build(); let long_help = cmd.render_long_help(); - // get_matches_from exits the process if `help`, `--help` or `-h`are passed in the slop + // try_get_matches_from returns an error if `help`, `--help` or `-h`are passed in the slop // see clap documentation for more info: https://github.com/clap-rs/clap/blob/v4.1.8/src/builder/command.rs#L631 - let mut matches_ = cmd.get_matches_from(slop); - let Some((function, matches_)) = &matches_.remove_subcommand() else { - println!("{long_help}"); - std::process::exit(1); + let maybe_matches = cmd.try_get_matches_from(slop); + let Some((function, matches_)) = (match maybe_matches { + Ok(mut matches) => &matches.remove_subcommand(), + Err(e) => { + // to not exit immediately (to be able to fetch help message in tests), check for an error + if e.kind() == DisplayHelp { + return Ok(HelpMessage(e.to_string())); + } + e.exit(); + } + }) else { + return Ok(HelpMessage(format!("{long_help}"))); }; let func = spec.find_function(function)?; @@ -145,7 +158,7 @@ pub fn build_host_function_parameters( args: final_args, }; - Ok((function.clone(), spec, invoke_args, signers)) + Ok(Params((function.clone(), spec, invoke_args, signers))) } fn build_custom_cmd(name: &str, spec: &Spec) -> Result { diff --git a/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs b/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs index 9bf63802cc..4c22df616d 100644 --- a/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs +++ b/cmd/soroban-cli/src/commands/contract/deploy/wasm.rs @@ -1,8 +1,3 @@ -use std::array::TryFromSliceError; -use std::ffi::OsString; -use std::fmt::Debug; -use std::num::ParseIntError; - use crate::xdr::{ AccountId, ContractExecutable, ContractIdPreimage, ContractIdPreimageFromAddress, CreateContractArgs, CreateContractArgsV2, Error as XdrError, Hash, HostFunction, @@ -11,11 +6,17 @@ use crate::xdr::{ VecM, WriteXdr, }; use clap::{arg, command, Parser}; +use itertools::Either; +use itertools::Either::{Left, Right}; use rand::Rng; use regex::Regex; - use soroban_spec_tools::contract as contract_spec; +use std::array::TryFromSliceError; +use std::ffi::OsString; +use std::fmt::Debug; +use std::num::ParseIntError; +use crate::commands::contract::arg_parsing::HostFunctionParameters; use crate::{ assembled::simulate_and_assemble_transaction, commands::{ @@ -128,26 +129,31 @@ pub enum Error { impl Cmd { pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> { - let res = self - .run_against_rpc_server(Some(global_args), None) - .await? - .to_envelope(); + let res = self.run_against_rpc_server(Some(global_args), None).await?; match res { - TxnEnvelopeResult::TxnEnvelope(tx) => println!("{}", tx.to_xdr_base64(Limits::none())?), - TxnEnvelopeResult::Res(contract) => { - let network = self.config.get_network()?; - - if let Some(alias) = self.alias.clone() { - self.config.locator.save_contract_id( - &network.network_passphrase, - &contract, - &alias, - )?; - } - - println!("{contract}"); + Left(help) => { + println!("{help}"); } + Right(res) => match res.to_envelope() { + TxnEnvelopeResult::TxnEnvelope(tx) => { + println!("{}", tx.to_xdr_base64(Limits::none())?); + } + TxnEnvelopeResult::Res(contract) => { + let network = self.config.get_network()?; + + if let Some(alias) = self.alias.clone() { + self.config.locator.save_contract_id( + &network.network_passphrase, + &contract, + &alias, + )?; + } + + println!("{contract}"); + } + }, } + Ok(()) } } @@ -167,14 +173,14 @@ fn alias_validator(alias: &str) -> Result { #[async_trait::async_trait] impl NetworkRunnable for Cmd { type Error = Error; - type Result = TxnResult; + type Result = Either>; #[allow(clippy::too_many_lines)] async fn run_against_rpc_server( &self, global_args: Option<&global::Args>, config: Option<&config::Args>, - ) -> Result, Error> { + ) -> Result>, Error> { let print = Print::new(global_args.map_or(false, |a| a.quiet)); let config = config.unwrap_or(&self.config); let wasm_hash = if let Some(wasm) = &self.wasm { @@ -248,15 +254,18 @@ impl NetworkRunnable for Cmd { } else { let mut slop = vec![OsString::from(CONSTRUCTOR_FUNCTION_NAME)]; slop.extend_from_slice(&self.slop); - Some( - arg_parsing::build_host_function_parameters( - &stellar_strkey::Contract(contract_id.0), - &slop, - &entries, - config, - )? - .2, - ) + let params = arg_parsing::build_host_function_parameters( + &stellar_strkey::Contract(contract_id.0), + &slop, + &entries, + config, + )?; + match params { + HostFunctionParameters::Params(p) => Some(p.2), + HostFunctionParameters::HelpMessage(h) => { + return Ok(Left(h)); + } + } } } else { None @@ -276,7 +285,7 @@ impl NetworkRunnable for Cmd { if self.fee.build_only { print.checkln("Transaction built!"); - return Ok(TxnResult::Txn(txn)); + return Ok(Right(TxnResult::Txn(txn))); } print.infoln("Simulating deploy transaction…"); @@ -286,7 +295,7 @@ impl NetworkRunnable for Cmd { if self.fee.sim_only { print.checkln("Done!"); - return Ok(TxnResult::Txn(txn)); + return Ok(Right(TxnResult::Txn(txn))); } print.globeln("Submitting deploy transaction…"); @@ -307,7 +316,7 @@ impl NetworkRunnable for Cmd { print.checkln("Deployed!"); - Ok(TxnResult::Res(contract_id)) + Ok(Right(TxnResult::Res(contract_id))) } } diff --git a/cmd/soroban-cli/src/commands/contract/invoke.rs b/cmd/soroban-cli/src/commands/contract/invoke.rs index 04eeaebd6d..d29e6738de 100644 --- a/cmd/soroban-cli/src/commands/contract/invoke.rs +++ b/cmd/soroban-cli/src/commands/contract/invoke.rs @@ -6,12 +6,15 @@ use std::str::FromStr; use std::{fmt::Debug, fs, io}; use clap::{arg, command, Parser, ValueEnum}; - +use itertools::Either; +use itertools::Either::{Left, Right}; use soroban_rpc::{Client, SimulateHostFunctionResult, SimulateTransactionResponse}; use soroban_spec::read::FromWasmError; use super::super::events; use super::arg_parsing; +use crate::commands::contract::arg_parsing::HostFunctionParameters; +use crate::commands::contract::arg_parsing::HostFunctionParameters::HelpMessage; use crate::{ assembled::simulate_and_assemble_transaction, commands::{ @@ -133,17 +136,27 @@ impl From for Error { impl Cmd { pub async fn run(&self, global_args: &global::Args) -> Result<(), Error> { - let res = self.invoke(global_args).await?.to_envelope(); + let res = self.invoke(global_args).await?; match res { - TxnEnvelopeResult::TxnEnvelope(tx) => println!("{}", tx.to_xdr_base64(Limits::none())?), - TxnEnvelopeResult::Res(output) => { - println!("{output}"); + Right(res) => match res.to_envelope() { + TxnEnvelopeResult::TxnEnvelope(tx) => { + println!("{}", tx.to_xdr_base64(Limits::none())?); + } + TxnEnvelopeResult::Res(output) => { + println!("{output}"); + } + }, + Left(help) => { + println!("{help}"); } } Ok(()) } - pub async fn invoke(&self, global_args: &global::Args) -> Result, Error> { + pub async fn invoke( + &self, + global_args: &global::Args, + ) -> Result>, Error> { self.run_against_rpc_server(Some(global_args), None).await } @@ -206,13 +219,13 @@ impl Cmd { #[async_trait::async_trait] impl NetworkRunnable for Cmd { type Error = Error; - type Result = TxnResult; + type Result = Either>; async fn run_against_rpc_server( &self, global_args: Option<&global::Args>, config: Option<&config::Args>, - ) -> Result, Error> { + ) -> Result>, Error> { let config = config.unwrap_or(&self.config); let network = config.get_network()?; tracing::trace!(?network); @@ -223,7 +236,11 @@ impl NetworkRunnable for Cmd { let spec_entries = self.spec_entries()?; if let Some(spec_entries) = &spec_entries { // For testing wasm arg parsing - let _ = build_host_function_parameters(&contract_id, &self.slop, spec_entries, config)?; + let params = + build_host_function_parameters(&contract_id, &self.slop, spec_entries, config)?; + if let HelpMessage(s) = params { + return Ok(Left(s)); + } } let client = network.rpc_client()?; @@ -237,9 +254,14 @@ impl NetworkRunnable for Cmd { .await .map_err(Error::from)?; - let (function, spec, host_function_params, signers) = + let params = build_host_function_parameters(&contract_id, &self.slop, &spec_entries, config)?; + let (function, spec, host_function_params, signers) = match params { + HostFunctionParameters::Params(x) => x, + HelpMessage(s) => return Ok(Left(s)), + }; + let should_send_tx = self .should_send_after_sim(host_function_params.clone(), client.clone()) .await?; @@ -265,12 +287,12 @@ impl NetworkRunnable for Cmd { account_id, )?; if self.fee.build_only { - return Ok(TxnResult::Txn(tx)); + return Ok(Right(TxnResult::Txn(tx))); } let txn = simulate_and_assemble_transaction(&client, &tx).await?; let txn = self.fee.apply_to_assembled_txn(txn); if self.fee.sim_only { - return Ok(TxnResult::Txn(txn.transaction().clone())); + return Ok(Right(TxnResult::Txn(txn.transaction().clone()))); } let sim_res = txn.sim_response(); if global_args.map_or(true, |a| !a.no_cache) { @@ -306,7 +328,7 @@ impl NetworkRunnable for Cmd { } }; crate::log::events(&events); - Ok(output_to_string(&spec, &return_value, &function)?) + Ok(Right(output_to_string(&spec, &return_value, &function)?)) } }