diff --git a/cmd/soroban-cli/src/commands/contract/info.rs b/cmd/soroban-cli/src/commands/contract/info.rs index 6192c1c61e..08f121caeb 100644 --- a/cmd/soroban-cli/src/commands/contract/info.rs +++ b/cmd/soroban-cli/src/commands/contract/info.rs @@ -6,6 +6,7 @@ pub mod env_meta; pub mod interface; pub mod meta; pub mod shared; +pub mod wasm_hash; #[derive(Debug, clap::Subcommand)] pub enum Cmd { @@ -49,6 +50,9 @@ pub enum Cmd { /// /// Outputs no data when no data is present in the contract. EnvMeta(env_meta::Cmd), + + /// Get the wasm hash of a deployed contract + WasmHash(wasm_hash::Cmd), } #[derive(thiserror::Error, Debug)] @@ -59,6 +63,8 @@ pub enum Error { Meta(#[from] meta::Error), #[error(transparent)] EnvMeta(#[from] env_meta::Error), + #[error(transparent)] + WasmHash(#[from] wasm_hash::Error), } impl Cmd { @@ -67,6 +73,7 @@ impl Cmd { Cmd::Interface(interface) => interface.run(global_args).await?, Cmd::Meta(meta) => meta.run(global_args).await?, Cmd::EnvMeta(env_meta) => env_meta.run(global_args).await?, + Cmd::WasmHash(cmd) => cmd.run(global_args).await?, }; println!("{result}"); Ok(()) diff --git a/cmd/soroban-cli/src/commands/contract/info/wasm_hash.rs b/cmd/soroban-cli/src/commands/contract/info/wasm_hash.rs new file mode 100644 index 0000000000..e943ecbc48 --- /dev/null +++ b/cmd/soroban-cli/src/commands/contract/info/wasm_hash.rs @@ -0,0 +1,67 @@ +use clap::{arg, command, Command, ArgMatches}; +use soroban_rpc::client::Client; +use soroban_xdr::{ScAddress, ScVal, DecodeError}; +use stellar_xdr::XdrCodec; +use crate::config::Config; +use crate::error::Result; +use clap::Parser; +use stellar_xdr::curr as xdr; + +use crate::commands::{config::network, global}; +use crate::config::locator; +use crate::rpc; + +#[derive(Parser, Debug, Clone)] +#[group(skip)] +pub struct Cmd { + #[command(flatten)] + pub config_locator: locator::Args, + + #[command(flatten)] + pub network: network::Args, + + /// Contract ID to get the wasm hash for + #[arg(long)] + pub contract_id: stellar_strkey::Contract, +} + +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error(transparent)] + Config(#[from] locator::Error), + + #[error(transparent)] + Network(#[from] network::Error), + + #[error(transparent)] + Rpc(#[from] rpc::Error), +} + +impl Cmd { + pub async fn run(&self, _global_args: &global::Args) -> Result<(), Error> { + let network = self.network.get(&self.config_locator)?; + let client = network.get_client()?; + + // Get the contract instance ledger entry + let key = xdr::LedgerKey::ContractData(xdr::LedgerKeyContractData { + contract: self.contract_id.clone().into(), + key: xdr::ScVal::LedgerKeyContractInstance, + durability: xdr::ContractDataDurability::Persistent, + }); + + let entry = client.get_ledger_entry(&key).await?; + + // Extract the wasm hash from the contract instance + if let xdr::LedgerEntryData::ContractData(data) = entry.data { + if let xdr::ScVal::ContractInstance(instance) = data.val { + if let xdr::ContractExecutable::Wasm(hash) = instance.executable { + println!("{}", hex::encode(hash.0)); + return Ok(()); + } + } + } + + Err(rpc::Error::InvalidResponse("Contract instance not found".into()).into()) + } +} + diff --git a/cmd/soroban-cli/src/commands/contract/mod.rs b/cmd/soroban-cli/src/commands/contract/mod.rs index dd642755ad..3e454b3ce8 100644 --- a/cmd/soroban-cli/src/commands/contract/mod.rs +++ b/cmd/soroban-cli/src/commands/contract/mod.rs @@ -16,6 +16,7 @@ pub mod read; pub mod restore; pub mod upload; + use crate::{commands::global, print::Print}; #[derive(Debug, clap::Subcommand)] @@ -91,6 +92,7 @@ pub enum Cmd { /// /// If no keys are specificed the contract itself is restored. Restore(restore::Cmd), + } #[derive(thiserror::Error, Debug)] @@ -142,6 +144,7 @@ pub enum Error { #[error(transparent)] Restore(#[from] restore::Error), + } impl Cmd {