/SKILL.md
Formally verify programs by writing Lean 4 proofs. Trigger this skill whenever the user wants to formally verify code, generate Lean 4 proofs, prove properties about algorithms or smart contracts, verify invariants, convert program logic into formal specifications, or anything involving Lean 4 and formal verification. Also trigger when the user mentions "leanstral", "lean proof", "formal proof", "verify my code", "prove correctness", "formal verification", or wants mathematical guarantees about their implementation.
npx skillsauth add abishekk92/leanstral-solana-skill leanstralInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
You (Claude) are the proof engineer. You read the codebase, write Lean 4 models and proofs, iterate on compiler errors, and call Leanstral (Mistral's theorem prover) only for hard sub-goals you cannot fill yourself.
You (Claude) Leanstral (remote model)
├── Read spec / source code ├── Fill sorry markers
├── Write Lean 4 models └── Suggest tactics for hard goals
├── Write theorem statements
├── Write proof attempts
├── Run `lake build`, read errors
└── Fix and iterate
Check for existing artifacts in this priority order:
target/idl/<program>.json) → Run leanstral spec --idl <path> to generate a draft SPEC.md with TODO markers, then refine interactively.If no spec.md was found, run a short interactive quiz — one question at a time, with checkbox options derived from the program's structure. Ask about functionality and risks, not implementation details.
Question 1: "What does this program need to guarantee above all else?" Options derived from the program's structure:
Question 2: "Which scenario worries you most?" Generate concrete risk scenarios from the program.
Question 3: "Does the program make any assumptions that aren't enforced on-chain?"
Ask questions one at a time. Wait for the user's answer before presenting the next question.
Write formal_verification/SPEC.md using normative language (MUST, MUST NOT, MAY). Structure:
# <Program Name> Verification Spec v1.0
<1-2 sentences describing what the program does>
## 0. Security Goals
1. **<Goal name>**: <normative statement>
## 1. State Model
<State struct with field names, types, and comments>
<Lifecycle diagram if applicable>
## 2. Operations
### 2.1 <Operation name>
**Signers**: <who MUST sign>
**Preconditions**: <what MUST be true before>
**Effects**: <numbered steps>
**Postconditions**: <what MUST be true after>
## 3. Formal Properties
### 3.1 <Category>
**<property_id>**: For all <quantified variables>,
if <transition predicate> then <conclusion>.
## 4. Trust Boundary
<What is axiomatic and why>
## 5. Verification Results
| Property | Status | Proof |
|---|---|---|
| ... | **Open** | |
Present SPEC.md to the user and get confirmation before proceeding.
leanstral setup # Ensure global Mathlib cache exists (first time: 15-45 min)
Create the project structure:
formal_verification/
lakefile.lean # import lean_support and Mathlib
lean-toolchain # leanprover/lean4:v4.15.0
lean_support/ # Solana axiom library (copy from leanstral)
Proofs.lean # root import: import Proofs.AccessControl etc.
Proofs/
AccessControl.lean
CpiCorrectness.lean
Conservation.lean
StateMachine.lean
ArithmeticSafety.lean
This is the core step. You write Lean 4 directly — models, transitions, theorems, and proofs.
For each property in SPEC.md:
Option StateType (return none on precondition failure)lake build and iterate on errorsAfter import Leanstral.Solana and open Leanstral.Solana:
Types:
Pubkey (= Nat), U64 (= Nat), U8 (= Nat)Account — { key : Pubkey, authority : Pubkey, balance : Nat, writable : Bool }Lifecycle — open | closed (with DecidableEq)TransferCpi — { program, «from», «to», authority, amount }MintToCpi, BurnCpi, CloseCpiConstants:
TOKEN_PROGRAM_ID, SYSTEM_PROGRAM_IDU8_MAX, U16_MAX, U32_MAX, U64_MAX, U128_MAXFunctions:
findByKey : List Account → Pubkey → Option AccountfindByAuthority : List Account → Pubkey → Option AccountcanWrite : Pubkey → Account → ProptransferCpiValid : TransferCpi → Propcloses : Lifecycle → Lifecycle → Propvalid_u64 : Nat → Prop (and u8, u16, u32, u128)Key lemmas:
closes_is_closed, closes_was_open, closed_irreversiblevalid_u64_preserved_by_zero, valid_u64_preserved_by_samefind_map_update_other, find_map_update_same (axioms for account list updates)Access control — signer must match authority:
structure ProgramState where
authority : Pubkey
def cancelTransition (s : ProgramState) (signer : Pubkey) : Option Unit :=
if signer = s.authority then some () else none
theorem cancel_access_control (s : ProgramState) (signer : Pubkey)
(h : cancelTransition s signer ≠ none) :
signer = s.authority := by
unfold cancelTransition at h
split_ifs at h with h_eq
· exact h_eq
· contradiction
CPI correctness — parameters match (pure rfl):
def cancel_build_cpi (ctx : CancelContext) : TransferCpi :=
{ program := TOKEN_PROGRAM_ID, «from» := ctx.escrow_token, «to» := ctx.dest,
authority := ctx.authority, amount := ctx.amount }
theorem cancel_cpi_correct (ctx : CancelContext) :
let cpi := cancel_build_cpi ctx
cpi.program = TOKEN_PROGRAM_ID ∧ cpi.«from» = ctx.escrow_token ∧
cpi.«to» = ctx.dest ∧ cpi.authority = ctx.authority ∧
cpi.amount = ctx.amount := by
unfold cancel_build_cpi
exact ⟨rfl, rfl, rfl, rfl, rfl⟩
State machine — lifecycle transitions:
def cancelTransition (s : ProgramState) : Option ProgramState :=
if s.escrow.lifecycle = Lifecycle.open then
some { escrow := { s.escrow with lifecycle := Lifecycle.closed } }
else none
theorem cancel_closes_escrow (pre post : ProgramState)
(h : cancelTransition pre = some post) :
post.escrow.lifecycle = Lifecycle.closed := by
unfold cancelTransition at h
split_ifs at h with h_open
cases h
rfl
Conservation — invariant preserved across operations:
def conservation (s : EngineState) : Prop := s.V >= s.C_tot + s.I
def depositTransition (s : EngineState) (amount : Nat) : Option EngineState :=
if s.V + amount <= MAX_VAULT_TVL then
some { V := s.V + amount, C_tot := s.C_tot + amount, I := s.I }
else none
theorem deposit_conservation (s s' : EngineState) (amount : Nat)
(h_inv : conservation s)
(h : depositTransition s amount = some s') :
conservation s' := by
unfold depositTransition at h
split_ifs at h with h_le
· cases h
unfold conservation at h_inv ⊢ -- MUST unfold in BOTH hypothesis and goal
omega
· contradiction
Arithmetic safety — bounds preserved:
def initializeTransition (amount taker : Nat) : Option ProgramState :=
if amount > 0 ∧ amount ≤ U64_MAX ∧ taker > 0 ∧ taker ≤ U64_MAX then
some { initializer_amount := amount, taker_amount := taker }
else none
theorem initialize_arithmetic_safety (amount taker : Nat) (post : ProgramState)
(h : initializeTransition amount taker = some post) :
post.initializer_amount ≤ U64_MAX ∧ post.taker_amount ≤ U64_MAX := by
unfold initializeTransition at h
split_ifs at h with h_bounds
cases h
exact ⟨h_bounds.2.1, h_bounds.2.2.2⟩
| Do | Don't |
|---|---|
| unfold f at h before split_ifs | simp [f] at h before split_ifs (kills if-structure) |
| unfold pred at h_inv ⊢ for named predicates | unfold pred only in goal (omega can't see hypotheses) |
| cases h after split_ifs on some = some | injection h (unnecessary, cases handles it) |
| omega for linear arithmetic | norm_num for linear goals (omega is more reliable) |
| exact ⟨rfl, rfl, rfl⟩ for conjunctions of rfl | constructor + rfl + constructor + rfl (verbose) |
| if cond then ... else ... without proof binding | if h : cond then ... when h is unused |
| Error | Fix |
|---|---|
| omega could not prove the goal | Unfold named predicates in hypotheses: unfold pred at h ⊢ |
| no goals to be solved | Remove redundant tactic (e.g., · contradiction after auto-closed branch) |
| unknown constant 'X' | Check imports; add import Leanstral.Solana.X or open Leanstral.Solana |
| tactic 'split_ifs' failed, no if-then-else | Use unfold first, not simp |
| unused variable 'h' | Remove proof binding: if h : cond → if cond |
When you have a proof with sorry markers you cannot fill after 2-3 attempts:
leanstral fill-sorry --file formal_verification/Proofs/Hard.lean --validate
This sends each sorry location to Leanstral with focused context. Review the result — Leanstral may introduce tactics you can learn from for future proofs.
If fill-sorry also fails, simplify the theorem statement or split the property into smaller lemmas.
cd formal_verification && lake build
Update SPEC.md verification results table:
sorrysorry markersMISTRAL_API_KEY — required for fill-sorry. Free from console.mistral.aiLEANSTRAL_VALIDATION_WORKSPACE — optional override for global Mathlib cache locationlake build is slow: Mathlib compilation takes 15-45 min on first run. Subsequent builds reuse the cache.could not resolve 'HEAD' to a commit: Remove .lake/packages/mathlib and run lake update.fill-sorry.development
Maintainer-only workflow for handling GitHub Secret Scanning alerts on OpenClaw. Use when Codex needs to triage, redact, clean up, and resolve secret leakage found in issue comments, issue bodies, PR comments, or other GitHub content.
development
Maintainer workflow for OpenClaw releases, prereleases, changelog release notes, and publish validation. Use when Codex needs to prepare or verify stable or beta release steps, align version naming, assemble release notes, check release auth requirements, or validate publish-time commands and artifacts.
development
Run, watch, debug, and extend OpenClaw QA testing with qa-lab and qa-channel. Use when Codex needs to execute the repo-backed QA suite, inspect live QA artifacts, debug failing scenarios, add new QA scenarios, or explain the OpenClaw QA workflow. Prefer the live OpenAI lane with regular openai/gpt-5.4 in fast mode; do not use gpt-5.4-pro or gpt-5.4-mini unless the user explicitly overrides that policy.
development
End-to-end Parallels smoke, upgrade, and rerun workflow for OpenClaw across macOS, Windows, and Linux guests. Use when Codex needs to run, rerun, debug, or interpret VM-based install, onboarding, gateway smoke tests, latest-release-to-main upgrade checks, fresh snapshot retests, or optional Discord roundtrip verification under Parallels.