recap Command
The recap command generates a compact, audit-friendly summary for an Anchor project.
It inspects IDL(s) under target/idl/, tries to map each IDL to its Anchor crate, performs lightweight source parsing of #[derive(Accounts)] blocks, and emits per-program Markdown tables with: Instruction | Signers | Writable | Constrained | Seeded | Memory.
Usage
# run recap on current directory (default) -> creates ./recap-solazy.md
cargo run -- recap
# run recap on a specific project path (optional -p) -> creates ./recap-solazy.md in the cwd
cargo run -- recap -d ../my-solana-project
Arguments:
-d, --target-dir <PATH>— optional, path to the project root. If omitted the current working directory is used.
How It Works
- Verify the target directory looks like an Anchor project (presence of
Anchor.toml). - Discover IDL JSON files under
target/idl/. - Parse each IDL to obtain instruction and account lists.
- Find Anchor crates in the repo by scanning
Cargo.tomlfiles for ananchor-langdependency, then attempt to map each IDL to the best-matching crate:- prefer crate with the same package name as
idl.name, - otherwise pick the crate with the largest overlap between IDL instruction names and functions discovered in the crate source.
- prefer crate with the same package name as
- For each mapped crate, the implementation concatenates
src/*.rsinto a single string (heuristic) and performs lightweight parsing that:- searches functions for
Context<...>(the parser scans for anyContext<...>occurrence in a function’s parameter list) and extracts the last top-level generic as the Accounts struct name (e.g.Context<'_, '_, '_, 'info, Foo<'info>>→Foo), - extracts
#[derive(Accounts)]structs and aggregates stacked#[account(...)]attributes attached to fields, - detects markers inside the
#[account(...)]attributes:seeds = [...],has_one = ...,address = ...,constraint/constraints, SPL helpers liketoken::mint,associated_token::mint,mint::authority, and memory-related flags likespace,realloc,realloc::zero, - flattens IDL account trees (via
flatten_accounts) to map IDL leaf account names to struct fields and then annotates table columns (Constrained, Seeded, Memory).
- searches functions for
- Produce
recap-solazy.mdcontaining one section per IDL/program and a Markdown table per program.
Output
-
File generated:
recap-solazy.md(created in the current working directory). -
The file contains one section per IDL/program with a Markdown table listing, for each instruction:
- Signers — accounts flagged as signers in the IDL
- Writable — accounts flagged writable /
mutin the IDL - Constrained — fields with
has_one,address,owner,constraint(s)or recognized SPL attribute markers - Seeded — fields using
seeds = [...](detected from#[account(...)]) - Memory — fields using
spaceorrealloc/realloc::zero
The output is intended as a quick-start audit report — readable, compact, and suitable for inclusion in initial findings.
Limitations & Notes (important)
- Anchor-only: the command expects Anchor-style IDLs and an
Anchor.tomlproject marker. Native Rust / Shank projects are not covered by this command. - Heuristic file handling: the tool concatenates
src/*.rsas a quick heuristic (it does not perform Rust module resolution). This is fast and works for many repos, but can miss or mis-attribute items in projects that rely heavily onmod ...;file layout,pub(crate)scope tricks, or macros that generate theAccountsstructs. - Text-based parsing: account/attribute detection is implemented with lightweight parsing / regex heuristics:
- it finds
#[derive(Accounts)]and groups stacked#[account(...)]attributes, - it searches inside attributes for tokens like
seeds = [,has_one =,address =,constraint,space,realloc, and SPL shorthand forms (e.g.associated_token::mint = ...), - these heuristics are fast but can produce false negatives on extremely exotic code constructs, unusual macro expansions, or heavily nested generics inside attributes.
- it finds
Contextdetection: the function-mapper looks for anyContext<...>usage in the fn parameters (qualified or unqualified).- IDL → crate mapping: mapping is best-effort: exact
idl.namematch preferred; otherwise instruction-name overlap is used. In multi-program monorepos this heuristic generally works but may need manual review for ambiguous cases. - Output filename is fixed: the current tool writes results to
recap-solazy.md. Changing this behavior is a small code tweak if you prefer stdout or a configurable filename.
Example
# analyze current project and generate recap-solazy.md
cargo run -- recap
# or if compiled under solazy bin
solazy recap
# or analyze a specific project path
cargo run -- recap -d ../helium-program-library
# or if compiled under solazy bin
solazy recap -d ../helium-program-library