Fe is a Rust-like language for the EVM, with explicit effects, message-passing contracts, and an integrated toolchain.

$ curl -fsSL https://raw.githubusercontent.com/argotorg/fe/master/feup/feup.sh | bash -s -- --version v26.4.1
$ brew install fe-lang/tap/fe

Examples target Fe 26.4. Installation instructions.

Explicit Effects

The uses clause declares all capabilities a function requires: storage access, event emission, external calls, contract creation. Side effects become explicit.

Explicit Mutability

All bindings, storage fields, and effect parameters are immutable unless marked mut. The compiler rejects writes to immutable state.

Message Passing

Contracts interact via msg types and recv handlers, mirroring the EVM's transaction-based execution model.

Pattern Matching

match expressions destructure enums, tuples, and nested data. Extract variant payloads and branch on values. The compiler checks that all cases are covered.

Traits

Define shared interfaces with trait and implement them for any type. Used throughout the standard library for Encode, Decode, Default, and more.

Generics

Type parameters on struct, enum, trait, and fn with trait bounds. Monomorphized at compile time with zero runtime overhead.

Higher-Kinded Types

Supports higher-kinded types via * -> * bounds on traits. Enables abstractions like Functor, Applicative, and Monad, generic over Option<T>, Result<E, T>, or any type constructor.

Const Functions

Functions marked const fn are evaluated at compile time. The sol("deposit()") selector in the code computes its 4-byte hash during compilation, not at runtime.

Standard Library

Ships with Option<T>, Result<E, T>, StorageMap<K, V>, and traits like Default, Encode, Decode.

Fe at a glance
/// A vault contract with traits, pattern matching, /// and explicit effects. use std::abi::sol // Enums as error types enum VaultError { InsufficientFunds, ZeroAmount, } // Traits define shared behavior trait Validate { fn validate(self) -> Result<VaultError, u256> } struct Withdrawal { balance: u256, amount: u256, } impl Validate for Withdrawal { fn validate(self) -> Result<VaultError, u256> { if self.amount == 0 { return Result::Err(VaultError::ZeroAmount) } if self.balance < self.amount { return Result::Err(VaultError::InsufficientFunds) } Result::Ok(self.balance - self.amount) } } // Events with indexed fields for efficient filtering #[event] struct Deposited { #[indexed] owner: Address, amount: u256, } struct VaultStore { balances: StorageMap<Address, u256>, } // Message interface defines the contract's public ABI msg VaultMsg { #[selector = sol("deposit()")] Deposit {}, #[selector = sol("withdraw(uint256)")] Withdraw { amount: u256 }, #[selector = sol("balanceOf(address)")] BalanceOf { addr: Address } -> u256, } // Effects declared explicitly, no hidden state access pub contract Vault uses (ctx: Ctx, log: mut Log, call: mut Call) { mut store: VaultStore recv VaultMsg { #[payable] Deposit {} uses (ctx, mut store, mut log) { let who = ctx.caller() let balance = store.balances.get(key: who) store.balances.set(key: who, value: balance + ctx.value()) log.emit(event: Deposited { owner: who, amount: ctx.value() }) } // Pattern match on Result for control flow Withdraw { amount } uses (ctx, mut store, mut call) { let who = ctx.caller() let balance = store.balances.get(key: who) let req = Withdrawal { balance, amount } match req.validate() { Ok(new_bal) => { store.balances.set(key: who, value: new_bal) let outcome = call.send_value(addr: who, gas: ctx.gas(), value: amount) assert!(outcome.success(), "withdrawal failed") } Err(VaultError::InsufficientFunds) => { revert_error(InsufficientFunds {}) } Err(VaultError::ZeroAmount) => { revert_error(ZeroAmount {}) } } } BalanceOf { addr } -> u256 uses (store) { store.balances.get(key: addr) } } } // Custom error payloads used by the validation branches. #[error] struct InsufficientFunds {} #[error] struct ZeroAmount {}

Built-in Testing

Run fe test with integrated EVM simulation. No external frameworks needed.

Package Manager

Organize code into ingots. Add dependencies and share reusable contracts.

Code Formatter

Run fe fmt for consistent, opinionated formatting.

Language Server

LSP support with diagnostics, go-to-definition, and completions for many popular editors.

Docs Generator

Generate browsable HTML docs from your code with fe doc.

EVM and Native

Compiles EVM contracts through Sonatina. An experimental native backend for standalone programs is available only in source builds with the cranelift feature.

Explore more contracts written in Fe

See examples →