For Agents

The contract-scanner project went designed → planned → SHIPPED all on 2026-05-30. The 10-task TDD plan was executed; the MVP is built and live-validated (commit 5be49b6, repo github.com/wowjeeez/bsc-vuln-scanner). This note captures the planning decisions (build order + concrete tech choices) — it does NOT re-state the design doc. For the workflow architecture, the BSC discovery funnel, target picks, and honest caveats, read contract-scanner first. For what was discovered actually executing this plan — the verified tool behaviors and the false assumptions that caused silent false-negatives — read verified-tool-behavior. For the follow-on Phase 2A address-resolution work, read phase2-address-resolution.

Outcome

All 10 tasks shipped. Task 10’s live EA Finance validation (which the plan marked BLOCKED on a free Etherscan key) unblocked and passed: the user’s free Etherscan V2 key worked for BSC, and the MVP produced real leads against EA Finance’s wCC contract (0x6050d829f5a5e0ea758d8357ddcdec1381699248) — divide-before-multiply in reward calcs and unused-return on a message inspector.

Plan file location

/Users/levander/coding/bsc-vuln-scanner/docs/superpowers/plans/2026-05-30-mvp-bsc-scanner.md 10 tasks, TDD (red → green → checkpoint per task). Driven by the superpowers:subagent-driven-development skill. Each task ends at a green-test Checkpoint instead of a commit (project rule: never auto-commit).

What’s new vs the design doc

The design doc (contract-scanner) answered what to build and why. The plan answers in what order, with which exact tools, and where the gotchas are. The decisions below are the new knowledge.

Build strategy — vertical slice first

Push ONE real contract (EA Finance) through all 5 stages end-to-end (Tasks 2–7) before generalizing to the batch funnel (Task 8).

  • Tasks 2–6 build each stage’s inner functions (logic + a thin I/O wrapper), unit-tested with saved fixtures.
  • Task 7 wires the orchestrator for a single contract via --slug / --address.
  • Task 8 generalizes the same code to the batch funnel (ThreadPoolExecutor, --batch --limit), refactoring run_slice to reuse an extracted run_slice_collect (DRY).

Rationale

Fastest path to a real Slither finding; de-risks each stage on live data one at a time instead of debugging a whole batch funnel at once. This is the design doc’s “validation play” expressed as build order — prove value on EA Finance, then scale.

Key technical decisions (with rationale)

These are the load-bearing build-time choices

Each differs from or refines the design doc. Don’t lose them in implementation.

1. Pin Python 3.12 (not system 3.14) via uv

uv init --python 3.12. Slither / slither-analyzer does not reliably support Python 3.14 yet. 3.12 also matches the eventual Docker base image (python:3.12-slim), so local and container behavior stay identical.

Gotcha

Running on the system 3.14 will break Slither. The project is pinned to 3.12 on purpose — do not “upgrade” it.

2. Etherscan V2 unified API — not legacy BscScan

Stage 3 uses the Etherscan V2 unified endpoint (https://api.etherscan.io/v2/api with chainid=56 for BSC and a single API key), not the legacy per-chain BscScan endpoint the design doc mentioned. The base URL is config-driven (config.yaml → chain.explorer_base).

Rationale

One key works across all chains, so Stage 3 is already Phase-2-multichain-ready — flipping to Ethereum/Polygon/Arbitrum/Base/Optimism is just a different chainid, no new client. A chainid regression assertion is baked into the Task 4 fetch test.

3. Slither runtime: local uv now → whole pipeline in Docker at the end

Slither is invoked as a subprocess on PATH (slither <target> --json -), so it behaves identically whether installed locally via uv or baked into the final image. Develop locally now; Task 9 packages the entire pipeline (scanner + Slither + solc) into one Dockerfile at the end — not stage-by-stage containerization. User’s explicit preference. solc-select installs/pins the per-contract compiler version (e.g. 0.8.19).

4. API key is a placeholder until Task 10

Build and test entirely on saved fixtures (key read from ETHERSCAN_API_KEY env / .env). Live EA Finance validation is deferred to Task 10, which is explicitly BLOCKED on the user adding a free Etherscan V2 key. Task 10 is a runbook, not an automated test (depends on live third-party data).

5. Architecture refinement — pure logic split from I/O

Each stage file splits pure logic (filtering / parsing / scoring — unit-tested with fixtures) from I/O (HTTP / subprocess — thin wrappers, one light test each). Shared dataclasses (Protocol, SourceResult, Finding) live once in scanner/models.py; shared config in config.yaml + a single cfg pytest fixture. Stage 5 (triage) is confirmed the largest task (Task 6) — matches the design doc’s “half the engineering is triage” principle.

Environment / tooling facts discovered (2026-05-30)

For Agents — verified state of the dev box

  • Project folder: ~/coding/bsc-vuln-scanner (hyphen) — was empty, not a git repo.
  • uv 0.10.9 available.
  • Docker 28.5.2 daemon running (needed for Task 9).
  • Slither not previously installed — added via uv add slither-analyzer solc-select.
  • No chain API keys in env — hence the placeholder approach and the Task 10 block.

Path reconciliation — hyphen, not underscore

The design doc suggested ~/coding/contract_scanner/ (underscore). The actual project lives at ~/coding/bsc-vuln-scanner/ (hyphen) — we are using the existing hyphen folder. Ignore the design doc’s underscore path; it was a pre-implementation suggestion.

Project policy baked into the plan

  • No commits — each task ends at a green-test Checkpoint, not a git commit.
  • No comments — all code is comment-free / self-explanatory.
  • DRY — shared config + types live in one place; run_slice reuses run_slice_collect.
  • Run via venv — prefix commands with uv run so slither / solc-select resolve from .venv/bin.

Task map (at a glance)

TaskStage / concernNotes
1Scaffold + data modelsuv init --python 3.12, models.py, config.yaml
2Stage 1 Discoverfilters + Binance-not-BSC regression test
3Stage 2 Resolveslug → BSC addresses
4Stage 3 Fetch sourceEtherscan V2 getsourcecode, unverified-skip, format parsing
5Stage 4 Analyzesolc-select + Slither subprocess + parse (+ marked integration test)
6Stage 5 Triagededupe + drop FPs + score + CSV — largest task
7Orchestrator — vertical slicesingle contract end-to-end (--slug/--address)
8Generalize to batch funnelThreadPoolExecutor, --batch --limit
9Containerize whole pipelineone Dockerfile (scanner + Slither + solc)
10Live EA Finance validationBLOCKED on API key — runbook, not a test
  • contract-scanner — the design doc (architecture, BSC funnel, targets, caveats); read first
  • LOG — this project’s session log
  • TOPICS — this project’s theme index