Skip to content

Contract Development Overview

What is a contract?

A Wasichain contract is a wasm32-wasip2 component that implements the contract-world WIT interface. Each contract is a standalone Wasm component linked against chain:contract@1.0.0 host imports.

The four exports

Every contract must export four functions:

Export Signature When called
init func(msg: list<u8>) -> result<list<u8>, string> Once, when the contract is instantiated
exec func(msg: list<u8>) -> result<list<u8>, string> On each ExecContract transaction
query func(msg: list<u8>) -> result<list<u8>, string> On read-only queries (no state changes allowed)
reply func(msg-id: u64, success: bool, data: list<u8>) -> result<list<u8>, string> When a dispatched sub-message completes (if reply-on matches)

Messages are opaque byte slices. By convention, contracts use JSON serialization via serde_json, but any encoding works.

Scaffolding a contract

Contracts use wit_bindgen to generate Rust bindings from the WIT file:

wit_bindgen::generate!({
    path: "../../../config/wit",
    world: "contract-world",
});

Then implement the Guest trait and use the export! macro:

struct MyContract;
export!(MyContract);

impl Guest for MyContract {
    fn init(msg: Vec<u8>) -> Result<Vec<u8>, String> { /* ... */ }
    fn exec(msg: Vec<u8>) -> Result<Vec<u8>, String> { /* ... */ }
    fn query(msg: Vec<u8>) -> Result<Vec<u8>, String> { /* ... */ }
    fn reply(_msg_id: u64, _success: bool, _data: Vec<u8>) -> Result<Vec<u8>, String> {
        Err("reply not implemented".into())
    }
}

Build target

cargo build --target wasm32-wasip2 --release

Deterministic execution

Contracts run inside a sandboxed Wasmtime instance with no access to:

  • Filesystem, sockets, or network
  • Clocks or timers
  • Random number generators
  • Process or environment APIs

The only I/O available is through the host functions defined in the WIT ABI. See WIT ABI Reference for the full list.

Actor model

Contracts communicate through an asynchronous dispatch/reply pattern rather than synchronous function calls. When contract A dispatches a message to contract B, B executes after A returns. A can optionally receive a reply callback with the result. See Cross-Contract Calls for details.

Synchronous read-only queries between contracts are also supported via query-contract.