cairo-guard
v0.1.1
Published
Invariant testing and on-chain security oracle for Cairo smart contracts on Starknet
Maintainers
Readme
cairo-guard
Invariant testing CLI for Cairo smart contracts on Starknet. Annotate your contracts, generate snforge fuzz tests, and get HTML security reports — all from one command.
Install
npm install -g cairo-guardRequires Node.js 20+. The run command also requires starknet-foundry (snforge) to be installed.
How it works
You add /// @invariant("description") doc comments above -> bool view functions in your Cairo contracts. cairo-guard picks them up, generates snforge test harnesses, runs them, and reports the results.
Annotating your contracts
#[starknet::contract]
pub mod MyToken {
// ... rest of contract ...
/// @invariant("Total supply must never exceed the hard cap")
fn invariant_supply_cap(self: @ContractState) -> bool {
self.total_supply.read() <= MAX_SUPPLY
}
/// @invariant("Zero address must never hold a balance")
fn invariant_no_zero_balance(self: @ContractState) -> bool {
let zero: ContractAddress = Zero::zero();
self.balances.read(zero) == 0
}
}The annotation is a doc comment so the Cairo compiler ignores it completely. The function itself is a plain view function — no macros or compiler plugins needed.
Commands
scan
Finds and displays all invariants in your Cairo files.
cairo-guard scan contracts/src/
cairo-guard scan contracts/src/my_token.cairogenerate
Generates snforge test files from the invariant annotations.
cairo-guard generate contracts/src/ -o contracts/tests/cairo_guard/By default the output goes to ./cairo_guard_tests/. Each Cairo source file gets its own test file, e.g. cairo_guard_my_token_invariants.cairo.
run
Scans, generates tests, and runs them through snforge in one go.
cairo-guard run contracts/Exits with code 1 if any invariant fails.
report
Generates a standalone HTML security report you can share or attach to an audit.
cairo-guard report contracts/src/ -o security_report.htmlGenerated test example
Given a contract my_token.cairo with two invariants, running generate produces:
// AUTO-GENERATED by cairo-guard — do not edit manually
#[cfg(test)]
mod cairo_guard_my_token_invariants {
use snforge_std::{declare, ContractClassTrait, DeclareResultTrait};
#[test]
fn fuzz_invariant_supply_cap() {
let contract = declare("MyToken").unwrap().contract_class();
let (addr, _) = contract.deploy(@array![]).unwrap();
let dispatcher = IMyTokenDispatcher { contract_address: addr };
assert!(
dispatcher.invariant_supply_cap(),
"Invariant violated: Total supply must never exceed the hard cap"
);
}
}Development
git clone https://github.com/soloking1412/CairoGuard.git
cd CairoGuard/cairo-guard
npm install
npm run build # compiles TypeScript to dist/
npm test # 13 vitest testsTo test against the example Cairo contracts in this repo:
# From repo root
npm run build -w cairo-guard
node cairo-guard/dist/index.js scan contracts/src/
node cairo-guard/dist/index.js generate contracts/src/ -o /tmp/cg_testsRequirements
- Node.js 20 or later
snforge0.50+ for theruncommand (install guide)
Part of CairoGuard
This package is the CLI component of CairoGuard, which also includes an on-chain InvariantRegistry contract (Cairo/Starknet) and a web dashboard for monitoring registered protocol invariants.
License
MIT
