| title | Installation and first contract |
|---|---|
| description | Install the Lithe compiler, write a contract, compile it, and deploy it to a local chain. |
:::warning Lithe is in early development and experimental. The language, standard library, and compiler output can change without notice, and neither the compiler nor the standard library has been audited. :::
Install the latest release with the install script:
curl -fsSL https://lithe-lang.org/install.sh | shIt downloads the compiler for your platform, Linux or macOS on x86-64 or ARM64, checks it against the release's checksums, and installs it to ~/.lithe/bin/lithe, or $LITHE_HOME/bin/lithe when LITHE_HOME is set. If that directory isn't on your PATH, it adds it in your shell's profile (~/.zshrc, ~/.bashrc, ~/.bash_profile on macOS, fish's config.fish, or ~/.profile); set LITHE_NO_MODIFY_PATH=1 to have it print the line instead. Run it again to update. To install a given version, pass it after -s --:
curl -fsSL https://lithe-lang.org/install.sh | sh -s -- 0.5.1Or build a release with Cargo, which installs it to ~/.cargo/bin and needs the same tools as building from source, below:
cargo install --git https://github.com/celestiaorg/lithe --tag v0.5.1 --lockedTo build from source, run this from the repository root with a recent stable Rust toolchain, CMake, Python 3, and a C++ compiler (brew install cmake on macOS, sudo apt install cmake python3 g++ on Debian and Ubuntu). The first build also compiles the Z3 solver that lithe prove runs, which takes a few minutes:
cargo build --release
export PATH="$PWD/target/release:$PATH"Check the install with lithe --version. Contracts you deploy should be built with a released compiler, so that they can be verified.
Run with no arguments, lithe prints its commands. See Command line for the full list, and Editors to set up VS Code, Cursor, or Recur.
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 += 1;
}
external function dec() is {
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, and+=adds to what is there.=compares.- A function body is a block
{ ... }or a single expression.
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 srcThe 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). To test a contract with Foundry or Hardhat, see Testing. To deploy one with a deploy, or with delegated modules, see Deploying.
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: callable
Inspecting contracts covers footprint, abi-tree, analysis, errors, and storage.
- Read The transition model to understand
query,emit, anddefer. - Browse Lithe by Example.
- Keep the Built-ins reference open while you write.