public/SKILLS/Web3 & Blockchain/move-prover/SKILL.md
Move Prover formal verification expert for Aptos smart contracts. Write specifications (MSL), preconditions (requires), postconditions (ensures), invariants, abort conditions (aborts_if), quantifiers, schemas, and pragmas. Debug verification failures. Triggers on Move Prover, formal verification, spec, invariant, ensures, requires, aborts_if, precondition, postcondition.
npx skillsauth add eric861129/skills_all-in-one move-proverInstall 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.
Formal verification for Move smart contracts - mathematically prove your code is correct.
Testing checks specific inputs. Verification proves ALL inputs.
// Testing: Checks one case
#[test]
fun test_transfer() {
transfer(alice, bob, 100);
}
// Verification: Proves for ALL possible inputs
spec transfer {
ensures sender_balance == old(sender_balance) - amount;
ensures recipient_balance == old(recipient_balance) + amount;
}
requiresConditions that must be true BEFORE function runs:
spec withdraw {
requires exists<Balance>(addr);
requires global<Balance>(addr).coins >= amount;
}
ensuresConditions that must be true AFTER function runs:
spec transfer {
ensures global<Balance>(from).coins == old(global<Balance>(from).coins) - amount;
ensures global<Balance>(to).coins == old(global<Balance>(to).coins) + amount;
}
aborts_ifWhen function should abort:
spec withdraw {
aborts_if !exists<Balance>(addr) with ERROR_NOT_FOUND;
aborts_if global<Balance>(addr).coins < amount with ERROR_INSUFFICIENT;
}
modifiesWhich global resources change:
spec transfer {
modifies global<Balance>(from);
modifies global<Balance>(to);
}
old() OperatorAccess pre-execution values:
spec increment {
ensures counter.value == old(counter.value) + 1;
}
Properties that always hold for a struct:
struct Balance has key {
coins: u64,
locked: u64,
}
spec Balance {
invariant coins >= locked;
}
Properties that hold across the module:
spec module {
invariant [global]
forall addr: address:
exists<Balance>(addr) ==> global<Balance>(addr).coins >= 0;
}
Properties about state transitions:
spec module {
invariant update [global]
forall addr: address:
old(exists<Frozen>(addr)) ==> exists<Frozen>(addr);
// Once frozen, always frozen
}
forallProperty holds for ALL values:
spec transfer {
// All other balances unchanged
ensures forall addr: address where addr != from && addr != to:
global<Balance>(addr).coins == old(global<Balance>(addr).coins);
}
existsProperty holds for AT LEAST ONE value:
spec module {
invariant exists addr: address: exists<AdminCap>(addr);
// At least one admin exists
}
spec schema BalanceExists {
addr: address;
requires exists<Balance>(addr);
}
spec schema SufficientBalance {
addr: address;
amount: u64;
requires global<Balance>(addr).coins >= amount;
}
// Reuse in functions
spec withdraw {
include BalanceExists;
include SufficientBalance;
}
spec module {
pragma verify = true; // Enable verification
pragma aborts_if_is_strict; // Require complete abort specs
pragma timeout = 120; // Timeout in seconds
}
spec complex_function {
pragma verify = false; // Skip this function
pragma timeout = 300; // Custom timeout
}
spec admin_only_function {
requires exists<AdminCap>(signer::address_of(admin));
aborts_if !exists<AdminCap>(signer::address_of(admin));
}
spec module {
// Only one admin
invariant [global]
forall a1: address, a2: address:
exists<AdminCap>(a1) && exists<AdminCap>(a2) ==> a1 == a2;
}
spec module {
fun total_balance(): u64 {
sum(all_addresses(), |addr| {
if (exists<Balance>(addr)) { global<Balance>(addr).coins }
else { 0 }
})
}
invariant [global] total_balance() == global<TotalSupply>(@admin).value;
}
spec transfer {
ensures global<TotalSupply>(@admin).value == old(global<TotalSupply>(@admin).value);
}
spec deposit {
requires global<Balance>(addr).coins + amount <= MAX_U64;
ensures global<Balance>(addr).coins == old(global<Balance>(addr).coins) + amount;
}
# Verify all modules
aptos move prove
# Verify specific module
aptos move prove --filter MyModule
# Verbose output
aptos move prove --verbose
[prover]
enabled = true
timeout = 60
solver = "z3"
error: post-condition does not hold
┌── example.move:15:9 ───
15 │ ensures balance.coins == old(balance.coins) + amount;
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= Counterexample:
amount = MAX_U64
old(balance.coins) = 1
Result: overflow
Solution: Add overflow precondition:
spec deposit {
requires global<Balance>(addr).coins + amount <= MAX_U64;
}
Missing precondition:
// Fails: no existence check
spec withdraw {
ensures global<Balance>(addr).coins == old(global<Balance>(addr).coins) - amount;
}
// Fixed
spec withdraw {
requires exists<Balance>(addr); // Add this
ensures global<Balance>(addr).coins == old(global<Balance>(addr).coins) - amount;
}
Incomplete abort specs:
spec module { pragma aborts_if_is_strict; }
// Fails: missing abort condition
spec transfer {
aborts_if !exists<Balance>(from);
// Missing: aborts_if !exists<Balance>(to);
// Missing: aborts_if global<Balance>(from).coins < amount;
}
Timeout:
spec complex_function {
pragma timeout = 300; // Increase timeout
// Or simplify the specification
}
module 0x1::coin {
struct Coin has key {
value: u64
}
const ERROR_NOT_FOUND: u64 = 1;
const ERROR_INSUFFICIENT: u64 = 2;
public fun transfer(from: &signer, to: address, amount: u64) acquires Coin {
let from_addr = signer::address_of(from);
assert!(exists<Coin>(from_addr), ERROR_NOT_FOUND);
assert!(exists<Coin>(to), ERROR_NOT_FOUND);
let from_coin = borrow_global_mut<Coin>(from_addr);
assert!(from_coin.value >= amount, ERROR_INSUFFICIENT);
from_coin.value = from_coin.value - amount;
let to_coin = borrow_global_mut<Coin>(to);
to_coin.value = to_coin.value + amount;
}
spec transfer {
let from_addr = signer::address_of(from);
// Preconditions
requires exists<Coin>(from_addr);
requires exists<Coin>(to);
requires global<Coin>(from_addr).value >= amount;
requires global<Coin>(to).value + amount <= MAX_U64;
// Abort conditions
aborts_if !exists<Coin>(from_addr) with ERROR_NOT_FOUND;
aborts_if !exists<Coin>(to) with ERROR_NOT_FOUND;
aborts_if global<Coin>(from_addr).value < amount with ERROR_INSUFFICIENT;
// Postconditions
ensures global<Coin>(from_addr).value == old(global<Coin>(from_addr).value) - amount;
ensures global<Coin>(to).value == old(global<Coin>(to).value) + amount;
// Modified resources
modifies global<Coin>(from_addr);
modifies global<Coin>(to);
}
spec module {
pragma verify = true;
pragma aborts_if_is_strict;
}
}
For critical functions, verify:
development
Run structured What-If scenario analysis with multi-branch possibility exploration. Use this skill when the user asks speculative questions like "what if...", "what would happen if...", "what are the possibilities", "explore scenarios", "scenario analysis", "possibility space", "what could go wrong", "best case / worst case", "risk analysis", "contingency planning", "strategic options", or any question about uncertain futures. Also trigger when the user faces a fork-in-the-road decision, wants to stress-test an idea, or needs to think through consequences before committing.
development
Access comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
development
Use when challenging ideas, plans, decisions, or proposals using structured critical reasoning. Invoke to play devil's advocate, run a pre-mortem, red team, or audit evidence and assumptions.
tools
Core skill for the deep research and writing tool. Write scientific manuscripts in full paragraphs (never bullet points). Use two-stage process with (1) section outlines with key points using research-lookup then (2) convert to flowing prose. IMRAD structure, citations (APA/AMA/Vancouver), figures/tables, reporting guidelines (CONSORT/STROBE/PRISMA), for research papers and journal submissions.