Receive Blocks in Contracts
Receive blocks inside contracts handle incoming messages and have access to the contract’s storage through effects. This section focuses on how recv blocks work within the contract context.
Recv Blocks and Contract State
Section titled “Recv Blocks and Contract State”In a contract, recv blocks access storage via uses clauses:
pub struct TokenStorage { pub balances: Map<u256, u256>, pub total_supply: u256,}
msg TokenMsg { #[selector = 0x70a08231] BalanceOf { account: u256 } -> u256,
#[selector = 0xa9059cbb] Transfer { to: u256, amount: u256 } -> bool,}
contract Token { mut store: TokenStorage,
recv TokenMsg { BalanceOf { account } -> u256 uses (store) { store.balances.get(account) }
Transfer { to, amount } -> bool uses (mut store) { do_transfer(caller(), to, amount) } }}The uses Clause
Section titled “The uses Clause”The uses clause on a handler declares which contract fields it needs:
BalanceOf { account } -> u256 uses (store) { // store is available here store.balances.get(account) }This pattern:
- Declares that the handler needs the
storefield - Makes
storedirectly accessible in the handler body - Propagates the effect to any called functions
Calling Helper Functions
Section titled “Calling Helper Functions”Handlers typically delegate to helper functions:
fn get_balance(account: u256) -> u256 uses (store: TokenStorage) { store.balances.get(account)}
fn do_transfer(from: u256, to: u256, amount: u256) -> bool uses (mut store: TokenStorage) { let from_bal = store.balances.get(from) if from_bal < amount { return false }
store.balances.set(from, from_bal - amount)
let to_bal = store.balances.get(to) store.balances.set(to, to_bal + amount) true}
contract Token { mut store: TokenStorage,
recv TokenMsg { BalanceOf { account } -> u256 uses (store) { get_balance(account) }
Transfer { to, amount } -> bool uses (mut store) { do_transfer(caller(), to, amount) } }}Multiple Storage Effects
Section titled “Multiple Storage Effects”When handlers need multiple storage types:
pub struct BalanceStorage { pub balances: Map<u256, u256>,}
pub struct AllowanceStorage { pub allowances: Map<u256, Map<u256, u256>>,}
contract Token { mut balances: BalanceStorage, mut allowances: AllowanceStorage,
recv TokenMsg { TransferFrom { from, to, amount } -> bool uses (mut balances, mut allowances) { do_transfer_from(caller(), from, to, amount) } }}Complete Contract Example
Section titled “Complete Contract Example”For a full ERC20-style token contract demonstrating all these patterns, see the Complete ERC20 example.
Handler Organization
Section titled “Handler Organization”For contracts with many handlers, organize by interface:
contract Token { store: TokenStorage,
// Core ERC20 operations recv Erc20 { Transfer { to, amount } -> bool { let _ = (to, amount) true } Approve { spender, amount } -> bool { let _ = (spender, amount) true } TransferFrom { from, to, amount } -> bool { let _ = (from, to, amount) true } BalanceOf { account } -> u256 { let _ = account 0 } Allowance { owner, spender } -> u256 { let _ = (owner, spender) 0 } TotalSupply {} -> u256 { 0 } }
// Metadata extension recv Erc20Metadata { Name {} -> String<32> { "Token" } Symbol {} -> String<8> { "TKN" } Decimals {} -> u8 { 18 } }}Summary
Section titled “Summary”| Concept | Description |
|---|---|
recv MsgType { } | Recv block in contract |
uses (field) | Access storage in handler |
| Helper functions | Functions with uses clause |
| Multiple effects | uses (mut a, mut b) |
| Organization | Separate recv blocks per interface |