Skip to main content
Version: next

Odra CLI

The Odra CLI library allows creating cli clients for your contracts. Instead of using casper-client with complex incantations, you can use the Odra CLI library to create a client that will be able to call your contract methods directly, by name, and with the correct arguments.

Deploy script

Let's go through an example available in the odra repository to see how to use the Odra CLI library. It creates a cli tool for a useful "DogContract".

To use the Odra CLI library in your project, you need to add odra-cli to your Cargo.toml file, alongside a new binary:

[dependencies]
...
odra-cli = "2"
...

[[bin]]
name = "odra-cli"
path = "src/bin/odra-cli.rs"

Then, create a new file in the src/bin directory named odra-cli.rs:

/// Deploys the `DogContract` and adds it to the container.
pub struct DeployDogScript;
impl DeployScript for DeployDogScript {
fn deploy(
&self,
env: &HostEnv,
container: &mut DeployedContractsContainer
) -> Result<(), odra_cli::deploy::Error> {
env.set_gas(350_000_000_000);
let dog_contract = DogContract::try_deploy(
env,
DogContractInitArgs {
barks: true,
weight: 10,
name: "Mantus".to_string()
}
)?;

container.add_contract(&dog_contract)?;

Ok(())
}
}

/// Main function to run the CLI tool.
pub fn main() {
OdraCli::new()
.about("Dog contract cli tool")
.deploy(DeployDogScript)
.contract::<DogContract>()
.build()
.run();
}

In the example above, we see an implementation of a simple DeployScript for our DogContract. It sets the gas limit, deploys the contract and adds it to a container. The main function creates a new OdraCli instance, and sets the deploy script, making it available for the user.

How to use it

Assuming the correct livenet environment is set up, you can run the cli tool using the following command:

cargo run --bin odra-cli

Which will display all of our options:

Dog contract cli tool

Usage: odra_cli <COMMAND>

Commands:
deploy Runs the deploy script
contract Commands for interacting with contracts
scenario Commands for running user-defined scenarios
help Print this message or the help of the given subcommand(s)

Options:
-h, --help Print help

First, we need to deploy the contract:

cargo run --bin odra_cli deploy

Which gives us an output:

cargo run --bin odra_cli -- deploy
Compiling odra-examples v2.0.0 (/home/kuba/Projekty/odra/odra/examples)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.65s
Running `../target/debug/odra_cli deploy`
💁 INFO : Found wasm under "wasm/DogContract.wasm".
💁 INFO : Deploying "DogContract".
🙄 WAIT : Waiting 10 for V1(TransactionV1Hash(10ce0134ac3a67772a668bb6c32a0dc74c09278f44d7896cc5419b8e2b2de33e)).
💁 INFO : Deploy "10ce0134ac3a67772a668bb6c32a0dc74c09278f44d7896cc5419b8e2b2de33e" successfully executed.
💁 INFO : Contract "contract-package-3e1e053c2e9377e823d9156e0663b7614f74eb524d47d9dc4a621f8cd06a357b" deployed.
💁 INFO : Command executed successfully

This will run the deploy script, and create a new file in the resources directory named deployed-contracts.toml:

time = "2025-05-22T14:40:31Z"

[[contracts]]
name = "DogContract"
package_hash = "hash-3e1e053c2e9377e823d9156e0663b7614f74eb524d47d9dc4a621f8cd06a357b"

All the calls to the contract will be made using this package hash.

Calling contract methods

To call a contract method, we need to use the contract command. The command itself will display all the available contracts:

cargo run --bin odra_cli -- contract

Which outputs:

Commands for interacting with contracts

Usage: odra_cli contract <COMMAND>

Commands:
DogContract Commands for interacting with the DogContract contract
help Print this message or the help of the given subcommand(s)

And when contract is selected, it will show us the available methods:

cargo run --bin odra_cli -- contract DogContract
Commands for interacting with the DogContract contract

Usage: odra_cli contract DogContract <COMMAND>

Commands:
barks Returns true if the dog barks.
weight Returns the dog's weight.
name Returns the dog's name.
walks_amount Adds a walk to the dog's walks.
walks_total_length Returns the total length of the dog's walks.
help Print this message or the help of the given subcommand(s)

To run a command, compose a command like this:

cargo run --bin odra_cli -- contract DogContract barks

It will result with:

💁  INFO : true
💁 INFO : Command executed successfully

Creating and running a scenario

Sometimes we want to run multiple calls one after another. To simplify this, we can create a scenario. To do this implement the Scenario trait in the odra-cli binary:


/// Checks if the name of the deployed dog matches the provided name.
pub struct DogCheckScenario;

impl Scenario for DogCheckScenario {
fn args(&self) -> Vec<CommandArg> {
vec![CommandArg::new(
"name",
"The name of the dog",
NamedCLType::String,
false,
false
)]
}

fn run(
&self,
env: &HostEnv,
container: DeployedContractsContainer,
args: ScenarioArgs
) -> Result<(), ScenarioError> {
let dog_contract = container.get_ref::<DogContract>(env)?;
let test_name = args.get_single::<String>("name")?;

env.set_gas(50_000_000);
let actual_name = dog_contract.try_name()?;

assert_eq!(test_name, actual_name, "Dog name mismatch");

Ok(())
}
}

impl ScenarioMetadata for DogCheckScenario {
const NAME: &'static str = "check";
const DESCRIPTION: &'static str =
"Checks if the name of the deployed dog matches the provided name";
}

The example above performs a simple check on the return value of one of the methods. Of course, there is no limit to how complex a scenario can be.

Remember to add the scenario in the main function:

/// Main function to run the CLI tool.
pub fn main() {
OdraCli::new()
.about("Dog contract cli tool")
.deploy(DeployDogScript)
.contract::<DogContract>()
.scenario::<DogCheckScenario>(DogCheckScenario) // New scenario
.build()
.run();
}

It will appear in the scenario command:

cargo run --bin odra_cli -- scenario

Will output:

Commands for running user-defined scenarios

Usage: odra_cli scenario <COMMAND>

Commands:
check Checks if the name of the deployed dog matches the provided name
help Print this message or the help of the given subcommand(s)

It can be run like this:

cargo run --bin odra_cli -- scenario check --name Doggy

This will output:

thread 'main' panicked at examples/bin/odra_cli.rs:59:9:
assertion `left == right` failed: Dog name mismatch
left: "Doggy"
right: "Mantus"