Skip to main content
A Sigil contract consists of five key components: imports, the contract declaration, interface imports (optional), storage definitions, and the Guest trait implementation containing your contract logic.

Anatomy of a Contract

The contract! Macro

The contract! macro generates the necessary boilerplate for your contract:
What it does:
  • Generates wit-bindgen glue code
  • Creates the Guest trait you implement
  • Sets up WASM component exports
  • The name must match your WIT package
Requirements:
  • Must appear after use stdlib::*;
  • Name must match the contract name in your WIT file

Context Types

Every function in a Sigil contract receives a context as its first parameter. There are three context types:

ViewContext - Read-Only Queries

Available methods:
  • ctx.storage() - Access low-level storage
  • ctx.model() - Get generated storage model (read-only)
Use for: Functions that don’t modify state, callable via API

ProcContext - State-Modifying Transactions

Available methods:
  • ctx.signer() - Transaction signer
  • ctx.contract_signer() - Contract’s own address (for receiving tokens)
  • ctx.storage() - Access storage
  • ctx.model() - Get generated storage model (read-write)
  • ctx.generate_id() - Generate unique IDs
  • ctx.view_context() - Get read-only view
Use for: Functions that modify state, called via blockchain transactions

FallContext - Fallback Handler

Available methods:
  • ctx.signer() - Returns Option<Signer> (may be None for view calls)
  • ctx.proc_context() - Returns Option<ProcContext> (Some if called with signer)
  • ctx.view_context() - Always available
Use for: Generic delegation and proxy patterns

WIT Files

WIT (WebAssembly Interface Type) files define your contract’s public interface.

Relationship to Rust Code

  • WIT files are hand-written by you
  • They define the public API of your contract
  • Every exported function in WIT must be implemented in Rust
  • The contract! macro generates Rust types from your WIT

Example WIT File

Built-in WIT Interfaces

The kontor:built-in package provides:
  • context - Storage and execution context (ViewContext, ProcContext, FallContext)
  • numbers - Arbitrary precision Integer and Decimal types
  • error - Error type with variants (Message, Overflow, DivByZero, SyntaxError)
  • crypto - Hash functions
  • foreign - Cross-contract calls
See core/indexer/src/runtime/wit/deps/built-in.wit for complete reference.

Module Organization

Workspace Structure

Contracts are organized in a Cargo workspace:

One Contract Per Crate

Each contract is a separate Rust crate with:
  • Cargo.toml - Dependencies and build config
  • src/lib.rs - Contract implementation
  • wit/contract.wit - Interface definition
  • wit/deps/ - Symlink to built-in types

Build Configuration

Cargo.toml:
.cargo/config.toml:

Hooks

Sigil defines specific function names that serve as hooks:

init Hook

Called when:
  • Contract is first deployed (publish transaction)
  • Automatically by the runtime
Use for:
  • Setting initial storage values
  • Contract initialization logic
  • Data migrations for upgrades

fallback Hook

Called when:
  • A function is called that doesn’t exist
  • Primarily for proxy contracts
Use for:
  • Implementing proxy patterns
  • Version upgrades
  • Generic delegation

Quick Reference

Context Types

ProcContext
  • Enables state-modifying operations, such as balance transfers
  • Provides write access to storage and signer access via ctx.signer()
  • Used in functions like mint or transfer to update blockchain state
ViewContext
  • Supports read-only queries for inspecting contract state
  • Restricts access to read-only storage operations, no signer or mutations allowed
  • Used in functions like balance for retrieving data without modifying the blockchain
FallContext
  • Manages unmatched calls via the fallback hook, enabling proxy patterns
  • Converts to ViewContext or Option<ProcContext> for storage reads
  • Exclusive to the fallback function for dynamic routing

Context Traits (for helper functions)

WriteContext
  • For mutation logic (e.g., internal updates)
  • Implemented only by ProcContext
ReadContext
  • For read-only logic (e.g., internal queries)
  • Implemented by both ViewContext and ProcContext, enabling shared read operations

Storage

StorageRoot
  • Marks the root struct or enum for contract storage
Map<Key, Value>
  • Key-value store for collections (e.g., account balances)
  • Supports get, set, and keys methods
Storage Access
  • ctx.model() - Returns the typed storage model
  • Field accessors (e.g., ctx.model().ledger()) - Provide structured access
  • Get/set methods - No ctx parameter needed (e.g., ledger.get(&key), ledger.set(key, value))

Signer Access

  • ctx.signer() - Retrieves the transaction signer (ProcContext only)
  • ctx.contract_signer() - Returns the contract’s own address (for receiving tokens)

Cross-Contract Calls

Static imports:
Dynamic interfaces:

Utilities

crypto::generate_id() -> String
  • Generates unique IDs for entities (e.g., account IDs)
crypto::hash(String) -> (String, Vec<u8>)
  • Applies sha256 hash and returns hex encoded string and raw bytes
crypto::hash_with_salt(data: String, salt: String) -> (String, Vec<u8>)
  • Applies sha256 hash to string concatenated with salt

Error Type

Macros

contract!(name = “name”)
  • Defines contract name and generates boilerplate code from WIT file
import!(name, height, tx_index, path)
  • Statically imports another contract’s WIT for cross-contract calls
interface!(name, path)
  • Defines dynamic interface for runtime contract calls with dynamic addresses