Skip to content
Pre-Release: Fe is under active development. This documentation covers the upcoming release. Follow progress on GitHub

Storage Structs

Storage structs are structs designed to hold persistent blockchain state. They serve as effect types, enabling the explicit storage access pattern that Fe uses.

A storage struct contains fields that persist on-chain:

pub struct TokenStorage {
pub balances: Map<u256, u256>,
pub total_supply: u256,
pub owner: u256,
}

Key characteristics:

  • Contains Map fields for mappings
  • Contains primitive fields for simple values
  • Used as effect types with uses clause
  • Bound to contract fields

Storage structs become effect types. Functions declare them in uses:

pub struct TokenStorage {
pub balances: Map<u256, u256>,
pub total_supply: u256,
}
// Function that reads from storage
fn get_balance(account: u256) -> u256 uses (store: TokenStorage) {
store.balances.get(account)
}
// Function that writes to storage
fn set_balance(account: u256, amount: u256) uses (mut store: TokenStorage) {
store.balances.set(account, amount)
}

Contracts hold storage structs as fields and provide them as effects:

contract Token {
mut store: TokenStorage,
recv TokenMsg {
BalanceOf { account } -> u256 uses (store) {
get_balance(account)
}
Transfer { to, amount } -> bool uses (mut store) {
transfer(caller(), to, amount)
}
}
}

The handler’s uses (store) clause binds the contract field to the effect.

For simple contracts, one storage struct is sufficient:

pub struct CounterStorage {
pub value: u256,
}
fn get_value() -> u256 uses (store: CounterStorage) {
store.value
}
fn increment() uses (mut store: CounterStorage) {
store.value = store.value + 1
}

For complex contracts, split storage by concern:

// Token balances
pub struct BalanceStorage {
pub balances: Map<u256, u256>,
pub total_supply: u256,
}
// Allowance tracking
pub struct AllowanceStorage {
pub allowances: Map<u256, Map<u256, u256>>,
}
// Access control
pub struct OwnerStorage {
pub owner: u256,
pub pending_owner: u256,
}
// Pausability
pub struct PauseStorage {
pub paused: bool,
}

Each becomes an independent effect:

fn transfer(from: u256, to: u256, amount: u256)
-> bool uses (mut balances: BalanceStorage, pause: PauseStorage)
{
if pause.paused {
return false
}
// ... transfer logic
true
}

Map is the primary collection type for storage:

pub struct Registry {
// Simple mapping: key -> value
pub entries: Map<u256, u256>,
// Nested mapping: key -> (key -> value)
pub nested: Map<u256, Map<u256, u256>>,
}

Access patterns:

fn get_entry(key: u256) -> u256 uses (reg: Registry) {
reg.entries.get(key)
}
fn set_entry(key: u256, value: u256) uses (mut reg: Registry) {
reg.entries.set(key, value)
}
fn get_nested(outer: u256, inner: u256) -> u256 uses (reg: Registry) {
reg.nested.get(outer).get(inner)
}
fn set_nested(outer: u256, inner: u256, value: u256) uses (mut reg: Registry) {
reg.nested.get(outer).set(inner, value)
}

Storage structs and their fields are typically public:

pub struct TokenStorage {
pub balances: Map<u256, u256>, // Public for effect access
pub total_supply: u256,
}

The pub on fields allows store.balances syntax in functions using the effect.

AspectStorage StructRegular Struct
PurposePersistent stateIn-memory data
ContainsMap, primitivesAny types
Used asEffect typeValue type
AccessVia uses clauseDirect
LocationOn-chainMemory

A full token with storage structs:

// Storage definitions
pub struct TokenStorage {
pub balances: Map<u256, u256>,
pub allowances: Map<u256, Map<u256, u256>>,
pub total_supply: u256,
}
pub struct MetadataStorage {
pub name_hash: u256,
pub symbol_hash: u256,
pub decimals: u8,
}
// Functions using storage effects
fn get_balance(account: u256) -> u256 uses (tokens: TokenStorage) {
tokens.balances.get(account)
}
fn transfer(from: u256, to: u256, amount: u256) -> bool uses (mut tokens: TokenStorage) {
let from_bal = tokens.balances.get(from)
if from_bal < amount {
return false
}
tokens.balances.set(from, from_bal - amount)
let to_bal = tokens.balances.get(to)
tokens.balances.set(to, to_bal + amount)
true
}
fn get_decimals() -> u8 uses (metadata: MetadataStorage) {
metadata.decimals
}
// Contract binding storage to effects
contract Token {
mut tokens: TokenStorage,
metadata: MetadataStorage,
recv Erc20 {
Transfer { to, amount } -> bool uses (mut tokens) {
transfer(caller(), to, amount)
}
BalanceOf { account } -> u256 uses (tokens) {
get_balance(account)
}
Decimals -> u8 uses (metadata) {
get_decimals()
}
}
}
ConceptDescription
Storage structStruct holding persistent state
Effect typeStorage struct used in uses clause
Map<K, V>Key-value storage field
uses (store: Storage)Read-only access
uses (mut store: Storage)Read-write access
Handler uses (field)Bind contract field to effect in handlers