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