soroban_cli/
key.rs

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    /// Contract ID to which owns the data entries.
30    /// If no keys provided the Contract's instance will be extended
31    #[arg(
32        long = "id",
33        required_unless_present = "wasm",
34        required_unless_present = "wasm_hash"
35    )]
36    pub contract_id: Option<alias::UnresolvedContract>,
37    /// Storage key (symbols only)
38    #[arg(long = "key", conflicts_with = "key_xdr")]
39    pub key: Option<Vec<String>>,
40    /// Storage key (base64-encoded XDR)
41    #[arg(long = "key-xdr", conflicts_with = "key")]
42    pub key_xdr: Option<Vec<String>>,
43    /// Path to Wasm file of contract code to extend
44    #[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    /// Path to Wasm file of contract code to extend
53    #[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    /// Storage entry durability
62    #[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}