Add PublishPrice — a permissionless instruction that computes the TWAP over a
PriceObservations buffer and writes it to the consumer-facing OraclePriceAccount.
Because each observations account is calibrated to a specific window_duration via
its sampling guard, the oldest valid entry is always the natural window start, so
the TWAP is computed over the full buffer span with no boundary search:
t2 = most recent observation (write_index - 1, wrapping)
t1 = oldest valid entry (0 if not full, write_index if full)
twap_tick = (t2.tick_cumulative - t1.tick_cumulative) / (t2.ts - t1.ts)
If fewer than two observations exist the call is a silent no-op, leaving the price
account at timestamp = 0 (the uninitialized signal consumers already reject). While
the buffer is young the TWAP is computed over the available span, which may be
shorter than the requested window.
The TWAP tick is converted to an actual price ratio via the Uniswap v3 sqrtPriceX96
representation (pure integer, zkVM-safe): get_sqrt_ratio_at_tick(tick) then
sqrtPriceX96^2 / 2^128, yielding a Q64.64 fixed-point ratio stored in
OraclePriceAccount.price. The OraclePriceAccount stays source-agnostic — no tick or
Uniswap framing leaks into the standard. Out-of-range ticks clamp; ratios above 2^64
saturate at u128::MAX. Adds PRICE_FRACTIONAL_BITS = 64; removes the placeholder
TWAP_PRICE_BIAS / oracle_price_to_tick bias encoding.
Pulls in uniswap_v3_math 0.6.2 and alloy-primitives for the conversion. Pins ruint
to =1.17.0 (transitive via alloy-primitives): 1.18 raised its MSRV to rustc 1.90 but
the risc0 guest toolchain ships 1.88. Guest build verified for riscv32im.
Closes #117
lez-programs
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.
Programs
| 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) |
Apps
| App | Description |
|---|---|
| amm | QML-based UI for interacting with the AMM program |
Running Apps
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.conf
Example (apps/amm)
cd apps/amm
# Run the app
nix run .
# Update pinned dependencies
nix flake update
Prerequisites
-
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
Build & Test
# 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
# Run integration tests (dev mode skips ZK proof generation)
RISC0_DEV_MODE=1 cargo test -p integration_tests
# Run all tests
make test
Integration tests live in programs/integration_tests/tests/ and cover token, amm, and ata 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.rs
stablecoin and twap_oracle are tested via their own unit tests (cargo test -p stablecoin_program -p twap_oracle_program).
Compile Guest Binaries
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.toml
Binaries are output to:
<PROGRAM>/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/<PROGRAM>.bin
Deployment
# Deploy a program binary to the sequencer
wallet deploy-program <path-to-binary>
# Example
wallet deploy-program programs/token/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/token.bin
wallet deploy-program programs/amm/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/amm.bin
wallet deploy-program programs/ata/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/ata.bin
wallet deploy-program programs/stablecoin/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/stablecoin.bin
wallet deploy-program programs/twap_oracle/methods/guest/target/riscv32im-risc0-zkvm-elf/docker/twap_oracle.bin
To inspect the ProgramId of a built binary:
spel inspect <path-to-binary>
Interacting with Programs via spel
Generate an IDL
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 idl
Using 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
Generated IDL files are committed under artifacts/. CI will fail if a program's IDL is missing or out of date.
Invoke Instructions
Use spel --idl <IDL> <INSTRUCTION> [ARGS...] to call a deployed program instruction:
spel --idl artifacts/token-idl.json <instruction> [args...]
spel --idl artifacts/amm-idl.json <instruction> [args...]
spel --idl artifacts/ata-idl.json <instruction> [args...]
spel --idl artifacts/stablecoin-idl.json <instruction> [args...]
spel --idl artifacts/twap_oracle-idl.json <instruction> [args...]