thruput-sdk 0.58.0

Thruput smart-contract SDK for Rust (rv32 guest runtime and native test harness)
Documentation
# Build a contract with Cargo

You can write and test a contract without the Thruput CLI. Cargo can also build
the RV32 ELF. Producing a deployable `.rv32a` requires a separate lowering step;
the CLI's `thruput build` performs that step. An ELF is not a deployed contract.

This example uses a local SDK clone and ordinary Cargo commands. It needs
Rust/rustup, a native linker, and access to crates.io. Native tests also
download the test executor; see [native executor setup](../../native-exec/README.md).

## Create a standalone project

Start in the parent directory of your `thruput-sdk-rs` clone:

```sh
cargo new --lib hello-contract
cd hello-contract
mkdir -p tests
cp ../thruput-sdk-rs/rust-toolchain.toml .
```

Use the following files. If your clone has a different name or location, change
both SDK dependency paths in the manifest and the `--config` path in the build
command. Cargo does not inherit configuration from a path dependency's checkout.

### `Cargo.toml`

```toml
[package]
name = "hello-contract"
version = "0.1.0"
edition = "2024"

[lib]
crate-type = ["rlib"]

[[bin]]
name = "hello_contract"
path = "src/main.rs"
required-features = ["entrypoints"]
test = false
bench = false

[features]
entrypoints = []
dev = ["thruput-sdk/dev"]

[target.'cfg(target_arch = "riscv32")'.dependencies]
thruput-sdk = { path = "../thruput-sdk-rs/crates/sdk", features = ["alloc"] }

[target.'cfg(not(target_arch = "riscv32"))'.dependencies]
thruput-sdk = { path = "../thruput-sdk-rs/crates/sdk", features = ["std"] }

[dev-dependencies]
hello-contract = { path = ".", features = ["dev"] }
```

`alloc` supports the owned strings used here. `std` is required on the host and
forbidden on the guest. The self-dependency enables the native executor during
tests. `entrypoints` includes the exported methods in the RV32 binary.

### `src/lib.rs`

```rust
#![cfg_attr(not(feature = "dev"), no_std)]

extern crate alloc;

use alloc::string::String;
use thruput_sdk::*;

thruput_sdk::declare_mock_contract!();

pub struct Greeting;

#[contract]
impl Greeting {
    #[contract(effect = "readOnly")]
    pub fn greet(name: String) -> String {
        alloc::format!("Hello, {name}!")
    }
}
```

### `src/main.rs`

```rust
#![no_std]
#![no_main]

extern crate hello_contract;
```

This wrapper links the contract library and its generated entrypoints. The SDK
supplies the guest runtime and linker script.

### `tests/greeting.rs`

```rust
use hello_contract::GreetingClient;

#[test]
fn greets_through_the_generated_client() {
    thruput_sdk::client_test(
        |env| hello_contract::register_mock_contract(env),
        |client: &GreetingClient| {
            assert_eq!(client.greet(String::from("friend")), "Hello, friend!");
            assert_eq!(client.greet(String::from("🦀")), "Hello, 🦀!");
        },
    );
}
```

## Test and build

From `hello-contract/`, run the native test:

```sh
cargo test
```

Build the RV32 ELF using the SDK's maintained target configuration:

```sh
cargo --config ../thruput-sdk-rs/example-contracts/.cargo/config.toml build \
  --release --target riscv32im-unknown-none-elf \
  --no-default-features --features entrypoints --bin hello_contract \
  -Zbuild-std=core,alloc --target-dir target
```

The explicit `--target-dir` keeps this app's output in its own directory. The
target configuration sets the required linker and runtime flags; `build-std`
rebuilds `core` and `alloc` with those flags. Native tests do not need it. The
binary uses an underscored name to match the CLI build convention.

The output is `target/riscv32im-unknown-none-elf/release/hello_contract`, an ELF
intermediate containing entrypoints and raw specification data. It is not a
deployable `.rv32a`, and passing native tests does not prove guest execution.
To produce the lowered artifact and finalized specs, use a compatible Thruput
CLI; see [Build guest contracts](../../../CONTRIBUTING.md#build-guest-contracts).

The repository's `scripts/cargo-example-smoke.sh` builds these exact file
examples in a temporary standalone project. SDK CI runs this check so the guide
stays aligned with the code.

For storage and tests across transactions, continue with the executable examples
linked from [Test a contract natively](../../../README.md#test-a-contract-natively).