Installation and first contract
Build the compiler
Lithe is written in Rust. Build it from the repository root with a recent stable toolchain:
cargo build --releaseThe compiler is now at target/release/lithe. Put it on your PATH, or call it by path:
export PATH="$PWD/target/release:$PATH"
litheRun with no arguments, lithe prints its commands. See Command line for the full list.
To prove contracts' specs with lithe prove, also install the Z3 solver, which it runs:
brew install z3 # macOS
sudo apt install z3 # Debian and UbuntuOr download a release from github.com/Z3Prover/z3/releases and put z3 on your PATH, or set LITHE_Z3 to its path. Nothing else needs Z3.
Write a contract
A Lithe file is a contract. Create counter.lithe:
(* Comments are written like this, and they nest. *)
storage is record {
count : uint;
}
external view function get() : uint is
storage.count
external function inc() is {
storage.count := storage.count + 1;
}
external function dec() is {
storage.count := storage.count - 1;
}A few things to notice:
storage is recorddeclares the contract's persistent state. Every contract has one, and every access is qualified asstorage.count.uintis an unsigned 256-bit integer.1is auintliteral. Arithmetic is checked, sodecon zero reverts withPanic(0x11), the same panic Solidity uses.externalputs a function in the ABI.external viewpromises the function never writes, and the compiler checks the promise.:=assigns.=compares.- A function body is a block
{ ... }or a single expression.
Compile
lithe compile counter.litheThis prints the contract's creation bytecode as hex. Generate its ABI with:
lithe abi counter.litheTo build every .lithe file in a directory into Foundry-style artifacts under ./out, pass the directory:
lithe compile srcDeploy and call
The output of lithe compile is creation code, so any deployment tool can use it. With Foundry and a local anvil:
anvil &
KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
cast send --private-key $KEY --create $(lithe compile counter.lithe)
# contractAddress 0x5FbDB2315678afecb367f032d93F642f64180aa3
cast send --private-key $KEY 0x5FbDB2315678afecb367f032d93F642f64180aa3 "inc()"
cast call 0x5FbDB2315678afecb367f032d93F642f64180aa3 "get()(uint256)"
# 1Calling dec() twice from here reverts with panic: arithmetic underflow or overflow (0x11).
See what the compiler knows
Because effects are explicit, the compiler can summarize each entrypoint:
lithe footprint counter.litheinc writes: count during defers: callable
dec writes: count during defers: callable
get reads: count during defers: callableInspecting contracts covers footprint, abi-tree, analysis, errors, and storage.
Next steps
- Read The transition model to understand
query,emit, anddefer. - Browse Lithe by Example.
- Keep the Built-ins reference open while you write.

