Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: clean up interface for info::shared::fetch #1802

Merged
merged 1 commit into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 24 additions & 15 deletions cmd/soroban-cli/src/commands/contract/bindings/typescript.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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,
Expand All @@ -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),
}
Expand All @@ -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() {
Expand All @@ -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,
Expand Down
10 changes: 5 additions & 5 deletions cmd/soroban-cli/src/commands/contract/info/env_meta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
},
Expand Down Expand Up @@ -43,12 +43,12 @@ pub enum Error {
impl Cmd {
pub async fn run(&self, global_args: &global::Args) -> Result<String, Error> {
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());
Expand Down
24 changes: 13 additions & 11 deletions cmd/soroban-cli/src/commands/contract/info/interface.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -47,18 +46,21 @@ pub enum Error {
impl Cmd {
pub async fn run(&self, global_args: &global::Args) -> Result<String, Error> {
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 {
Expand Down
11 changes: 5 additions & 6 deletions cmd/soroban-cli/src/commands/contract/info/meta.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -36,12 +35,12 @@ pub enum Error {
impl Cmd {
pub async fn run(&self, global_args: &global::Args) -> Result<String, Error> {
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());
Expand Down
82 changes: 66 additions & 16 deletions cmd/soroban-cli/src/commands/contract/info/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<u8>>, Option<String>, Option<Network>), Error> {
pub struct Fetched {
pub contract: Contract,
pub source: Source,
}

pub enum Contract {
Wasm { wasm_bytes: Vec<u8> },
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<Fetched, Error> {
// 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
Expand All @@ -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);
}
}
Loading