soroban_cli/
get_spec.rs

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
33///
34/// # Errors
35pub 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    // Get contract data
49    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    // Get the contract spec entries based on the executable type
61    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}