diff --git a/Cargo.lock b/Cargo.lock index 451235fa7c..feafc7dd61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2734,6 +2734,7 @@ dependencies = [ "hex", "itertools 0.10.5", "serde_json", + "soroban-env-host", "soroban-spec", "stellar-strkey 0.0.7", "stellar-xdr", diff --git a/cmd/crates/soroban-spec-tools/Cargo.toml b/cmd/crates/soroban-spec-tools/Cargo.toml index 61a32c1371..514b82924b 100644 --- a/cmd/crates/soroban-spec-tools/Cargo.toml +++ b/cmd/crates/soroban-spec-tools/Cargo.toml @@ -20,6 +20,8 @@ crate-type = ["rlib"] soroban-spec = { workspace = true } stellar-strkey = { workspace = true } stellar-xdr = { workspace = true, features = ["curr", "std", "serde"] } +soroban-env-host = { workspace = true } + serde_json = { workspace = true } itertools = { workspace = true } ethnum = { workspace = true } diff --git a/cmd/soroban-cli/src/utils/contract_spec.rs b/cmd/crates/soroban-spec-tools/src/contract.rs similarity index 98% rename from cmd/soroban-cli/src/utils/contract_spec.rs rename to cmd/crates/soroban-spec-tools/src/contract.rs index b4f24abec8..2d0d857cd7 100644 --- a/cmd/soroban-cli/src/utils/contract_spec.rs +++ b/cmd/crates/soroban-spec-tools/src/contract.rs @@ -10,7 +10,7 @@ use soroban_env_host::xdr::{ StringM, WriteXdr, }; -pub struct ContractSpec { +pub struct Spec { pub env_meta_base64: Option, pub env_meta: Vec, pub meta_base64: Option, @@ -38,7 +38,7 @@ pub enum Error { Parser(#[from] wasmparser::BinaryReaderError), } -impl ContractSpec { +impl Spec { pub fn new(bytes: &[u8]) -> Result { let mut env_meta: Option<&[u8]> = None; let mut meta: Option<&[u8]> = None; @@ -87,7 +87,7 @@ impl ContractSpec { vec![] }; - Ok(ContractSpec { + Ok(Spec { env_meta_base64, env_meta, meta_base64, @@ -108,7 +108,7 @@ impl ContractSpec { } } -impl Display for ContractSpec { +impl Display for Spec { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(env_meta) = &self.env_meta_base64 { writeln!(f, "Env Meta: {env_meta}")?; diff --git a/cmd/crates/soroban-spec-tools/src/lib.rs b/cmd/crates/soroban-spec-tools/src/lib.rs index 7f310fd996..bc3c2a3866 100644 --- a/cmd/crates/soroban-spec-tools/src/lib.rs +++ b/cmd/crates/soroban-spec-tools/src/lib.rs @@ -13,6 +13,7 @@ use stellar_xdr::curr::{ UInt128Parts, UInt256Parts, Uint256, VecM, }; +pub mod contract; pub mod utils; #[derive(thiserror::Error, Debug)] diff --git a/cmd/crates/soroban-test/tests/it/help.rs b/cmd/crates/soroban-test/tests/it/help.rs index 6d4680e772..a66c449ed3 100644 --- a/cmd/crates/soroban-test/tests/it/help.rs +++ b/cmd/crates/soroban-test/tests/it/help.rs @@ -1,11 +1,11 @@ use soroban_cli::commands::contract; use soroban_test::TestEnv; -use crate::util::{invoke_custom as invoke, CUSTOM_TYPES}; +use crate::util::{invoke_custom as invoke, CUSTOM_TYPES, DEFAULT_CONTRACT_ID}; async fn invoke_custom(func: &str, args: &str) -> Result { let e = &TestEnv::default(); - invoke(e, "1", func, args, &CUSTOM_TYPES.path()).await + invoke(e, DEFAULT_CONTRACT_ID, func, args, &CUSTOM_TYPES.path()).await } #[tokio::test] diff --git a/cmd/crates/soroban-test/tests/it/integration/dotenv.rs b/cmd/crates/soroban-test/tests/it/integration/dotenv.rs index d7d56aaf3b..7c0f25b3fc 100644 --- a/cmd/crates/soroban-test/tests/it/integration/dotenv.rs +++ b/cmd/crates/soroban-test/tests/it/integration/dotenv.rs @@ -35,7 +35,7 @@ fn current_env_not_overwritten() { write_env_file(e, &contract_id()); e.new_assert_cmd("contract") - .env("SOROBAN_CONTRACT_ID", "2") + .env("SOROBAN_CONTRACT_ID", "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4") .arg("invoke") .arg("--") .arg("hello") @@ -51,7 +51,10 @@ fn cli_args_have_priority() { deploy_hello(e); write_env_file(e, &contract_id()); e.new_assert_cmd("contract") - .env("SOROBAN_CONTRACT_ID", "2") + .env( + "SOROBAN_CONTRACT_ID", + "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFCT4", + ) .arg("invoke") .arg("--id") .arg(TEST_CONTRACT_ID) diff --git a/cmd/crates/soroban-test/tests/it/util.rs b/cmd/crates/soroban-test/tests/it/util.rs index 6d62510126..112d5f841a 100644 --- a/cmd/crates/soroban-test/tests/it/util.rs +++ b/cmd/crates/soroban-test/tests/it/util.rs @@ -68,3 +68,5 @@ pub async fn invoke_custom( i.invoke(&soroban_cli::commands::global::Args::default()) .await } + +pub const DEFAULT_CONTRACT_ID: &str = "CDR6QKTWZQYW6YUJ7UP7XXZRLWQPFRV6SWBLQS4ZQOSAF4BOUD77OO5Z"; diff --git a/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs b/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs index 19c7eecd66..091f8255a9 100644 --- a/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs +++ b/cmd/soroban-cli/src/commands/contract/bindings/typescript.rs @@ -1,17 +1,15 @@ use std::{ffi::OsString, fmt::Debug, path::PathBuf}; use clap::{command, Parser}; +use soroban_spec_tools::contract as contract_spec; use soroban_spec_typescript::{self as typescript, boilerplate::Project}; -use crate::wasm; -use crate::{ - commands::{ - config::locator, - contract::{self, fetch}, - network::{self, Network}, - }, - utils::contract_spec::{self, ContractSpec}, +use crate::commands::{ + config::locator, + contract::{self, fetch}, + network::{self, Network}, }; +use crate::wasm; #[derive(Parser, Debug, Clone)] #[group(skip)] @@ -78,7 +76,7 @@ impl Cmd { network: self.network.clone(), }; let bytes = fetch.get_bytes().await?; - ContractSpec::new(&bytes)?.spec + contract_spec::Spec::new(&bytes)?.spec }; if self.output_dir.is_file() { return Err(Error::IsFile(self.output_dir.clone())); diff --git a/cmd/soroban-cli/src/commands/contract/inspect.rs b/cmd/soroban-cli/src/commands/contract/inspect.rs index 355c18ca81..e66bf83fdb 100644 --- a/cmd/soroban-cli/src/commands/contract/inspect.rs +++ b/cmd/soroban-cli/src/commands/contract/inspect.rs @@ -1,5 +1,6 @@ use clap::{command, Parser}; use soroban_env_host::xdr; +use soroban_spec_tools::contract; use std::{fmt::Debug, path::PathBuf}; use tracing::debug; @@ -28,7 +29,7 @@ pub enum Error { #[error(transparent)] Xdr(#[from] xdr::Error), #[error(transparent)] - Spec(#[from] crate::utils::contract_spec::Error), + Spec(#[from] contract::Error), } impl Cmd { diff --git a/cmd/soroban-cli/src/commands/contract/install.rs b/cmd/soroban-cli/src/commands/contract/install.rs index 905775298a..22fa90c71f 100644 --- a/cmd/soroban-cli/src/commands/contract/install.rs +++ b/cmd/soroban-cli/src/commands/contract/install.rs @@ -153,7 +153,7 @@ impl Cmd { } } -fn get_contract_meta_sdk_version(wasm_spec: &utils::contract_spec::ContractSpec) -> Option { +fn get_contract_meta_sdk_version(wasm_spec: &soroban_spec_tools::contract::Spec) -> Option { let rs_sdk_version_option = if let Some(_meta) = &wasm_spec.meta_base64 { wasm_spec.meta.iter().find(|entry| match entry { ScMetaEntry::ScMetaV0(ScMetaV0 { key, .. }) => { diff --git a/cmd/soroban-cli/src/commands/contract/invoke.rs b/cmd/soroban-cli/src/commands/contract/invoke.rs index 669342b065..5030c03d33 100644 --- a/cmd/soroban-cli/src/commands/contract/invoke.rs +++ b/cmd/soroban-cli/src/commands/contract/invoke.rs @@ -28,13 +28,8 @@ use super::super::{ config::{self, locator}, events, }; -use crate::{ - commands::global, - rpc::{self, Client}, - utils::{self, contract_spec}, - Pwd, -}; -use soroban_spec_tools::Spec; +use crate::{commands::global, rpc, Pwd}; +use soroban_spec_tools::{contract, Spec}; #[derive(Parser, Debug, Default, Clone)] #[allow(clippy::struct_excessive_bools)] @@ -140,7 +135,7 @@ pub enum Error { #[error(transparent)] StrKey(#[from] stellar_strkey::DecodeError), #[error(transparent)] - ContractSpec(#[from] contract_spec::Error), + ContractSpec(#[from] contract::Error), #[error("")] MissingFileArg(PathBuf), } @@ -275,7 +270,7 @@ impl Cmd { // For testing wasm arg parsing let _ = self.build_host_function_parameters(contract_id, spec_entries)?; } - let client = Client::new(&network.rpc_url)?; + let client = rpc::Client::new(&network.rpc_url)?; client .verify_network_passphrase(Some(&network.network_passphrase)) .await?; @@ -344,7 +339,7 @@ impl Cmd { impl Cmd { fn contract_id(&self) -> Result<[u8; 32], Error> { - utils::contract_id_from_str(&self.contract_id) + soroban_spec_tools::utils::contract_id_from_str(&self.contract_id) .map_err(|e| Error::CannotParseContractId(self.contract_id.clone(), e)) } } diff --git a/cmd/soroban-cli/src/key.rs b/cmd/soroban-cli/src/key.rs index e9901abd2c..7866e40605 100644 --- a/cmd/soroban-cli/src/key.rs +++ b/cmd/soroban-cli/src/key.rs @@ -83,7 +83,7 @@ impl Args { } else if let Some(wasm_hash) = &self.wasm_hash { return Ok(vec![LedgerKey::ContractCode(LedgerKeyContractCode { hash: xdr::Hash( - utils::contract_id_from_str(wasm_hash) + soroban_spec_tools::utils::contract_id_from_str(wasm_hash) .map_err(|e| Error::CannotParseContractId(wasm_hash.clone(), e))?, ), })]); diff --git a/cmd/soroban-cli/src/rpc/mod.rs b/cmd/soroban-cli/src/rpc/mod.rs index 535426292b..74fc379f42 100644 --- a/cmd/soroban-cli/src/rpc/mod.rs +++ b/cmd/soroban-cli/src/rpc/mod.rs @@ -16,6 +16,7 @@ use soroban_env_host::xdr::{ }; use soroban_sdk::token; use soroban_sdk::xdr::Limits; +use soroban_spec_tools::contract::Spec; use std::{ fmt::Display, str::FromStr, @@ -25,7 +26,7 @@ use termcolor::{Color, ColorChoice, StandardStream, WriteColor}; use termcolor_output::colored; use tokio::time::sleep; -use crate::utils::contract_spec; +// use soroban_spec_tools::contract::Spec; mod txn; @@ -88,7 +89,7 @@ pub enum Error { #[error("unexpected contract code data type: {0:?}")] UnexpectedContractCodeDataType(LedgerEntryData), #[error(transparent)] - CouldNotParseContractSpec(#[from] contract_spec::Error), + CouldNotParseContractSpec(#[from] soroban_spec_tools::contract::Error), #[error("unexpected contract code got token")] UnexpectedToken(ContractDataEntry), #[error(transparent)] @@ -898,11 +899,9 @@ soroban config identity fund {address} --helper-url "# xdr::ScVal::ContractInstance(xdr::ScContractInstance { executable: xdr::ContractExecutable::Wasm(hash), .. - }) => Ok(contract_spec::ContractSpec::new( - &self.get_remote_wasm_from_hash(hash).await?, - ) - .map_err(Error::CouldNotParseContractSpec)? - .spec), + }) => Ok(Spec::new(&self.get_remote_wasm_from_hash(hash).await?) + .map_err(Error::CouldNotParseContractSpec)? + .spec), xdr::ScVal::ContractInstance(xdr::ScContractInstance { executable: xdr::ContractExecutable::StellarAsset, .. diff --git a/cmd/soroban-cli/src/utils.rs b/cmd/soroban-cli/src/utils.rs index ff0018a94c..97fc9bfcc7 100644 --- a/cmd/soroban-cli/src/utils.rs +++ b/cmd/soroban-cli/src/utils.rs @@ -9,7 +9,7 @@ use soroban_env_host::xdr::{ TransactionV1Envelope, WriteXdr, }; -pub mod contract_spec; +pub use soroban_spec_tools::contract as contract_spec; /// # Errors /// @@ -55,16 +55,17 @@ pub fn sign_transaction( /// /// Might return an error pub fn contract_id_from_str(contract_id: &str) -> Result<[u8; 32], stellar_strkey::DecodeError> { - stellar_strkey::Contract::from_string(contract_id) - .map(|strkey| strkey.0) - .or_else(|_| { + Ok( + if let Ok(strkey) = stellar_strkey::Contract::from_string(contract_id) { + strkey.0 + } else { // strkey failed, try to parse it as a hex string, for backwards compatibility. soroban_spec_tools::utils::padded_hex_from_str(contract_id, 32) .map_err(|_| stellar_strkey::DecodeError::Invalid)? .try_into() - .map_err(|_| stellar_strkey::DecodeError::Invalid) - }) - .map_err(|_| stellar_strkey::DecodeError::Invalid) + .map_err(|_| stellar_strkey::DecodeError::Invalid)? + }, + ) } /// # Errors @@ -198,47 +199,5 @@ mod tests { ), Err(err) => panic!("Failed to parse contract id: {err}"), } - - // hex - match contract_id_from_str( - "363eaa3867841fbad0f4ed88c779e4fe66e56a2470dc98c0ec9c073d05c7b103", - ) { - Ok(contract_id) => assert_eq!( - contract_id, - [ - 0x36, 0x3e, 0xaa, 0x38, 0x67, 0x84, 0x1f, 0xba, 0xd0, 0xf4, 0xed, 0x88, 0xc7, - 0x79, 0xe4, 0xfe, 0x66, 0xe5, 0x6a, 0x24, 0x70, 0xdc, 0x98, 0xc0, 0xec, 0x9c, - 0x07, 0x3d, 0x05, 0xc7, 0xb1, 0x03, - ] - ), - Err(err) => panic!("Failed to parse contract id: {err}"), - } - - // unpadded-hex - match contract_id_from_str("1") { - Ok(contract_id) => assert_eq!( - contract_id, - [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - ] - ), - Err(err) => panic!("Failed to parse contract id: {err}"), - } - - // invalid hex - match contract_id_from_str("foobar") { - Ok(_) => panic!("Expected parsing to fail"), - Err(err) => assert_eq!(err, stellar_strkey::DecodeError::Invalid), - } - - // hex too long (33 bytes) - match contract_id_from_str( - "000000000000000000000000000000000000000000000000000000000000000000", - ) { - Ok(_) => panic!("Expected parsing to fail"), - Err(err) => assert_eq!(err, stellar_strkey::DecodeError::Invalid), - } } } diff --git a/cmd/soroban-cli/src/wasm.rs b/cmd/soroban-cli/src/wasm.rs index fce44c7c56..4b8a7f8ca8 100644 --- a/cmd/soroban-cli/src/wasm.rs +++ b/cmd/soroban-cli/src/wasm.rs @@ -1,11 +1,12 @@ use clap::arg; use soroban_env_host::xdr::{self, LedgerKey, LedgerKeyContractCode}; +use soroban_spec_tools::contract::{self, Spec}; use std::{ fs, io, path::{Path, PathBuf}, }; -use crate::utils::{self, contract_spec::ContractSpec}; +use crate::utils::{self}; #[derive(thiserror::Error, Debug)] pub enum Error { @@ -25,7 +26,7 @@ pub enum Error { #[error(transparent)] Parser(#[from] wasmparser::BinaryReaderError), #[error(transparent)] - ContractSpec(#[from] crate::utils::contract_spec::Error), + ContractSpec(#[from] contract::Error), } #[derive(Debug, clap::Args, Clone)] @@ -60,9 +61,9 @@ impl Args { /// # Errors /// May fail to read wasm file or parse xdr section - pub fn parse(&self) -> Result { + pub fn parse(&self) -> Result { let contents = self.read()?; - Ok(ContractSpec::new(&contents)?) + Ok(Spec::new(&contents)?) } }