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

Storage Fields

Storage fields hold the persistent state of a contract. In Fe, storage is defined as struct types that contain storage-capable fields.

Storage is defined as a struct with storage-compatible fields:

pub struct TokenStorage {
pub balances: Map<u256, u256>,
pub total_supply: u256,
}
contract Token {
store: TokenStorage,
}

The contract field store holds an instance of TokenStorage, which persists between transactions.

All primitive types can be stored:

pub struct Config {
pub enabled: bool,
pub count: u256,
pub threshold: i128,
}

For key-value mappings, use StorageMap:

pub struct TokenStorage {
// Maps account -> balance
pub balances: Map<u256, u256>,
// Maps owner -> (spender -> allowance)
pub allowances: Map<u256, Map<u256, u256>>,
}

Storage structs can contain other structs:

pub struct Metadata {
pub name_length: u256,
pub decimals: u8,
}
pub struct TokenStorage {
pub balances: Map<u256, u256>,
pub metadata: Metadata,
}

Storage is accessed through effects, not directly:

fn get_balance(account: u256) -> u256 uses (store: TokenStorage) {
store.balances.get(account)
}
fn set_balance(account: u256, amount: u256) uses (mut store: TokenStorage) {
store.balances.set(account, amount)
}

In handlers, use the uses clause to access storage fields:

contract Token {
mut store: TokenStorage,
recv TokenMsg {
BalanceOf { account } -> u256 uses (store) {
store.balances.get(account)
}
}
}

Retrieve a value (returns zero/default if not set):

let balance = store.balances.get(account)

Store a value:

store.balances.set(account, new_balance)

For nested mappings, chain the operations:

pub struct AllowanceStorage {
// owner -> spender -> amount
pub allowances: Map<u256, Map<u256, u256>>,
}
fn get_allowance(owner: u256, spender: u256) -> u256 uses (store: AllowanceStorage) {
store.allowances.get(owner).get(spender)
}
fn set_allowance(owner: u256, spender: u256, amount: u256) uses (mut store: AllowanceStorage) {
store.allowances.get(owner).set(spender, amount)
}

Contracts can have multiple storage fields for logical separation:

pub struct BalanceStorage {
pub balances: Map<u256, u256>,
pub total_supply: u256,
}
pub struct OwnerStorage {
pub owner: u256,
pub pending_owner: u256,
}
contract OwnableToken {
mut tokens: BalanceStorage,
mut ownership: OwnerStorage,
recv TokenMsg {
Transfer { to, amount } -> bool uses (mut tokens) {
do_transfer(caller(), to, amount)
}
}
recv OwnerMsg {
TransferOwnership { new_owner } uses (mut ownership) {
initiate_transfer(new_owner)
}
}
}

Fe computes storage slots automatically. Each field gets a deterministic location based on:

  • The struct layout
  • The field position
  • For maps, the key combined with the base slot

You don’t need to manually specify storage slots.

ConceptDescription
Storage structStruct type containing persistent fields
Contract fieldInstance of storage struct in contract
StorageMap<K, V>Key-value mapping in storage
.get(key)Read from map
.set(key, value)Write to map
Effect accessUse with to provide storage to functions