WIT Reference
package chain:contract@1.0.0;
/// Host functions available to every contract. Each contract runs in an
/// isolated sandbox with no filesystem, network, clock, or randomness —
/// these imports are the only way to interact with the outside world.
interface host {
// ── Storage ──────────────────────────────────────────────────────
// Each contract has its own isolated key-value namespace. Writes
// accumulate in a transactional overlay during execution and are
// committed atomically on success or discarded entirely on failure.
/// Read a value from this contract's storage.
/// Returns `none` if the key has never been set.
kv-get: func(key: string) -> option<list<u8>>;
/// Write a value to this contract's storage.
/// Traps if called during a read-only query.
kv-set: func(key: string, value: list<u8>);
/// Delete a key from this contract's storage.
/// Traps if called during a read-only query.
kv-delete: func(key: string);
/// Check whether a key exists without reading its value.
/// More efficient than `kv-get` when you only need an existence check.
kv-has: func(key: string) -> bool;
// ── Events ───────────────────────────────────────────────────────
/// Emit a typed event that is included in the transaction receipt.
/// `kind` is an application-defined tag (e.g. "transfer") and `data`
/// is an arbitrary byte payload. Each byte of data costs fuel.
/// Traps if called during a read-only query.
emit-event: func(kind: string, data: list<u8>);
// ── Identity ─────────────────────────────────────────────────────
/// Get the immediate caller's address (32 bytes). For a user-submitted
/// transaction this is the signer's Ed25519 public key. In a
/// cross-contract sub-message from contract A → B, B's `get-sender`
/// returns A's contract address. Use this for access-control checks.
get-sender: func() -> list<u8>;
/// Get this contract instance's own address (32 bytes). The address is
/// deterministically derived from the creator, code ID, and
/// instantiation salt, so it can be pre-computed off-chain.
get-self-address: func() -> list<u8>;
/// Get the original transaction signer (32 bytes). Unlike `get-sender`,
/// this value never changes across sub-message depths — it always
/// identifies the account that signed the root transaction.
get-origin: func() -> list<u8>;
// ── Block context ────────────────────────────────────────────────
/// Get the height of the block currently being executed.
get-block-height: func() -> u64;
// ── Debugging ────────────────────────────────────────────────────
/// Write a debug message to the node's log output. These messages are
/// visible to node operators but are **not** stored on-chain.
log: func(msg: string);
// ── Cross-contract calls ─────────────────────────────────────────
/// Controls whether (and when) the `reply` export is called after a
/// sub-message dispatched with `dispatch` finishes executing.
enum reply-on {
/// Fire and forget. If the sub-message fails the entire
/// transaction is reverted — no reply handler is called.
never,
/// Call `reply` only on success. Failure still reverts the
/// entire transaction.
success,
/// Call `reply` only on failure. This lets the parent contract
/// handle errors gracefully without reverting.
error,
/// Call `reply` on both success and failure.
always,
}
/// Queue a state-changing sub-message for deferred execution. The
/// target contract's `exec` runs **after** this contract returns,
/// eliminating reentrancy by construction. Returns a locally-unique
/// `msg-id` that is later passed to `reply` so you can match
/// responses. `funds` is reserved for future use (pass 0).
dispatch: func(target: list<u8>, msg: list<u8>, reply-on: reply-on, funds: u64) -> result<u64, string>;
/// Synchronously call another contract's `query` export and return
/// the result inline. Because queries are read-only, this is safe
/// from reentrancy and does not require the dispatch/reply pattern.
query-contract: func(target: list<u8>, msg: list<u8>) -> result<list<u8>, string>;
}
world contract-world {
import host;
/// Constructor — called exactly once when the contract is instantiated.
/// `msg` contains application-defined initialization parameters.
export init: func(msg: list<u8>) -> result<list<u8>, string>;
/// Handle a state-changing transaction. May call `dispatch` to send
/// sub-messages, `emit-event` to log events, and read/write storage.
export exec: func(msg: list<u8>) -> result<list<u8>, string>;
/// Handle a read-only query. Storage writes, event emission, and
/// dispatch are all forbidden (they will trap). Can be called
/// synchronously by other contracts via `query-contract`.
export query: func(msg: list<u8>) -> result<list<u8>, string>;
/// Derive a deterministic consensus key for a service payload. Services
/// using the `contract-query` consensus strategy call this export on the
/// target contract and compare the returned bytes across validators.
/// Often this just returns `payload` unchanged.
export service-consensus-query: func(payload: list<u8>) -> list<u8>;
/// Called when a dispatched sub-message completes, if the `reply-on`
/// mode matches the outcome. `msg-id` is the ID returned by
/// `dispatch`. On success `data` contains the sub-message's return
/// value; on failure it contains the error message.
export reply: func(msg-id: u64, success: bool, data: list<u8>) -> result<list<u8>, string>;
}