Handler Syntax
Handlers are the functions inside recv blocks that process incoming messages. Each handler matches a specific message variant and implements its logic.
Basic Handler Structure
Section titled “Basic Handler Structure”A handler consists of a pattern, optional return type, and body:
VariantName { fields } -> u256 { // handler body 0 }For handlers that don’t return a value:
VariantName { fields } { // handler body, implicitly returns () }Pattern Matching
Section titled “Pattern Matching”Handlers use pattern matching to destructure message fields:
Simple Destructuring
Section titled “Simple Destructuring”Extract fields by their names:
recv TokenMsg { Transfer { to, amount } -> bool { // 'to' and 'amount' are available as local variables true } }Renaming Fields
Section titled “Renaming Fields”Give fields different local names:
recv TokenMsg { Transfer { to: recipient, amount: value } -> bool { // Use 'recipient' and 'value' instead of 'to' and 'amount' true } }Ignoring Fields
Section titled “Ignoring Fields”Use _ to ignore specific fields:
recv TokenMsg { Transfer { to, amount: _ } -> bool { // Only use 'to', ignore the amount true } }Use .. to ignore all remaining fields:
recv TokenMsg { TransferFrom { from, .. } -> bool { // Only use 'from', ignore 'to' and 'amount' true } }No Fields
Section titled “No Fields”For variants without parameters, omit the braces:
recv TokenMsg { TotalSupply -> u256 { 1000000 } }Return Types
Section titled “Return Types”Explicit Returns
Section titled “Explicit Returns”The return type must match the message variant’s declaration:
msg Query { #[selector = 0x70a08231] BalanceOf { account: u256 } -> u256,}
recv Query { BalanceOf { account } -> u256 { // Must return u256 get_balance(account) } }Implicit Unit Return
Section titled “Implicit Unit Return”Handlers without a return type implicitly return ():
msg Commands { #[selector = 0x42842e0e] SafeTransfer { from: u256, to: u256, token_id: u256 },}
recv Commands { SafeTransfer { from, to, token_id } { // No return type means () is returned } }Handler Bodies
Section titled “Handler Bodies”Handler bodies contain the implementation logic. They can use all standard Fe expressions and statements.
Simple Handlers
Section titled “Simple Handlers” recv TokenMsg { TotalSupply -> u256 { 1000000 }
BalanceOf { account } -> u256 { if account == 0 { 0 } else { 100 } } }Early Returns
Section titled “Early Returns”Use return for early exits:
recv TokenMsg { Transfer { to, amount } -> bool { if amount == 0 { return false } if to == 0 { return false } true } }Calling Helper Functions
Section titled “Calling Helper Functions”Handlers typically delegate to helper functions:
fn validate_transfer(to: u256, amount: u256) -> bool { to != 0 && amount > 0}
fn execute_transfer(to: u256, amount: u256) -> bool uses (mut store: TokenStorage) { // transfer logic using storage effect true}
recv TokenMsg { Transfer { to, amount } -> bool uses (mut store) { if !validate_transfer(to, amount) { return false } execute_transfer(to, amount) } }Using Effects in Handlers
Section titled “Using Effects in Handlers”Handlers access contract state through effects:
pub struct TokenStorage { pub balances: Map<u256, u256>, pub total_supply: u256,}
fn get_balance(account: u256) -> u256 uses (store: TokenStorage) { store.balances.get(account)}
fn add_balance(account: u256, amount: u256) uses (mut store: TokenStorage) { let current = store.balances.get(account) store.balances.set(account, current + amount)}
contract Token { mut store: TokenStorage,
recv TokenMsg { BalanceOf { account } -> u256 uses (store) { get_balance(account) }
Transfer { to, amount } -> bool uses (mut store) { add_balance(to, amount) true } }}Context Functions
Section titled “Context Functions”Handlers can access transaction context using built-in functions:
recv TokenMsg { Transfer { to, amount } -> bool { let sender = caller() // Get the message sender do_transfer(sender, to, amount) } }Common context functions:
caller()- The address that called this contractself_address()- The contract’s own addressblock_number()- Current block numberblock_timestamp()- Current block timestamp
Summary
Section titled “Summary”| Pattern | Description |
|---|---|
{ field } | Extract field with same name |
{ field: name } | Extract field with new name |
{ field: _ } | Ignore specific field |
{ .., field } | Extract one, ignore rest |
-> Type { } | Handler with return type |
{ } | Handler returning () |