Skip to main content
Sigil uses a hierarchical path-based storage model, similar to a filesystem. The storage system provides type-safe accessors through Rust derives that generate methods for reading and writing state.

Storage Derives

StorageRoot - Top-Level Contract Storage

Every contract has exactly one StorageRoot:
What it generates:
  • .init(ctx) method to initialize storage
  • Accessible via ctx.model()
Usage:

Storage - Nested Structures

For structures nested within your storage root:
What it generates:
  • Same accessors as StorageRoot but without .init()
  • Used for nested data structures

Store and Model

#[derive(Store)] - Generates only persistence methods (__set()) #[derive(Model)] - Generates only read/write accessor types (*Model, *WriteModel) Most contracts only need StorageRoot and Storage.

Type Constraints

Supported Storage Types

Primitive types:
  • u64, s64, bool, String
Built-in types:
  • Integer - Arbitrary precision (256-bit)
  • Decimal - Arbitrary precision with decimals
  • ContractAddress - References to other contracts
Structured types:
  • Enums and structs with #[derive(Storage)] or #[derive(Wavey)]
  • Option<T> where T is a supported type
  • Map<K, V> where K: ToString + FromString, V is a supported type

Not Directly Supported

Vec - Use Map<u64, T> as workaround:
Unsupported primitives - Use alternatives:
  • No u32, u16, u8 → Use u64
  • No f64, f32 → Use Decimal

Working with Basic Fields

Working with Options

Working with Maps

Maps provide key-value storage:

Map API

For read-only access (ViewContext):
For read-write access (ProcContext):

Map Initialization with Data

Nested Structures

Storage structures can be nested arbitrarily deep:

Updating Nested Fields with Closures

Storage Key Scoping

Keys are scoped by path, preventing collisions:
Keys in map_a and map_b are independent—they can have the same key without collision.

Gas Considerations

Storage operations consume gas: General guidance:
  • Storage writes are more expensive than reads
  • Minimize storage writes
  • Cache reads when accessing multiple times
  • Use lazy evaluation (models load only what you access)
  • Map iterations over many keys can be expensive