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