Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add contract info #1532

Merged
merged 15 commits into from
Aug 13, 2024
683 changes: 342 additions & 341 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@ version = "=21.2.0"
version = "21.2.0"

[workspace.dependencies.soroban-spec]
version = "=21.2.0"
version = "=21.5.0"

[workspace.dependencies.soroban-spec-rust]
version = "=21.2.0"
version = "=21.5.0"

[workspace.dependencies.soroban-spec-json]
version = "=21.3.0"
Expand Down
132 changes: 132 additions & 0 deletions FULL_HELP_DOCS.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ Tools for smart contract developers
* `deploy` — Deploy a wasm contract
* `fetch` — Fetch a contract's Wasm binary
* `id` — Generate the contract id for a given contract or asset
* `info` — Access info about contracts
* `init` — Initialize a Soroban project with an example contract
* `inspect` — Inspect a WASM file listing contract functions, meta, etc
* `install` — Install a WASM file to the ledger without creating a contract instance
Expand Down Expand Up @@ -386,6 +387,137 @@ Deploy normal Wasm Contract



## `stellar contract info`

Access info about contracts

**Usage:** `stellar contract info <COMMAND>`

###### **Subcommands:**

* `interface` — Output the interface of a contract
* `meta` — Output the metadata stored in a contract
* `env-meta` — Output the env required metadata stored in a contract



## `stellar contract info interface`

Output the interface of a contract.

A contract's interface describes the functions, parameters, and types that the contract makes accessible to be called.

The data outputted by this command is a stream of `SCSpecEntry` XDR values. See the type definitions in [stellar-xdr](https://github.com/stellar/stellar-xdr). [See also XDR data format](https://developers.stellar.org/docs/learn/encyclopedia/data-format/xdr).

Outputs no data when no data is present in the contract.

**Usage:** `stellar contract info interface [OPTIONS] <--wasm <WASM>|--wasm-hash <WASM_HASH>|--id <CONTRACT_ID>>`

###### **Options:**

* `--wasm <WASM>` — Wasm file to extract the data from
* `--wasm-hash <WASM_HASH>` — Wasm hash to get the data for
* `--id <CONTRACT_ID>` — Contract id to get the data for
* `--rpc-url <RPC_URL>` — RPC server endpoint
* `--network-passphrase <NETWORK_PASSPHRASE>` — Network passphrase to sign the transaction sent to the rpc server
* `--network <NETWORK>` — Name of network to use from config
* `--global` — Use global config
* `--config-dir <CONFIG_DIR>` — Location of config directory, default is "."
* `--output <OUTPUT>` — Format of the output

Default value: `rust`

Possible values:
- `rust`:
Rust code output of the contract interface
- `xdr-base64`:
XDR output of the info entry
- `json`:
JSON output of the info entry (one line, not formatted)
- `json-formatted`:
Formatted (multiline) JSON output of the info entry




## `stellar contract info meta`

Output the metadata stored in a contract.

A contract's meta is a series of key-value pairs that the contract developer can set with any values to provided metadata about the contract. The meta also contains some information like the version of Rust SDK, and Rust compiler version.

The data outputted by this command is a stream of `SCMetaEntry` XDR values. See the type definitions in [stellar-xdr](https://github.com/stellar/stellar-xdr). [See also XDR data format](https://developers.stellar.org/docs/learn/encyclopedia/data-format/xdr).

Outputs no data when no data is present in the contract.

**Usage:** `stellar contract info meta [OPTIONS] <--wasm <WASM>|--wasm-hash <WASM_HASH>|--id <CONTRACT_ID>>`

###### **Options:**

* `--wasm <WASM>` — Wasm file to extract the data from
* `--wasm-hash <WASM_HASH>` — Wasm hash to get the data for
* `--id <CONTRACT_ID>` — Contract id to get the data for
* `--rpc-url <RPC_URL>` — RPC server endpoint
* `--network-passphrase <NETWORK_PASSPHRASE>` — Network passphrase to sign the transaction sent to the rpc server
* `--network <NETWORK>` — Name of network to use from config
* `--global` — Use global config
* `--config-dir <CONFIG_DIR>` — Location of config directory, default is "."
* `--output <OUTPUT>` — Format of the output

Default value: `text`

Possible values:
- `text`:
Text output of the meta info entry
- `xdr-base64`:
XDR output of the info entry
- `json`:
JSON output of the info entry (one line, not formatted)
- `json-formatted`:
Formatted (multiline) JSON output of the info entry




## `stellar contract info env-meta`

Output the env required metadata stored in a contract.

Env-meta is information stored in all contracts, in the `contractenvmetav0` WASM custom section, about the environment that the contract was built for. Env-meta allows the Soroban Env to know whether the contract is compatibility with the network in its current configuration.

The data outputted by this command is a stream of `SCEnvMetaEntry` XDR values. See the type definitions in [stellar-xdr](https://github.com/stellar/stellar-xdr). [See also XDR data format](https://developers.stellar.org/docs/learn/encyclopedia/data-format/xdr).

Outputs no data when no data is present in the contract.

**Usage:** `stellar contract info env-meta [OPTIONS] <--wasm <WASM>|--wasm-hash <WASM_HASH>|--id <CONTRACT_ID>>`

###### **Options:**

* `--wasm <WASM>` — Wasm file to extract the data from
* `--wasm-hash <WASM_HASH>` — Wasm hash to get the data for
* `--id <CONTRACT_ID>` — Contract id to get the data for
* `--rpc-url <RPC_URL>` — RPC server endpoint
* `--network-passphrase <NETWORK_PASSPHRASE>` — Network passphrase to sign the transaction sent to the rpc server
* `--network <NETWORK>` — Name of network to use from config
* `--global` — Use global config
* `--config-dir <CONFIG_DIR>` — Location of config directory, default is "."
* `--output <OUTPUT>` — Format of the output

Default value: `text`

Possible values:
- `text`:
Text output of the meta info entry
- `xdr-base64`:
XDR output of the info entry
- `json`:
JSON output of the info entry (one line, not formatted)
- `json-formatted`:
Formatted (multiline) JSON output of the info entry




## `stellar contract init`

Initialize a Soroban project with an example contract
Expand Down
21 changes: 14 additions & 7 deletions cmd/crates/soroban-spec-tools/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,11 @@ impl Spec {
vec![]
};

let mut spec_base64 = None;
let spec = if let Some(spec) = spec {
spec_base64 = Some(base64.encode(spec));
let cursor = Cursor::new(spec);
let mut read = Limited::new(cursor, Limits::none());
ScSpecEntry::read_xdr_iter(&mut read).collect::<Result<Vec<_>, xdr::Error>>()?
let (spec_base64, spec) = if let Some(spec) = spec {
let (spec_base64, spec) = Spec::spec_to_base64(spec)?;
(Some(spec_base64), spec)
} else {
vec![]
(None, vec![])
};

Ok(Spec {
Expand All @@ -106,6 +103,16 @@ impl Spec {
.join(",\n");
Ok(format!("[{spec}]"))
}

pub fn spec_to_base64(spec: &[u8]) -> Result<(String, Vec<ScSpecEntry>), Error> {
let spec_base64 = base64.encode(spec);
let cursor = Cursor::new(spec);
let mut read = Limited::new(cursor, Limits::none());
Ok((
spec_base64,
ScSpecEntry::read_xdr_iter(&mut read).collect::<Result<Vec<_>, xdr::Error>>()?,
))
}
}

impl Display for Spec {
Expand Down
44 changes: 4 additions & 40 deletions cmd/soroban-cli/src/commands/contract/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,13 @@ use std::str::FromStr;
use std::{fmt::Debug, fs, io};

use clap::{arg, command, Parser};
use stellar_xdr::curr::{ContractDataEntry, ContractExecutable, ScVal};

use crate::commands::contract::fetch::Error::{ContractIsStellarAsset, UnexpectedContractToken};
use crate::commands::{global, NetworkRunnable};
use crate::config::{
self, locator,
network::{self, Network},
};
use crate::utils::rpc::get_remote_wasm_from_hash;
use crate::{
rpc::{self, Client},
Pwd,
};
use crate::{wasm, Pwd};

#[derive(Parser, Debug, Default, Clone)]
#[allow(clippy::struct_excessive_bools)]
Expand Down Expand Up @@ -53,8 +47,6 @@ impl Pwd for Cmd {

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
Rpc(#[from] rpc::Error),
#[error(transparent)]
Config(#[from] config::Error),
#[error(transparent)]
Expand All @@ -67,13 +59,8 @@ pub enum Error {
Network(#[from] network::Error),
#[error("cannot create contract directory for {0:?}")]
CannotCreateContractDir(PathBuf),
#[error("unexpected contract data {0:?}")]
UnexpectedContractToken(ContractDataEntry),
#[error(
"cannot fetch wasm for contract because the contract is \
a network built-in asset contract that does not have a downloadable code binary"
)]
ContractIsStellarAsset(),
#[error(transparent)]
Wasm(#[from] wasm::Error),
}

impl From<Infallible> for Error {
Expand Down Expand Up @@ -110,14 +97,6 @@ impl Cmd {
pub fn network(&self) -> Result<Network, Error> {
Ok(self.network.get(&self.locator)?)
}

fn contract_id(&self) -> Result<[u8; 32], Error> {
let network = self.network()?;
Ok(self
.locator
.resolve_contract_id(&self.contract_id, &network.network_passphrase)?
.0)
}
}

#[async_trait::async_trait]
Expand All @@ -130,21 +109,6 @@ impl NetworkRunnable for Cmd {
config: Option<&config::Args>,
) -> Result<Vec<u8>, Error> {
let network = config.map_or_else(|| self.network(), |c| Ok(c.get_network()?))?;
tracing::trace!(?network);
let contract_id = self.contract_id()?;
let client = Client::new(&network.rpc_url)?;
client
.verify_network_passphrase(Some(&network.network_passphrase))
.await?;
let data_entry = client.get_contract_data(&contract_id).await?;
if let ScVal::ContractInstance(contract) = &data_entry.val {
return match &contract.executable {
ContractExecutable::Wasm(hash) => {
Ok(get_remote_wasm_from_hash(&client, hash).await?)
}
ContractExecutable::StellarAsset => Err(ContractIsStellarAsset()),
};
}
return Err(UnexpectedContractToken(data_entry));
return Ok(wasm::fetch_from_contract(&self.contract_id, &network, &self.locator).await?);
}
}
72 changes: 72 additions & 0 deletions cmd/soroban-cli/src/commands/contract/info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use std::fmt::Debug;

pub mod env_meta;
pub mod interface;
pub mod meta;
mod shared;

#[derive(Debug, clap::Subcommand)]
pub enum Cmd {
/// Output the interface of a contract.
///
/// A contract's interface describes the functions, parameters, and
/// types that the contract makes accessible to be called.
///
/// The data outputted by this command is a stream of `SCSpecEntry` XDR values.
/// See the type definitions in [stellar-xdr](https://github.com/stellar/stellar-xdr).
/// [See also XDR data format](https://developers.stellar.org/docs/learn/encyclopedia/data-format/xdr).
///
/// Outputs no data when no data is present in the contract.
Interface(interface::Cmd),

/// Output the metadata stored in a contract.
///
/// A contract's meta is a series of key-value pairs that the contract
/// developer can set with any values to provided metadata about the
/// contract. The meta also contains some information like the version
/// of Rust SDK, and Rust compiler version.
///
/// The data outputted by this command is a stream of `SCMetaEntry` XDR values.
/// See the type definitions in [stellar-xdr](https://github.com/stellar/stellar-xdr).
/// [See also XDR data format](https://developers.stellar.org/docs/learn/encyclopedia/data-format/xdr).
///
/// Outputs no data when no data is present in the contract.
Meta(meta::Cmd),

/// Output the env required metadata stored in a contract.
///
/// Env-meta is information stored in all contracts, in the
/// `contractenvmetav0` WASM custom section, about the environment
/// that the contract was built for. Env-meta allows the Soroban Env
/// to know whether the contract is compatibility with the network in
/// its current configuration.
///
/// The data outputted by this command is a stream of `SCEnvMetaEntry` XDR values.
/// See the type definitions in [stellar-xdr](https://github.com/stellar/stellar-xdr).
/// [See also XDR data format](https://developers.stellar.org/docs/learn/encyclopedia/data-format/xdr).
///
/// Outputs no data when no data is present in the contract.
EnvMeta(env_meta::Cmd),
}

#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error(transparent)]
Interface(#[from] interface::Error),
#[error(transparent)]
Meta(#[from] meta::Error),
#[error(transparent)]
EnvMeta(#[from] env_meta::Error),
}

impl Cmd {
pub async fn run(&self) -> Result<(), Error> {
let result = match &self {
Cmd::Interface(interface) => interface.run().await?,
Cmd::Meta(meta) => meta.run().await?,
Cmd::EnvMeta(env_meta) => env_meta.run().await?,
};
println!("{result}");
Ok(())
}
}
Loading
Loading