1use crate::xdr;
2
3use crate::xdr::{ContractDataEntry, ContractExecutable, ScContractInstance, ScSpecEntry, ScVal};
4
5use soroban_spec::read::FromWasmError;
6pub use soroban_spec_tools::contract as contract_spec;
7
8use crate::commands::global;
9use crate::config::{self, data, locator, network};
10use crate::rpc;
11use crate::utils::rpc::get_remote_wasm_from_hash;
12
13#[derive(thiserror::Error, Debug)]
14pub enum Error {
15 #[error("parsing contract spec: {0}")]
16 CannotParseContractSpec(FromWasmError),
17 #[error(transparent)]
18 Rpc(#[from] rpc::Error),
19 #[error("missing result")]
20 MissingResult,
21 #[error(transparent)]
22 Data(#[from] data::Error),
23 #[error(transparent)]
24 Xdr(#[from] xdr::Error),
25 #[error(transparent)]
26 Network(#[from] network::Error),
27 #[error(transparent)]
28 Config(#[from] config::Error),
29 #[error(transparent)]
30 ContractSpec(#[from] contract_spec::Error),
31}
32
33pub async fn get_remote_contract_spec(
36 contract_id: &[u8; 32],
37 locator: &locator::Args,
38 network: &network::Args,
39 global_args: Option<&global::Args>,
40 config: Option<&config::Args>,
41) -> Result<Vec<ScSpecEntry>, Error> {
42 let network = config.map_or_else(
43 || network.get(locator).map_err(Error::from),
44 |c| c.get_network().map_err(Error::from),
45 )?;
46 tracing::trace!(?network);
47 let client = network.rpc_client()?;
48 let r = client.get_contract_data(contract_id).await?;
50 tracing::trace!("{r:?}");
51
52 let ContractDataEntry {
53 val: ScVal::ContractInstance(ScContractInstance { executable, .. }),
54 ..
55 } = r
56 else {
57 return Err(Error::MissingResult);
58 };
59
60 Ok(match executable {
62 ContractExecutable::Wasm(hash) => {
63 let hash_str = hash.to_string();
64 if let Ok(entries) = data::read_spec(&hash_str) {
65 entries
66 } else {
67 let raw_wasm = get_remote_wasm_from_hash(&client, &hash).await?;
68 let res = contract_spec::Spec::new(&raw_wasm)?;
69 let res = res.spec;
70 if global_args.is_none_or(|a| !a.no_cache) {
71 data::write_spec(&hash_str, &res)?;
72 }
73 res
74 }
75 }
76 ContractExecutable::StellarAsset => {
77 soroban_spec::read::parse_raw(stellar_asset_spec::xdr())?
78 }
79 })
80}