Ship to mainnet without fear.
Write what your Solana program must guarantee in a .qedspec file. QEDGen validates the spec, finds bugs your tests miss, then generates everything needed to keep them fixed: property tests, Kani harnesses, Lean 4 proofs, program code, and CI workflows — all from a single source of truth. Supports Anchor, Quasar, and sBPF assembly.
npx skills add qedgen/solana-skillsWorks with Claude Code, Cursor, Windsurf, GitHub Copilot, and any agent supporting the Agent Skills spec.
.qedspec ──► check (validate spec) ──► codegen --all ──► lake build ──► ∎
│ │ ▲ │
├── lint (instant) ├── Rust skeleton │ ├─► Leanstral (fast)
├── proptest (~100ms) ├── Lean proofs │ └─► Aristotle (deep)
└── lean-gen (seconds) ├── Kani harnesses └── iterate
└── tests
- Define guarantees — write a
.qedspecdescribing what your program must guarantee, or let your agent generate one from the code or IDL - Validate —
qedgen checkruns the verification waterfall: lint catches structural issues, property tests find counterexamples in milliseconds, Lean catches what tests can't - Generate —
qedgen codegen --allproduces program code, test harnesses, Lean proofs, and CI workflows from the single spec - Prove — your agent fills proof obligations; Leanstral handles routine sub-goals (seconds), Aristotle handles the hardest ones (minutes–hours)
| Property | Approach |
|---|---|
| Access control | Signer checks, authority constraints |
| CPI correctness | Correct program, accounts, flags, and discriminator for each invocation (axiomatic, pure rfl) |
| State machines | Lifecycle correctness, one-shot safety |
| Conservation | Custom invariants (token totals, vault bounds) preserved across operations |
| Arithmetic safety | Overflow/underflow for fixed-width integers, U64 bounds |
| Input validation | Account count, duplicates, data length, discriminators, parameter bounds — each guard maps to a specific error exit |
| Memory correctness | Stack/heap disjointness, pointer arithmetic (sBPF) |
| PDA integrity | Program-derived address derivation and 4-chunk comparison (sBPF) |
CPI calls are axiomatic — we verify the program passes correct parameters. SPL Token internals and the Solana runtime are trusted.
# 1. Install
npx skills add qedgen/solana-skills
# 2. Write a spec and validate it
qedgen check --spec my_program.qedspec
# 3. Generate all artifacts
qedgen codegen --spec my_program.qedspec --allLean proofs, Kani harnesses, and API keys are set up automatically when first needed. To configure them manually:
# Lean + Mathlib (only needed for formal proofs)
qedgen setup --mathlib
# API keys (only needed for sorry-filling and deep proof search)
export MISTRAL_API_KEY=your_key_here # https://console.mistral.ai (free tier available)
export ARISTOTLE_API_KEY=your_key_here # https://aristotle.harmonic.fun# Generate a .qedspec scaffold from your Anchor IDL
qedgen spec --idl target/idl/my_program.json --format qedspec
# Review and complete the TODO items in the generated .qedspec
# Then use the same pipeline as greenfield:
qedgen init --name my_program
qedgen codegen --spec my_program.qedspec --lean
cd formal_verification && lake buildThe generated .qedspec auto-derives state fields, operations, contexts, PDAs, and errors from the IDL. Guards, effects, lifecycle transitions, and properties are stubbed with TODOs for you or your agent to fill in.
# Initialize a new verification project from a .qedspec
qedgen init --name my_program
# Validate the spec (lint + coverage)
qedgen check --spec my_program.qedspec
qedgen check --spec my_program.qedspec --json # machine-readable output
# Generate all committed artifacts from .qedspec
qedgen codegen --spec my_program.qedspec --all # everything: Rust, Lean, Kani, tests
# Or generate selectively
qedgen codegen --spec my_program.qedspec # Quasar Rust skeleton only
qedgen codegen --spec my_program.qedspec --lean # + Lean proofs
qedgen codegen --spec my_program.qedspec --kani # + Kani harnesses
qedgen codegen --spec my_program.qedspec --test # + unit tests
qedgen codegen --spec my_program.qedspec --proptest # + proptest harnesses
qedgen codegen --spec my_program.qedspec --integration # + QuasarSVM integration tests
# Check with drift detection and verification report
qedgen check --spec my_program.qedspec --coverage # operation × property matrix
qedgen check --spec my_program.qedspec --explain # Markdown verification report
qedgen check --spec my_program.qedspec --code ./programs --kani ./tests/kani.rs # drift detection# Transpile sBPF assembly to Lean 4
qedgen asm2lean --input src/program.s --output formal_verification/Program.lean
# Verify sBPF proofs (checks source hash, regenerates if stale)
qedgen check --spec my_program.qedspec --asm src/program.sqedgen generate \
--prompt-file /tmp/analysis/property.prompt.txt \
--output-dir /tmp/proof \
--passes 4 \
--validate# Leanstral (fast, seconds)
qedgen fill-sorry \
--file formal_verification/Spec.lean \
--passes 3 \
--validate
# Auto-escalate to Aristotle if sorry markers remain
qedgen fill-sorry \
--file formal_verification/Spec.lean \
--passes 3 \
--validate \
--escalate# Submit and wait inline
qedgen aristotle submit --project-dir formal_verification --wait
# Or submit, detach, and poll later
qedgen aristotle submit --project-dir formal_verification
qedgen aristotle status <project-id> --wait --output-dir formal_verification
# List / cancel
qedgen aristotle list
qedgen aristotle cancel <project-id>After verifying a function, stamp it with #[qed(verified)] to detect future changes — either to the function body or to its spec contract:
use qedgen_macros::qed;
#[qed(verified,
spec = "my_program.qedspec",
handler = "deposit",
hash = "5af369bb254368d3",
spec_hash = "c3d4e5f67890abcd")]
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
guards::deposit(&ctx, amount)?;
// user business logic
}Both hashes are pure compile-time checks — the macro expands to the function unchanged, so there's zero runtime cost. hash fires when the body changes; spec_hash fires when the .qedspec handler block changes.
# Unified drift report — Rust handlers + Lean theorems vs spec
qedgen reconcile --spec my_program.qedspec --json
# Scan and stamp hashes on all #[qed(verified)] functions
qedgen check --spec my_program.qedspec --drift programs/src/ --update-hashes
# CI gate — exit 1 if any verified function has changed
qedgen check --spec my_program.qedspec --drift programs/src/
# Transitive drift — also check if callees of verified functions changed
qedgen check --spec my_program.qedspec --drift programs/src/ --deepqedgen reconcile is the agent-friendly entry point: it combines Rust-side spec_hash mismatches with Lean-side orphan/missing theorem findings into one machine-readable report, ready for an LLM to consume and act on.
qedgen consolidate \
--input-dir /tmp/proofs \
--output-dir my_program/formal_verificationqedgen codegen --spec my_program.qedspec --ci # Lean-only verification workflow
qedgen codegen --spec my_program.qedspec --ci --ci-asm src/program.s # Add sBPF source hash check- Escrow — Token escrow with lifecycle proofs
- Lending — Lending pool with multi-account state
- Multisig — Multi-signature vault with voting
- Percolator — Perpetual DEX risk engine
- Counter — PDA counter
- Tree — Red-black tree
- Dropset — On-chain order book
- Transfer — SOL transfer via System Program CPI
- Slippage — AMM slippage guard
- Rust toolchain (auto-installed if missing)
The following are only needed when working with Lean proofs and are set up automatically on first use:
- Lean 4 / elan — for
lake buildand formal proofs MISTRAL_API_KEY— forfill-sorryandgenerate(console.mistral.ai, free tier available)ARISTOTLE_API_KEY— foraristotledeep proof search (aristotle.harmonic.fun)
| Variable | Purpose | When needed |
|---|---|---|
MISTRAL_API_KEY |
Leanstral API access (fill-sorry, generate) |
Lean proofs |
ARISTOTLE_API_KEY |
Aristotle long-running proof search | Hard sub-goals |
QEDGEN_HOME |
Override global home directory (default: ~/.qedgen) |
Always |
QEDGEN_VALIDATION_WORKSPACE |
Override validation workspace path | Lean proofs |