lez-programs/CLAUDE.md
r4bbit 7b1696f98e docs: update README and CLAUDE.md to reflect current state
- Rename amm-ui to amm in the Apps table
- Add "Running Apps" section with Nix flake setup and amm example
- Remove hardcoded Rust toolchain version; point to rust-toolchain.toml
- Replace raw cargo/clippy invocations with make targets (clippy, test, fmt, idl)
- Expand program listings in overview and workspace structure to cover
  all five programs: token, amm, ata, stablecoin, twap_oracle
- Add integration_tests and apps/amm to the workspace structure diagram
2026-05-26 16:42:18 +02:00

6.3 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Overview

This repo contains 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 nssa_core library from logos-execution-zone.

Five programs are implemented:

  • token — Fungible and non-fungible token program (create, mint, burn, transfer, print NFTs)
  • amm — Automated market maker (constant product AMM with add/remove liquidity and swaps)
  • ata — Associated Token Account program (derives and initializes deterministic token accounts for a given owner and token definition)
  • stablecoin — Collateral-backed position program (open positions, repay debt, withdraw collateral)
  • twap_oracle — TWAP oracle (provides canonical on-chain price accounts consumed by other programs)

Build Commands

# Check all workspace crates (skips expensive guest ZK builds)
make clippy

# Run all tests (dev mode skips ZK proof generation)
make test

# Run tests for a single package
RISC0_DEV_MODE=1 cargo test -p token_program
RISC0_DEV_MODE=1 cargo test -p amm_program
RISC0_DEV_MODE=1 cargo test -p ata_program
RISC0_DEV_MODE=1 cargo test -p stablecoin_program
RISC0_DEV_MODE=1 cargo test -p twap_oracle_program

# Format
make fmt

# Build the guest ZK binary (requires risc0 toolchain)
cargo risczero build --manifest-path programs/<program>/methods/guest/Cargo.toml

Built binaries output to: <program>/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/<program>.bin

IDL Generation

Using the idl-gen crate (no external toolchain required — this is what CI uses):

make idl

Or individually per program:

cargo run -p idl-gen -- programs/<program>/methods/guest/src/bin/<program>.rs > artifacts/<program>-idl.json

Alternatively, using the spel CLI (requires the SPEL toolchain):

spel generate-idl programs/<program>/methods/guest/src/bin/<program>.rs > artifacts/<program>-idl.json

Generated IDL files live in artifacts/. CI checks that every program under */methods/guest/src/bin/ has a corresponding artifacts/<program>-idl.json that matches the source.

Deployment

wallet and spel are CLI tools that ship with the SPEL toolchain. wallet requires NSSA_WALLET_HOME_DIR to point to a directory containing the wallet config.

Note: spel and wallet may use different versions of the wallet package. If spel --idl <IDL> <PROGRAM_FUNCTION> ... fails, ensure seq_poll_timeout_millis is set in the wallet config at ~/.nssa/wallet.

# Deploy a program binary to the sequencer
wallet deploy-program <path-to-binary>

# Inspect the ProgramId of a built binary
spel inspect <path-to-binary>

Workspace Structure

Cargo.toml              # Workspace root (excludes guest crates)
programs/
  token/
    core/src/lib.rs     # Data types & Instruction enum (shared with guest)
    src/                # Program logic: burn, mint, transfer, initialize, new_definition, print_nft
    methods/            # Host-side zkVM method embedding (build.rs uses risc0_build::embed_methods)
    methods/guest/      # Guest binary (separate workspace, riscv32im target)
  amm/
    core/src/lib.rs     # Data types, Instruction enum, PDA computation helpers
    src/                # Program logic: add, remove, swap, new_definition
    methods/            # Host-side zkVM method embedding
    methods/guest/      # Guest binary (separate workspace)
  ata/
    core/src/lib.rs     # Data types & Instruction enum
    src/                # Program logic: create, burn, transfer
    methods/            # Host-side zkVM method embedding
    methods/guest/      # Guest binary (separate workspace)
  stablecoin/
    core/src/lib.rs     # Data types & Instruction enum
    src/                # Program logic: open_position, repay_debt, withdraw_collateral
    methods/            # Host-side zkVM method embedding
    methods/guest/      # Guest binary (separate workspace)
  twap_oracle/
    core/src/lib.rs     # Data types & Instruction enum
    src/                # Program logic: noop (price account initialization)
    methods/            # Host-side zkVM method embedding
    methods/guest/      # Guest binary (separate workspace)
  integration_tests/
    tests/              # End-to-end tests through the zkVM (token, amm, ata)
apps/
  amm/                  # QML-based UI for the AMM program (Nix flake)

Architecture

Each program follows a layered pattern:

  1. *_core crate — shared types (Instructions, account data structs) serialized with Borsh for on-chain storage, serde for instruction passing. Also contains PDA seed computation (amm_core).

  2. Program crate — pure functions that take AccountWithMetadata inputs and return Vec<AccountPostState> (and Vec<ChainedCall> for AMM). No I/O or state — all state transitions are deterministic and testable without the zkVM.

  3. methods/guest — the guest binary wired to the LEZ framework via spel-framework using the #[lez_program] and #[instruction] proc macros. This is what gets compiled to RISC-V and ZK-proven.

  4. methods — host crate that embeds the guest ELF for use in tests and deployment.

Key Patterns

Account data serialization: On-chain account data uses Borsh (BorshSerialize/BorshDeserialize). Instructions use serde JSON. Both implement TryFrom<&Data> and From<&T> for Data for conversion.

Program-Derived Addresses (PDAs): The AMM uses SHA-256-based PDAs (compute_pool_pda, compute_vault_pda, compute_liquidity_token_pda in amm_core) to derive deterministic account addresses for pools, vaults, and liquidity tokens.

Chained calls: The AMM's swap and liquidity operations compose with the token program via ChainedCall — the AMM instructs the token program to execute transfers as part of the same atomic operation.

Testing: Tests call program functions directly (no zkVM overhead). Set RISC0_DEV_MODE=1 to skip ZK proof generation when running integration tests that go through the zkVM. The Rust toolchain version is pinned in rust-toolchain.toml.