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:
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¶
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.