1use crate::xdr::{
2 self, LedgerKey, LedgerKeyContractCode, LedgerKeyContractData, Limits, ReadXdr, ScAddress,
3 ScVal,
4};
5use crate::{
6 commands::contract::Durability,
7 config::{alias, locator, network::Network},
8 wasm,
9};
10use std::path::PathBuf;
11
12#[derive(thiserror::Error, Debug)]
13pub enum Error {
14 #[error(transparent)]
15 Spec(#[from] soroban_spec_tools::Error),
16 #[error(transparent)]
17 Xdr(#[from] xdr::Error),
18 #[error("cannot parse contract ID {0}: {1}")]
19 CannotParseContractId(String, stellar_strkey::DecodeError),
20 #[error(transparent)]
21 Wasm(#[from] wasm::Error),
22 #[error(transparent)]
23 Locator(#[from] locator::Error),
24}
25
26#[derive(Debug, clap::Args, Clone)]
27#[group(skip)]
28pub struct Args {
29 #[arg(
32 long = "id",
33 required_unless_present = "wasm",
34 required_unless_present = "wasm_hash"
35 )]
36 pub contract_id: Option<alias::UnresolvedContract>,
37 #[arg(long = "key", conflicts_with = "key_xdr")]
39 pub key: Option<Vec<String>>,
40 #[arg(long = "key-xdr", conflicts_with = "key")]
42 pub key_xdr: Option<Vec<String>>,
43 #[arg(
45 long,
46 conflicts_with = "contract_id",
47 conflicts_with = "key",
48 conflicts_with = "key_xdr",
49 conflicts_with = "wasm_hash"
50 )]
51 pub wasm: Option<PathBuf>,
52 #[arg(
54 long,
55 conflicts_with = "contract_id",
56 conflicts_with = "key",
57 conflicts_with = "key_xdr",
58 conflicts_with = "wasm"
59 )]
60 pub wasm_hash: Option<String>,
61 #[arg(long, value_enum, default_value = "persistent")]
63 pub durability: Durability,
64}
65
66impl Args {
67 pub fn parse_keys(
68 &self,
69 locator: &locator::Args,
70 Network {
71 network_passphrase, ..
72 }: &Network,
73 ) -> Result<Vec<LedgerKey>, Error> {
74 let keys = if let Some(keys) = &self.key {
75 keys.iter()
76 .map(|key| {
77 Ok(soroban_spec_tools::from_string_primitive(
78 key,
79 &xdr::ScSpecTypeDef::Symbol,
80 )?)
81 })
82 .collect::<Result<Vec<_>, Error>>()?
83 } else if let Some(keys) = &self.key_xdr {
84 keys.iter()
85 .map(|s| Ok(ScVal::from_xdr_base64(s, Limits::none())?))
86 .collect::<Result<Vec<_>, Error>>()?
87 } else if let Some(wasm) = &self.wasm {
88 return Ok(vec![crate::wasm::Args { wasm: wasm.clone() }.try_into()?]);
89 } else if let Some(wasm_hash) = &self.wasm_hash {
90 return Ok(vec![LedgerKey::ContractCode(LedgerKeyContractCode {
91 hash: xdr::Hash(
92 soroban_spec_tools::utils::contract_id_from_str(wasm_hash)
93 .map_err(|e| Error::CannotParseContractId(wasm_hash.clone(), e))?,
94 ),
95 })]);
96 } else {
97 vec![ScVal::LedgerKeyContractInstance]
98 };
99 let contract = self
100 .contract_id
101 .as_ref()
102 .unwrap()
103 .resolve_contract_id(locator, network_passphrase)?;
104
105 Ok(keys
106 .into_iter()
107 .map(|key| {
108 LedgerKey::ContractData(LedgerKeyContractData {
109 contract: ScAddress::Contract(stellar_xdr::curr::ContractId(xdr::Hash(
110 contract.0,
111 ))),
112 durability: (&self.durability).into(),
113 key,
114 })
115 })
116 .collect())
117 }
118}