Essential programs for the Logos Execution Zone (LEZ) — a zkVM-based execution environment built on RISC Zero. Programs run inside the RISC Zero zkVM (riscv32im-risc0-zkvm-elf target) and interact with the LEZ runtime via the lee_core library.
| Program | Description |
|---|---|
| token | Fungible and non-fungible token program — create definitions, mint/burn tokens, transfer, initialize accounts, print NFTs |
| amm | Constant-product AMM — add/remove liquidity and swap via chained calls to the token program |
| ata | Associated Token Account program — derives and initializes deterministic token holding accounts for a given owner and token definition |
| stablecoin | Collateral-backed position program — open collateral positions as a foundation for stablecoin debt issuance |
| twap_oracle | TWAP oracle — provides canonical on-chain price accounts consumed by other programs (e.g. stablecoin) |
| token-mint-authority | Testnet faucet mint authority — holds the mint authority for faucet token definitions and lets any account self-mint a fixed amount, rate-limited to once per day per account and token, via a chained call to the token program |
| App | Description |
|---|---|
| amm | QML-based UI for interacting with the AMM program |
Apps live under apps/ and are standalone UI applications. Each app has its own README.md with full details.
Apps use Nix flakes. Enable flakes if you haven't already:
mkdir -p ~/.config/nix && echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.confThe AMM UI is built from the repository-root flake (which also provides the
amm_client_ffi library it links). Run it from the repo root by its named
attribute — there is no bare nix run . default, so future apps are
nix run .#<name>:
# Run the app (from the repo root)
nix run .#amm-ui
# Update pinned dependencies
nix flake updateTo use the Swap view, also set AMM_PROGRAM_ID (the deployed AMM program's
address), AMM_CONFIG_ID (its config account) and TOKENS_CONFIG (your token
list) — use absolute paths, from the repo root:
AMM_PROGRAM_ID=<deployed-amm-program-id> \
AMM_CONFIG_ID=<amm-config-id> \
TOKENS_CONFIG=$(pwd)/apps/amm/amm-tokens.json \
nix run .#amm-uiSee apps/amm/README.md for full details on these variables.
-
Rust — install via rustup. The pinned toolchain version is set in
rust-toolchain.toml. -
RISC Zero toolchain — required to build guest ZK binaries:
cargo install cargo-risczero cargo risczero install
-
SPEL toolchain — provides
spelandwalletCLI tools. Install from logos-co/spel. -
LEZ — provides
walletCLI. Install from logos-blockchain/logos-execution-zone
# Lint the entire workspace (skips expensive guest ZK builds)
make clippy
# Format check
make fmt
# Run unit tests for all programs (no zkVM, no ZK proof generation)
RISC0_DEV_MODE=1 cargo test -p token_program -p amm_program -p ata_program -p stablecoin_program -p twap_oracle_program -p token_mint_authority_program
# Run integration tests (dev mode skips ZK proof generation)
RISC0_DEV_MODE=1 cargo test -p integration_tests
# Run all tests
make testIntegration tests live in programs/integration_tests/tests/ and cover token, amm, ata, stablecoin, and token-mint-authority programs end-to-end through the zkVM using RISC0_DEV_MODE=1 to skip proof generation. Each test file corresponds to a program:
programs/integration_tests/tests/token.rsprograms/integration_tests/tests/amm.rsprograms/integration_tests/tests/ata.rsprograms/integration_tests/tests/stablecoin.rsprograms/integration_tests/tests/token_mint_authority.rs
twap_oracle is tested via its own unit tests (cargo test -p twap_oracle_program).
The guest binaries are compiled to the riscv32im-risc0-zkvm-elf target. This requires the RISC Zero toolchain.
cargo risczero build --manifest-path <PROGRAM>/methods/guest/Cargo.tomlBinaries are output to:
<PROGRAM>/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/<PROGRAM>.bin
Since LEZ v0.2.5 a program is deployed through the program_loader: its binary is
uploaded as a chain of write-once segment accounts (one per 96 KiB chunk), and a header
account points at that chain. The wallet never generates these accounts itself, so create
them first. The header account's id is the program's address from then on.
BIN=programs/token/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/token.bin
N=$(( ($(wc -c < "$BIN") + 98303) / 98304 )) # 96 KiB segments; the count must match exactly
# One header account and N segment accounts, all fresh
wallet account new public --label token-header
for i in $(seq 1 "$N"); do wallet account new public --label "token-seg-$i"; done
# Header and segments start empty, so a separate funded public account pays the fees.
# Accounts are labels or `Public/<base58-id>`; a bare id is mistaken for a label.
wallet program-loader deploy \
--elf "$BIN" \
--header token-header \
--segments $(for i in $(seq 1 "$N"); do printf 'token-seg-%s ' "$i"; done) \
--payer <funded-account> \
--immutable # optional: the program self-declares as immutable (not enforced)
# The program's address
wallet account id --account-id token-headerRepeat with each program's binary and its own labels (amm, ata, stablecoin,
twap_oracle, token_mint_authority). Segments are write-once: if a deploy fails
partway, use fresh segment accounts for the next attempt.
apps/amm/tests/testnet/setup-amm-testnet.sh scripts this flow for several programs.
To print the ImageID of a built binary (it identifies the code, but is not the program's address):
spel -- program-id <path-to-binary>The IDL describes the program's instructions and can be used to interact with a deployed program.
Using the idl-gen crate (no external toolchain required — this is what CI uses):
make idlUsing the spel CLI (requires the SPEL toolchain):
spel generate-idl programs/token/methods/guest/src/bin/token.rs > artifacts/token-idl.json
spel generate-idl programs/amm/methods/guest/src/bin/amm.rs > artifacts/amm-idl.json
spel generate-idl programs/ata/methods/guest/src/bin/ata.rs > artifacts/ata-idl.json
spel generate-idl programs/stablecoin/methods/guest/src/bin/stablecoin.rs > artifacts/stablecoin-idl.json
spel generate-idl programs/twap_oracle/methods/guest/src/bin/twap_oracle.rs > artifacts/twap_oracle-idl.json
spel generate-idl programs/token_mint_authority/methods/guest/src/bin/token_mint_authority.rs > artifacts/token_mint_authority-idl.jsonGenerated IDL files are committed under artifacts/. CI will fail if a program's IDL is missing or out of date.
Use spel --idl <IDL> --program <PROGRAM_ID> --fee-payer <FEE_PAYER> -- <INSTRUCTION> [ARGS...]
to call a deployed program instruction:
spel --idl artifacts/token-idl.json --program <TOKEN_PROGRAM_ID> --fee-payer <FEE_PAYER> -- <instruction> [args...]
spel --idl artifacts/amm-idl.json --program <AMM_PROGRAM_ID> --fee-payer <FEE_PAYER> -- <instruction> [args...]
spel --idl artifacts/ata-idl.json --program <ATA_PROGRAM_ID> --fee-payer <FEE_PAYER> -- <instruction> [args...]
spel --idl artifacts/stablecoin-idl.json --program <STABLECOIN_PROGRAM_ID> --fee-payer <FEE_PAYER> -- <instruction> [args...]
spel --idl artifacts/twap_oracle-idl.json --program <TWAP_PROGRAM_ID> --fee-payer <FEE_PAYER> -- <instruction> [args...]
spel --idl artifacts/token_mint_authority-idl.json --program <FAUCET_PROGRAM_ID> --fee-payer <FEE_PAYER> -- <instruction> [args...]--programis the program's header account id (see Deployment); spel rejects a binary path.--fee-payeris a funded account your wallet holds. Without it the first signer pays, which fails when the signers are fresh accounts, and instructions with no signers are refused.- spel reports
Transaction confirmedeven when the program rejected the instruction, so check the result withspel --idl <IDL> inspect <ACCOUNT_ID> --type <TYPE>.
See docs/testnet-runbook.md for complete, ordered examples.