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

Contract Composition

Fe’s effect system enables clean contract composition through helper functions and modular storage. This section covers patterns for organizing well-structured contracts.

Unlike Solidity’s inheritance, Fe uses composition through:

  • Standalone functions with effect dependencies
  • Modular storage structs for logical separation
  • Multiple recv blocks for interface organization
// Modular storage
pub struct BalanceStorage { pub total: u256 }
pub struct OwnerStorage { pub owner: u256 }
// Reusable functions
fn transfer(from: u256, to: u256, amount: u256) -> bool uses (mut balances: BalanceStorage) {
let _ = (from, to, amount)
true
}
fn only_owner() uses (ownership: OwnerStorage) {
let _ = ownership
}
// Contract composes everything
contract Token {
balances: BalanceStorage,
ownership: OwnerStorage,
}

Extract business logic into functions that declare their effect dependencies:

pub struct TokenStorage {
pub balances: StorageMap<u256, u256>,
pub total_supply: u256,
}
// Read-only helper
fn get_balance(account: u256) -> u256 uses (store: TokenStorage) {
store.balances.get(account)
}
// Mutating helper
fn add_balance(account: u256, amount: u256) uses (mut store: TokenStorage) {
let current = store.balances.get(account)
store.balances.set(account, current + amount)
}
fn sub_balance(account: u256, amount: u256) -> bool uses (mut store: TokenStorage) {
let current = store.balances.get(account)
if current < amount {
return false
}
store.balances.set(account, current - amount)
true
}
// Higher-level helper composing lower-level ones
fn transfer(from: u256, to: u256, amount: u256) -> bool uses (mut store: TokenStorage) {
if !sub_balance(from, amount) {
return false
}
add_balance(to, amount)
true
}

Split storage into logical units:

// Core token state
pub struct BalanceStorage {
pub balances: StorageMap<u256, u256>,
pub total_supply: u256,
}
// Ownership state
pub struct OwnerStorage {
pub owner: u256,
}
// Pausability state
pub struct PauseStorage {
pub paused: bool,
}
// Message definitions
msg TokenMsg {
#[selector = 0xa9059cbb]
Transfer { to: u256, amount: u256 } -> bool,
}
msg AdminMsg {
#[selector = 0x8456cb59]
Pause {} -> bool,
}
contract Token {
mut balances: BalanceStorage,
ownership: OwnerStorage,
mut pause_state: PauseStorage,
// Each handler uses only what it needs
recv TokenMsg {
Transfer { to, amount } -> bool uses (ctx: Ctx, mut balances, pause_state) {
require_not_paused()
transfer(ctx.caller(), to, amount)
}
}
recv AdminMsg {
Pause {} -> bool uses (ctx: Ctx, ownership, mut pause_state) {
require_owner(ownership.owner)
set_paused(true)
true
}
}
}

Implement access control as a reusable module:

pub struct OwnerStorage {
pub owner: u256,
}
fn get_owner() -> u256 uses (ownership: OwnerStorage) {
ownership.owner
}
fn require_owner() uses (ctx: Ctx, ownership: OwnerStorage) {
if ctx.caller() != ownership.owner {
revert(0, 0)
}
}
fn transfer_ownership(new_owner: u256) uses (ctx: Ctx, mut ownership: OwnerStorage) {
require_owner()
ownership.owner = new_owner
}
// Message definitions
msg AdminMsg {
#[selector = 0xf2fde38b]
TransferOwnership { new_owner: u256 } -> bool,
#[selector = 0x40c10f19]
Mint { to: u256, amount: u256 } -> bool,
}
// Use in any contract
contract OwnableToken {
mut ownership: OwnerStorage,
mut store: TokenStorage,
init() uses (ctx: Ctx, mut ownership) {
ownership.owner = ctx.caller()
}
recv AdminMsg {
TransferOwnership { new_owner } -> bool uses (ctx: Ctx, mut ownership) {
transfer_ownership(new_owner)
true
}
Mint { to, amount } -> bool uses (ctx: Ctx, ownership, mut store) {
require_owner()
mint_tokens(to, amount)
true
}
}
}
pub struct PauseStorage {
pub paused: bool,
}
fn is_paused() -> bool uses (pause_state: PauseStorage) {
pause_state.paused
}
fn require_not_paused() uses (pause_state: PauseStorage) {
if pause_state.paused {
revert(0, 0)
}
}
fn set_paused(paused: bool) uses (mut pause_state: PauseStorage) {
pause_state.paused = paused
}
contract PausableToken {
mut pause_state: PauseStorage,
ownership: OwnerStorage,
mut store: TokenStorage,
recv TokenMsg {
Transfer { to, amount } -> bool uses (ctx: Ctx, pause_state, mut store) {
require_not_paused()
transfer(ctx.caller(), to, amount)
}
}
recv AdminMsg {
Pause {} -> bool uses (ctx: Ctx, ownership, mut pause_state) {
require_owner()
set_paused(true)
true
}
Unpause {} -> bool uses (ctx: Ctx, ownership, mut pause_state) {
require_owner()
set_paused(false)
true
}
}
}

Functions can require multiple effects:

fn guarded_transfer(
from: u256,
to: u256,
amount: u256
) -> bool uses (mut store: TokenStorage, pause_state: PauseStorage) {
require_not_paused()
transfer(from, to, amount)
}
contract Token {
mut store: TokenStorage,
pause_state: PauseStorage,
ownership: OwnerStorage,
recv TokenMsg {
Transfer { to, amount } -> bool uses (ctx: Ctx, mut store, pause_state) {
guarded_transfer(ctx.caller(), to, amount)
}
}
}

For larger projects, organize code across files:

src/
├── main.fe # Contract definitions
├── storage.fe # Storage struct definitions
├── token.fe # Token-related functions
├── access.fe # Access control functions
└── pausable.fe # Pausability functions

Each file exports its functions and types for use in the main contract.

AspectInheritance (Solidity)Composition (Fe)
ReuseInherit from baseImport functions
StateMixed in parentExplicit storage fields
DependenciesImplicit via superExplicit via uses
TestingMock entire contractMock individual effects
ClarityDiamond problem riskClear function flow
PatternDescription
Helper functionsExtract logic with uses clause
Modular storageSeparate storage structs per concern
Access controlReusable ownership/role checking
PausabilityReusable pause state management
Multi-effectFunctions requiring multiple effects