soroban_cli/commands/contract/id/
wasm.rs

1use crate::xdr::{
2    self, AccountId, ContractIdPreimage, ContractIdPreimageFromAddress, Hash, HashIdPreimage,
3    HashIdPreimageContractId, Limits, PublicKey, ScAddress, Uint256, WriteXdr,
4};
5use clap::{arg, command, Parser};
6use sha2::{Digest, Sha256};
7
8use crate::config;
9
10#[derive(Parser, Debug, Clone)]
11#[group(skip)]
12pub struct Cmd {
13    /// ID of the Soroban contract
14    #[arg(long)]
15    pub salt: String,
16
17    #[command(flatten)]
18    pub config: config::Args,
19}
20#[derive(thiserror::Error, Debug)]
21pub enum Error {
22    #[error(transparent)]
23    ConfigError(#[from] config::Error),
24    #[error(transparent)]
25    Xdr(#[from] xdr::Error),
26    #[error("cannot parse salt {0}")]
27    CannotParseSalt(String),
28    #[error("only Ed25519 accounts are allowed")]
29    OnlyEd25519AccountsAllowed,
30}
31impl Cmd {
32    pub async fn run(&self) -> Result<(), Error> {
33        let salt: [u8; 32] = soroban_spec_tools::utils::padded_hex_from_str(&self.salt, 32)
34            .map_err(|_| Error::CannotParseSalt(self.salt.clone()))?
35            .try_into()
36            .map_err(|_| Error::CannotParseSalt(self.salt.clone()))?;
37        let source_account = match self.config.source_account().await? {
38            xdr::MuxedAccount::Ed25519(uint256) => stellar_strkey::ed25519::PublicKey(uint256.0),
39            xdr::MuxedAccount::MuxedEd25519(_) => return Err(Error::OnlyEd25519AccountsAllowed),
40        };
41        let contract_id_preimage = contract_preimage(&source_account, salt);
42        let contract_id = get_contract_id(
43            contract_id_preimage.clone(),
44            &self.config.get_network()?.network_passphrase,
45        )?;
46        println!("{contract_id}");
47        Ok(())
48    }
49}
50
51pub fn contract_preimage(
52    key: &stellar_strkey::ed25519::PublicKey,
53    salt: [u8; 32],
54) -> ContractIdPreimage {
55    let source_account = AccountId(PublicKey::PublicKeyTypeEd25519(key.0.into()));
56    ContractIdPreimage::Address(ContractIdPreimageFromAddress {
57        address: ScAddress::Account(source_account),
58        salt: Uint256(salt),
59    })
60}
61
62pub fn get_contract_id(
63    contract_id_preimage: ContractIdPreimage,
64    network_passphrase: &str,
65) -> Result<stellar_strkey::Contract, Error> {
66    let network_id = Hash(Sha256::digest(network_passphrase.as_bytes()).into());
67    let preimage = HashIdPreimage::ContractId(HashIdPreimageContractId {
68        network_id,
69        contract_id_preimage,
70    });
71    let preimage_xdr = preimage.to_xdr(Limits::none())?;
72    Ok(stellar_strkey::Contract(
73        Sha256::digest(preimage_xdr).into(),
74    ))
75}