agentleFS
WhyUSayMyNameWhyUSayMyName/skill-proofhound-audit/skills/sc-map/SKILL.md

sc-map

Skill1 starsChanged 5 months agoMITView on GitHub

Stage 2 of the ProofHound smart-contract audit pipeline. Builds the shared mental model of a Solidity protocol from the stage-1 chunk bank — actors and trust model, privileged roles and their abuse surface, asset and external-integration assumptions, money flows, and the protocol invariants (each with a stable INV-N id) that later stages target. Produces .audit/project-map.md and .audit/project-map.json. Run after sc-ingest, before sc-graph and sc-hypothesize.

The file

We split this skill into the rules it gives an agent

10 rules. About 0 are common, 2 are distinctive, and 8 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈2

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 8

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Read project docs: README*, docs/, NatSpec @notice/@dev on the top entry points (Grep "@notice" / read the relevant chunks' natspec).

    line 46
  2. Very specific:

    Read the actual source of the highest-risk entry points (from signals.entry_points: the unprivileged, value-moving, reentrancy-surface …

    line 48
  3. Very specific:

    Read each __state__ chunk to understand the storage model.

    line 50
  4. Very specific:

    Write both artifacts (templates in templates/):

    line 76
  5. Very specific:

    Every item in signals.json must be accounted for in the map — either incorporated or consciously dismissed with a one-line reason.

    line 118
  6. Very specific:

    Every role → appears in §3.

    line 120
  7. Very specific:

    Every integration → appears in §4 with assumptions.

    line 121
  8. Very specific:

    Every invariant_seed → promoted to an INV-N or dismissed with reason.

    line 122
  9. Distinctive:

    Every unprivileged value-moving entry point → in §7 risk register.

    line 123
  10. Distinctive:

    Do not silently drop signals — a dropped signal is an unexamined surface.

    line 124

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

sc-map — Global Project Model (Pipeline Stage 2)

Turns the raw chunk bank into a mental model of intended behavior. This is the single most important input for keeping false positives low: stage 5 can only tell "this deviates from how the protocol is supposed to work" (a finding) from "this is exactly how it's designed" (not a finding) if stage 2 wrote down what "supposed to" means — the invariants, the trust model, the intended powers.

The map is injected (by reference) into every hypothesis and every verification.

When to Use

  • Immediately after sc-ingest succeeds (.audit/manifest.json exists).
  • Orchestrator (sc-audit) calls this second.
  • User says: "model the protocol", "what are the invariants", "build the trust model".

Announce

Begin with: "I'm using the sc-map skill to build the protocol's mental model and invariants..."

Workflow

1. Generate the grounded signal digest (deterministic)

python skills/sc-map/scripts/aggregate_signals.py <audit_dir>   # default .audit

This writes .audit/signals.json: roles + the functions they guard, every entry point with guard/payable/reentrancy flags, classified external integrations, value-moving functions, the full state inventory, and invariant seeds (SEED-N). You MUST reconcile your map against this digest — it is the completeness backstop.

2. Read for intent (not just structure)

Signals tell you what the code does; you also need what it is meant to do.

  • Read project docs: README*, docs/, NatSpec @notice/@dev on the top entry points (Grep "@notice" / read the relevant chunks' natspec).
  • Read the actual source of the highest-risk entry points (from signals.entry_points: the unprivileged, value-moving, reentrancy-surface ones).
  • Read each __state__ chunk to understand the storage model.
  • Note the protocol_type — vault, lending, staking, amm, oracle-dependent, auction, etc. This decides which audit-* checklists stage 4 runs.

Scaling: inline vs fan-out (choose by contract count)

  • Few contracts: inline. Synthesize the whole map yourself (step 3 below).
  • Many contracts: fan-out per module, then reconcile centrally:
    python skills/sc-map/scripts/batch_modules.py <audit_dir> --size 3
    For each map/batches/batch-NNN.json, spawn an sc-map-worker subagent in parallel; each writes a PARTIAL map (local invariants with local_id) for its contracts to map/_partials/. Then reconcile:
    python skills/sc-map/scripts/merge_maps.py <audit_dir> --name "<Protocol>"
    The merge assigns the global, stable INV-N ids, dedups actors/roles/assets/ integrations, and guarantees a generic attacker. Then do one short inline pass to add cross-contract / protocol-level invariants the per-module workers couldn't see (continue the INV-N numbering) — merge_maps flags this in open_questions.

Both paths produce the same project-map.json schema and feed the same downstream stages; fan-out only distributes the per-module modeling.

3. Synthesize the map

(inline path; for fan-out each worker does this for its contracts, then merge) Write both artifacts (templates in templates/):

  • .audit/project-map.md — human-readable (follow project-map.template.md).
  • .audit/project-map.json — structured (conform to project-map.schema.json).

Build each section with discipline:

Actors & trust model. Enumerate privileged (owner/keeper/governance) and unprivileged (user/attacker/liquidator/MEV) actors. For each, capabilities and economic incentive. Always include a generic attacker who can: call any external function, deploy arbitrary contracts, supply malicious tokens/callbacks, and borrow unlimited flash-loan capital. State the trust assumptions explicitly — a bug that only works by violating a stated assumption (e.g. "oracle is honest") is real but must be labeled and is usually lower severity.

Roles / rug surface. For every role in signals.roles, write the worst thing a malicious or key-compromised holder could do, and mark by_design. This is what prevents stage 5 from reporting "owner can change the oracle" as a critical bug when it's an intended admin power — while still capturing it if the power is unintended or unbounded.

Assets & integrations. For each asset handle and integration in signals, write the assumptions the code makes and what breaks if false. Be specific about the classics:

  • Tokens: fee-on-transfer, rebasing, ERC777/callback hooks, non-standard decimals, missing return values, blocklists.
  • Oracles: staleness/heartbeat, manipulation (spot vs TWAP), L2 sequencer uptime, decimals, min/max bounds, multi-feed reuse.
  • Routers/AMMs: slippage, deadline, manipulable quoters, fee-tier assumptions.

Invariants (⭐). Promote signals.invariant_seeds into real invariants with stable INV-N ids, and ADD any the seeds missed (read the code — seeds are only name-pattern heuristics). For each: statement, kind, criticality, enforced_by (chunk IDs), and breaks_if. These IDs are referenced by stage-4 hypotheses (targets: INV-3) and broken by stage-5 PoCs. Aim for the invariants a real auditor would write: conservation (sum of parts == total), solvency (held assets >= liabilities), access (only role X mutates Y), pricing, monotonicity, pause semantics.

Money flow. Narrate where value enters, accrues, and exits, with the guarding conditions. Cross-check against signals.value_movers.

4. Reconcile (completeness gate)

Every item in signals.json must be accounted for in the map — either incorporated or consciously dismissed with a one-line reason. Specifically:

  • Every role → appears in §3.
  • Every integration → appears in §4 with assumptions.
  • Every invariant_seed → promoted to an INV-N or dismissed with reason.
  • Every unprivileged value-moving entry point → in §7 risk register. Do not silently drop signals — a dropped signal is an unexamined surface.

5. Quality gate (see checklist.md)

Confirm before handoff. Key bars: ≥1 critical/high invariant identified per value-handling contract; trust assumptions explicit; every role's rug surface written; project-map.json validates against schema.

Anti-False-Positive Principles (why this stage exists)

  1. Write the intent down. A finding is a deviation from intent. Undocumented intent ⇒ everything looks like a bug ⇒ noise.
  2. Separate by_design powers from bugs. Admin omnipotence that's intended is not a critical finding; mark it so stage 5 doesn't re-litigate it.
  3. Name the trust assumptions. Then "this breaks only if the oracle lies" is a calibrated, labeled finding — not a false alarm and not a missed bug.
  4. Invariants are falsifiable targets. Vague worries don't survive to stage 6; "violates INV-2 (solvency)" with a PoC does.

Handoff

Tell the orchestrator: protocol type(s), count of invariants by criticality, number of by_design admin powers, and any open_questions. Next stage: sc-graph (call / storage / value-flow graphs).

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.