Multi-stage parallelized per-function audit for Solidity contracts with human-in-the-loop review. Discovers functions, captures design decisions, runs 3 analysis stages, then presents findings for developer classification and re-evaluation of disputed items.
How this skill is triggered — by the user, by Claude, or both
Slash command
/solidity-function-audit:solidity-function-auditThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Perform a comprehensive per-function audit of all Solidity contracts in a project using a 6-stage approach. Stage 0 captures design decisions interactively. Stages 1-3 spawn background agents for parallelized analysis. Stage 4 presents findings for developer classification. Stage 5 re-evaluates disputed findings. Stages 0, 4, and 5 are orchestrator-interactive (no agents spawned). Stages 1-3 wr...
Perform a comprehensive per-function audit of all Solidity contracts in a project using a 6-stage approach. Stage 0 captures design decisions interactively. Stages 1-3 spawn background agents for parallelized analysis. Stage 4 presents findings for developer classification. Stage 5 re-evaluates disputed findings. Stages 0, 4, and 5 are orchestrator-interactive (no agents spawned). Stages 1-3 write to markdown files, keeping the main context window minimal.
Check if docs/audit/function-audit/ exists. If it does, ask the user:
docs/audit/function-audit-{YYYY-MM-DD-HHMMSS}/ (using current timestamp) and proceed freshIf the directory does not exist, proceed normally.
$ARGUMENTS as the project path if provided, otherwise use the current working directory.PROJECT_PATH for all subsequent steps.Use Glob for src/**/*.sol (excluding src/artifacts/) to find all source files. Then use Grep for contract \w+ and library \w+ to identify contract and library declarations. Do NOT Read entire source files — only Read a specific file when domain grouping is ambiguous (e.g., a function straddles two contracts). The goal is to know file paths + contract names, not to understand the code.
Use Grep for function \w+\( in each discovered .sol file to find all function declarations. Use Grep context flags (-A 1 or -B 1) to determine visibility from the surrounding lines — do NOT Read full files:
external and public functionsinternal functions (they are often where the real logic lives)Group functions into logical domains using these heuristics (in priority order):
Target 4-10 domains of 3-15 functions each. If the contract has fewer than 15 functions total, use a single domain. If natural grouping exceeds 10 domains, merge the smallest related domains.
mkdir -p docs/audit/function-audit/{stage0,stage1,stage2,stage3,verification,review}
Display to the user:
Build the list of all .sol source file paths (absolute paths) that agents will need to read. Format as one absolute path per line when substituting into {source_file_list} placeholders in agent prompts.
Scan source files for DeFi-relevant patterns to condition Stage 2/3 prompts:
ERC20, ERC721, ERC1155, ERC4626, IERC20, SafeERC20 → set {has_tokens} true/falseUUPSUpgradeable, TransparentProxy, Initializable → set {has_proxies} true/falseAggregatorV3Interface, IOracle, TWAP → set {has_oracles} true/falseAfter each completed stage, write {output_root}/stage-checkpoint.md using the Write tool (full overwrite). Include:
PROJECT_PATH, OUTPUT_ROOTSTAGE_STATUS: key=value pairs for each stage (e.g., preflight=complete stage0=complete stage1=pending). Write as a standalone line starting with STAGE_STATUS: — this line is machine-parsed by the PreCompact hook.DOMAINS: one line per domain with slug, name, and function listFLAGS: has_tokens, has_proxies, has_oraclesPATHS: design_decisions_file, slither_file, and all stage output file paths known so farFINDING_TOTALS with severity countsREVIEW_RESPONSES_FILE and DISPUTED_COUNTBefore each stage, read the checkpoint file to confirm all paths and domain groupings. If state has been lost (e.g., after auto-compaction), recover via:
Glob(pattern: "**/docs/audit/function-audit/stage-checkpoint.md")Capture developer intent before the automated audit. This prevents design trade-offs from being flagged as bugs.
Read the extraction patterns from resources/REVIEW_PROMPTS.md (Stage 0 section). Using the source files already discovered in pre-flight:
@dev comments, static analysis annotations (slither-disable, solhint-disable, @audit), and intent keywords (intentional, by design, trade-off, known, accepted, deliberate)Ownable/AccessControl/custom), upgrade strategy, nonReentrant coverage gaps, whenNotPaused coverage gapsPresent each category to the user following the confirmation script in REVIEW_PROMPTS.md:
Write docs/audit/function-audit/stage0/design-decisions.md using the output format from REVIEW_PROMPTS.md. Store the absolute path as {design_decisions_file} for substitution into agent prompts in Stages 2-3.
Display to the user:
Run Slither static analysis if available. This is NOT an agent — the orchestrator does this directly.
which slither via Bashpip install slither-analyzer for automated static analysis. Continuing without it." → set {slither_file} to empty → proceed to Stage 1slither . --json /tmp/slither-output.json --exclude-informational --filter-paths "test|script|lib|node_modules" 2>&1 || true/tmp/slither-output.json exists and is non-empty (use Bash: test -s /tmp/slither-output.json){slither_file} to empty → proceed to Stage 1docs/audit/function-audit/stage0/slither-findings.md{slither_file} for agent promptsWrite the initial session state checkpoint. Inform the user: "Checkpoint saved. You may run /compact preserve audit stage status, domain groupings, and file paths to free context before agent launch, or say proceed."
Launch 3 Task agents, ALL with run_in_background: true, subagent_type: "general-purpose", and max_turns: 15.
Read the prompt templates from resources/STAGE_PROMPTS.md and fill in the placeholders:
{output_file} — the absolute path to the output markdown file{source_file_list} — the collected source file paths| Agent | Output File | Prompt Template |
|---|---|---|
| 1a: State Variable Map | docs/audit/function-audit/stage1/state-variable-map.md | Stage 1a from STAGE_PROMPTS.md |
| 1b: Access Control Map | docs/audit/function-audit/stage1/access-control-map.md | Stage 1b from STAGE_PROMPTS.md |
| 1c: External Call Map | docs/audit/function-audit/stage1/external-call-map.md | Stage 1c from STAGE_PROMPTS.md |
After launching all 3:
TaskOutput(block: true, timeout: 300000) on each agent to wait for completion (up to 5 minutes each)docs/audit/function-audit/stage1/*.md## ). If validation fails for any file, report the issue to the user and note the file as INCOMPLETE in synthesis.Launch ONE Task agent per domain, ALL with run_in_background: true, subagent_type: "general-purpose", and max_turns: 25.
Read the Stage 2 prompt template from resources/STAGE_PROMPTS.md and fill in:
{domain_name} — the domain name{output_file} — docs/audit/function-audit/stage2/domain-{slug}.md{stage1_state_var_file} — absolute path to stage1/state-variable-map.md{stage1_access_control_file} — absolute path to stage1/access-control-map.md{stage1_external_call_file} — absolute path to stage1/external-call-map.md{design_decisions_file} — absolute path to stage0/design-decisions.md (if Stage 0 produced output){slither_file} — absolute path to stage0/slither-findings.md (empty string if Slither was not run){source_file_list} — source files relevant to this domain: include files containing the domain's functions, files containing contracts called by those functions (from Stage 1c external call map), and files containing inherited contracts or imported libraries. Do NOT include all project source files — scope to what this domain needs.{function_list} — the functions in this domain with their contract and line numbers{template_file} — absolute path to resources/FUNCTION_TEMPLATE.md{example_file} — absolute path to resources/EXAMPLE_OUTPUT.mdAfter launching all domain agents:
TaskOutput(block: true, timeout: 600000) on each agent (up to 10 minutes each — Stage 2 is the heaviest)docs/audit/function-audit/stage2/*.md## heading, contains ## Summary of Findings or ## Cross-Cutting Analysis, and has at least one severity tag (**CRITICAL -- , **HIGH -- , **MEDIUM -- , **LOW -- , or **INFO -- ). If validation fails, note the file as INCOMPLETE in synthesis.Launch 4 Task agents, ALL with run_in_background: true, subagent_type: "general-purpose", and max_turns: 25.
Read the Stage 3 prompt templates from resources/STAGE_PROMPTS.md and fill in:
{output_file} — the absolute path to the output markdown file{stage1_file_list} — all 3 stage 1 file paths{stage2_file_list} — all stage 2 domain file paths{design_decisions_file} — absolute path to stage0/design-decisions.md (if Stage 0 produced output){slither_file} — absolute path to stage0/slither-findings.md (empty string if Slither was not run){source_file_list} — all source file paths| Agent | Output File | Prompt Template |
|---|---|---|
| 3a: State Consistency | docs/audit/function-audit/stage3/state-consistency.md | Stage 3a from STAGE_PROMPTS.md |
| 3b: Math & Rounding | docs/audit/function-audit/stage3/math-rounding.md | Stage 3b from STAGE_PROMPTS.md |
| 3c: Reentrancy & Trust | docs/audit/function-audit/stage3/reentrancy-trust.md | Stage 3c from STAGE_PROMPTS.md |
| 3d: Adversarial Sequences | docs/audit/function-audit/stage3/adversarial-sequences.md | Stage 3d from STAGE_PROMPTS.md |
After launching all 4:
TaskOutput(block: true, timeout: 600000) on each agent (up to 10 minutes each — Stage 3 reads the most material)docs/audit/function-audit/stage3/*.md## heading, and has at least one severity tag (**CRITICAL -- , **HIGH -- , **MEDIUM -- , **LOW -- , or **INFO -- ). If validation fails, note the file as INCOMPLETE in synthesis.After all 3 stages are complete, the orchestrator (you, in the main context) performs synthesis:
Use Grep to extract all findings and verdicts in one pass — do NOT read each output file in full:
Grep(pattern: "\\*\\*(CRITICAL|HIGH|MEDIUM|LOW|INFO) -- ", path: "docs/audit/function-audit/", output_mode: "content") — returns all findings with file paths and line numbersGrep(pattern: "\\*\\*Verdict\\*\\*: \\*\\*", path: "docs/audit/function-audit/", output_mode: "content") — returns all verdictsFrom the Grep output, count findings per severity per file:
**CRITICAL -- matches per file**HIGH -- matches per file**MEDIUM -- matches per file**LOW -- matches per file**INFO -- matches per fileCount per-function verdicts:
**Verdict**: **SOUND** matches**Verdict**: **NEEDS_REVIEW** matches**Verdict**: **ISSUE_FOUND** matchesDo NOT count domain-level overall verdicts (e.g., "Overall Domain Verdict:") in the per-function tally — track those separately.
From the Grep results in step 1, extract each finding's:
CRITICAL, HIGH, MEDIUM, LOW, INFO)-- up to **)Grep(pattern: "### \\w+", path: "{file}") on each file with findings to map findings to their parent functionOnly Read individual files briefly (first/last 10 lines) for executive summary context.
Write docs/audit/function-audit/INDEX.md containing:
# Function Audit -- Index
**Generated**: {date}
**Project**: {project_path}
## Stage 0: Design Decisions
| File | Description |
|------|-------------|
| [design-decisions.md](stage0/design-decisions.md) | Developer-confirmed design intent ({N} categories) |
## Stage 1: Foundation Context
| File | Description | Findings |
|------|-------------|----------|
| [state-variable-map.md](stage1/state-variable-map.md) | State variable analysis | {C}C / {H}H / {M}M / {L}L / {I}I |
| ... | ... | ... |
## Stage 2: Per-Domain Analysis
| File | Domain | Functions | Verdict | Findings |
|------|--------|-----------|---------|----------|
| [domain-{slug}.md](stage2/domain-{slug}.md) | {name} | {N} | {verdict} | {C}C / {H}H / {M}M / {L}L / {I}I |
| ... | ... | ... | ... | ... |
## Stage 3: Cross-Cutting Audit
| File | Focus | Findings |
|------|-------|----------|
| [state-consistency.md](stage3/state-consistency.md) | Accounting invariants, divergent tracking | {C}C / {H}H / {M}M / {L}L / {I}I |
| [adversarial-sequences.md](stage3/adversarial-sequences.md) | Cross-contract exploit sequencing and attacker flows | {C}C / {H}H / {M}M / {L}L / {I}I |
| ... | ... | ... |
## All Findings
| # | Severity | Finding | Location | Source File |
|---|----------|---------|----------|-------------|
| 1 | CRITICAL | {title} | `Contract.function()` L{line} | [domain-{slug}.md](stage2/domain-{slug}.md) |
| 2 | HIGH | {title} | `Contract.function()` L{line} | [state-consistency.md](stage3/state-consistency.md) |
| ... | ... | ... | ... | ... |
Sort by severity (CRITICAL first, then HIGH, MEDIUM, LOW, INFO).
## Totals
- **CRITICAL**: {total}
- **HIGH**: {total}
- **MEDIUM**: {total}
- **LOW**: {total}
- **INFO**: {total}
- Functions: **SOUND** {N} | **NEEDS_REVIEW** {N} | **ISSUE_FOUND** {N}
Write docs/audit/function-audit/SUMMARY.md containing:
Display finding stats and ask if the user wants to proceed to human review:
Update the session state checkpoint (Synthesis complete, add finding tallies). Inform the user: "Checkpoint updated. You may run /compact preserve audit stage status, domain groupings, and finding tallies to free context before interactive review, or proceed directly."
If the user declines, output links to INDEX.md and SUMMARY.md and stop.
Using the "All Findings" master table from INDEX.md, collect all CRITICAL, HIGH, and MEDIUM findings.
Ask the user: "Run automated verification? This spawns one sequential agent per CRITICAL/HIGH finding (Foundry test each) plus one batch agent for MEDIUMs (anti-pattern check only). Estimated: {N} sequential agents + 1 batch. [yes/skip]"
If skip → proceed directly to Stage 4.
mkdir -p docs/audit/function-audit/verification
mkdir -p test/audit-verification
For each CRITICAL/HIGH finding (CRITICALs first, then HIGHs):
resources/VERIFICATION_PROMPTS.md and fill in placeholders:
{finding_number} — zero-padded 3-digit from master table (e.g., 001){finding_severity}, {finding_title}, {finding_source_file}, {finding_function}{output_file} — docs/audit/function-audit/verification/finding-{NNN}.md{test_dir} — absolute path to {PROJECT_PATH}/test/audit-verification/{test_name} — AuditVerify_{NNN}_{ContractName} (PascalCase){source_file_list}, {stage1_file_list}, {design_decisions_file}subagent_type: "solidity-function-audit:solidity-verifier", max_turns: 20TaskOutput(block: true, timeout: 480000) — do NOT launch next agent until completefinding-{NNN}.md is non-empty and contains one of [CONFIRMED], [REFUTED], [LIKELY-FP], [INCONCLUSIVE]If MEDIUM findings exist:
resources/VERIFICATION_PROMPTS.md and fill in {medium_findings_list} (number, title, source file, function, full finding text for each), {output_file} (verification/medium-findings.md), {source_file_list}, {stage1_file_list}, {design_decisions_file}subagent_type: "solidity-function-audit:solidity-verifier", max_turns: 25TaskOutput(block: true, timeout: 600000)medium-findings.md is non-empty and contains ## headingOrchestrator writes docs/audit/function-audit/verification/verification-summary.md with:
| # | Severity | Finding | Verdict | Test File |CONFIRMED: N | REFUTED: N | LIKELY-FP: N | INCONCLUSIVE: NUpdate INDEX.md: add "Verification" section with file links + add "Verified" column to "All Findings" table. Update SUMMARY.md: add "Verification" section with verdict counts and notable confirmed issues. Update session state checkpoint (Verification complete, add verdict tallies).
Report: "Verification complete. {N} CONFIRMED, {N} REFUTED, {N} LIKELY-FP, {N} INCONCLUSIVE. Proceed to findings review? [yes/no]"
Read the review flow from resources/REVIEW_PROMPTS.md (Stage 4 section). Execute interactively:
Extract findings: Parse all stage2/ and stage3/ files for **CRITICAL -- , **HIGH -- , **MEDIUM -- , **LOW -- , **INFO -- patterns. Also note DESIGN_DECISION -- tagged findings separately.
Present CRITICALs (if any): Numbered list with finding title, source function, file link. Ask user to classify each: BUG, DESIGN, DISPUTED, or DISCUSS.
Present HIGHs (if any): Same format.
Present MEDIUMs (if any): Same format.
Present LOWs and INFOs: Show count summary (total LOWs, total INFOs, design-decision tagged, other). Ask "Review LOWs and INFOs? [skip/review]". If review, present in batches of 10.
Follow-up on DISPUTED/DISCUSS: For each, show full finding text + relevant source code, ask user for reasoning, record response.
Write output: Write docs/audit/function-audit/review/review-responses.md using the format from REVIEW_PROMPTS.md.
Update the session state checkpoint (Stage 4 complete, add review file path and disputed count).
Skip this stage entirely if no findings were classified as DISPUTED or DISCUSS in Stage 4.
If DISPUTED or DISCUSS items exist:
resources/REVIEW_PROMPTS.md{output_file} — docs/audit/function-audit/review/re-evaluation.md{design_decisions_file} — absolute path to stage0/design-decisions.md{review_responses_file} — absolute path to review/review-responses.md{source_file_list} — all source file paths{disputed_findings} — the full text of each DISPUTED/DISCUSS finding with developer reasoningrun_in_background: true, subagent_type: "general-purpose", and max_turns: 15TaskOutput(block: true, timeout: 600000)review/re-evaluation.md. Verify it is non-empty and contains at least one ## heading. If validation fails, report the issue to the user.After Stage 5 completes (or is skipped), update SUMMARY.md with a "Human Review" section:
## Human Review
| # | Finding | Original | Classification | Final Status |
|---|---------|----------|----------------|-------------|
| 1 | {title} | CRITICAL | BUG | BUG |
| 2 | {title} | HIGH | DISPUTED | UPHELD (HIGH) |
| 3 | {title} | MEDIUM | DISPUTED | WITHDRAWN |
- **Confirmed bugs**: {N}
- **Design decisions**: {N}
- **Upheld after dispute**: {N}
- **Withdrawn after dispute**: {N}
- **Downgraded**: {N}
- **Needs testing**: {N}
Also update INDEX.md to include the review section:
## Human Review
| File | Description |
|------|-------------|
| [review-responses.md](review/review-responses.md) | Developer classifications ({N} findings reviewed) |
| [re-evaluation.md](review/re-evaluation.md) | Re-evaluation of {N} disputed findings |
Display final summary to the user with links to all output files.
block: true and wait for agent completion. Unfinished agents produce incomplete analysis.subagent_type: "general-purpose". Verification uses solidity-function-audit:solidity-verifier (tool-restricted, background: true encoded in agent definition). All prompts use absolute paths.INCOMPLETE — agent failed.test/audit-verification/ in the project root. Tests are persistent artifacts the developer can re-run.CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=70 in settings for earlier, higher-quality compaction summaries.npx claudepluginhub gonzaloetjo/solidity-audit-skills --plugin solidity-function-auditOrchestrates interactive Solidity smart contract security audits using Map-Hunt-Attack methodology: static analysis (Slither, Aderyn), fuzzing (Echidna, Medusa, Halmos), verification, and reporting.
Audits EVM smart contracts for security vulnerabilities using 500+ checklist items across 19 domains via parallel sub-agents; synthesizes findings and files GitHub issues.
Generates project overviews and audit scopes for smart contract security by mapping structure, entry points, value flows, trust boundaries, and high-risk areas.