Skip to content
This guide targets Fe 26.4. Fe is not production-ready. Install Fe 26.4

Built-in Types Reference

This appendix provides a complete reference for Fe’s built-in types.

Unsigned integers cannot be negative. Fe provides sizes matching EVM word boundaries:

TypeBitsBytesRange
u8810 to 255
u161620 to 65,535
u323240 to 4,294,967,295
u646480 to 18,446,744,073,709,551,615
u128128160 to 2¹²⁸ - 1
u256256320 to 2²⁵⁶ - 1
let small: u8 = 255
let balance: u256 = 1000000000000000000 // 1 ETH in wei
let max_supply: u256 = 21000000
  • u256 is the native EVM word size and most efficient for storage
  • Choose integer widths for their range and ABI requirements; do not assume automatic storage packing
  • Arithmetic overflow causes a revert by default

Signed integers can be negative. They use two’s complement representation:

TypeBitsBytesRange
i881-128 to 127
i16162-32,768 to 32,767
i32324-2,147,483,648 to 2,147,483,647
i64648-2⁶³ to 2⁶³ - 1
i12812816-2¹²⁷ to 2¹²⁷ - 1
i25625632-2²⁵⁵ to 2²⁵⁵ - 1
let delta: i256 = -100
let temperature: i32 = -40
let positive: i256 = 1000
  • Use signed integers when negative values are meaningful
  • Most ERC standards use unsigned integers
  • Signed division and comparison use different EVM opcodes

The bool type represents true/false values:

TypeSizeValues
bool1 bit (stored as 1 byte)true, false
let is_active: bool = true
let paused: bool = false
if is_active && !paused {
// ...
}
OperationSyntaxDescription
ANDa && bTrue if both true
ORa || bTrue if either true
NOT!aInverts the value
Equalitya == bTrue if same value

Fixed-size strings with a maximum length:

TypeDescription
String<N>String with max length N bytes
let name: String<31> = "CoolCoin"
let symbol: String<8> = "COOL"
let message: String<31> = "Transfer failed"
  • String length is fixed at compile time
  • Shorter strings are padded
  • Used for token names, symbols, and error messages

Fixed-size collections of heterogeneous types:

TypeDescription
(T1, T2, ...)Tuple of types T1, T2, etc.
let pair: (u256, bool) = (100, true)
let triple: (u256, u256, u256) = (1, 2, 3)
// Destructuring
let (_amount, _success): (u256, bool) = (100, true)
// Access by index
let pair2: (u256, bool) = (100, true)
let first = pair2.0
let pair3: (u256, bool) = (100, true)
let second = pair3.1

Fixed-size collections of homogeneous types:

TypeDescription
[T; N]Array of N elements of type T
let numbers: [u256; 3] = [1, 2, 3]
let first = numbers[0]

Fixed-size arrays also support == and != when their elements implement Eq:

#[test]
fn array_equality() {
let left: [u256; 3] = [1, 2, 3]
let right: [u256; 3] = [1, 2, 3]
assert!(left == right)
}

std::abi::DynArray<T> represents an ABI array with a runtime length. Fe provides typed get(index) access and MemVec<T> for building mutable arrays in memory. MemVec has a fixed length chosen at construction; it does not provide push.

use std::abi::{DynArray, MemVec}
#[test]
fn dynamic_array_copy() {
let mut values = MemVec<u256>::zeroed(2)
values.set(index: 0, value: 10)
values.set(index: 1, value: 20)
let encoded: DynArray<u256> = values.to_dyn_array()
values.set(index: 0, value: 99)
assert!(encoded.len() == 2)
assert!(encoded.get(0) == 10)
assert!(values.get(0) == 99)
}

to_dyn_array creates an independent copy suitable for ABI arguments, return values, or event fields. from_dyn_array copies in the other direction. In Fe 26.4, typed DynArray::get and MemVec support sealed single-word static ABI element types: integers, booleans, addresses, and fixed bytes. They do not support structs, tuple elements, or dynamic elements such as Bytes. Out-of-bounds access reverts with Panic(0x32).

The empty tuple, representing no value:

TypeDescription
()Unit type, no value
fn do_something() {
// Implicitly returns ()
}
fn explicit_unit() -> () {
()
}

Represents an optional value:

TypeDescription
Option<T>Either Some(T) or None
let maybe_value: Option<u256> = Option::Some(42)
let nothing: Option<u256> = Option::None
match maybe_value {
Option::Some(v) => v,
Option::None => 0,
}

Key-value storage mapping:

TypeDescription
StorageMap<K, V>Maps keys of type K to values of type V
struct Storage {
balances: StorageMap<Address, u256>,
allowances: StorageMap<(Address, Address), u256>,
}
// Access
let balance = storage.balances.get(account)
// Update
storage.balances.set(key: account, value: new_balance)
  • Maps are storage-only types
  • Non-existent keys return the zero value
  • Tuples can be used as composite keys

Convert between numeric types with as:

let small: u8 = 100
let big: u256 = small as u256
let signed: i256 = -50
let unsigned: u256 = signed.downcast_unchecked() // Caution: reinterprets bits
FromToBehavior
Smaller unsignedLarger unsignedZero-extends
Larger unsignedSmaller unsignedTruncates
SignedUnsignedReinterprets bits
UnsignedSignedReinterprets bits
CategoryTypes
Unsigned integersu8, u16, u32, u64, u128, u256
Signed integersi8, i16, i32, i64, i128, i256
Booleanbool
StringString<N>
Tuple(T1, T2, ...)
Array[T; N]
Unit()
OptionalOption<T>
MapStorageMap<K, V>

An EVM storage slot is 32 bytes. Do not infer Fe field layout by dividing a type’s bit width by 256: smaller integer types do not imply Solidity-style automatic packing. Inspect the compiler’s contract layout information when layout matters. StorageMap derives entry locations with Keccak-256 and a map salt.

Pointer-bearing memory values cannot be persisted in contract storage.

To construct arrays of supported static elements, use MemVec::zeroed, set, and to_dyn_array as shown above. Do not assume a DynArray<Bytes> can be indexed with get; dynamic and composite elements require APIs beyond this release’s typed array helpers.