Skip to content

Latest commit

 

History

History
159 lines (122 loc) · 6.81 KB

File metadata and controls

159 lines (122 loc) · 6.81 KB

Slither

Static analyzer for Solidity smart contracts. Detects vulnerabilities, prints contract information, and provides an intermediate representation (SlithIR) for analysis.

Architecture

slither/
├── analyses/      # Data dependency, dominators, control flow
├── core/          # Core classes: SlitherCore, Contract, Function
├── detectors/     # Security checks (subclass AbstractDetector)
├── printers/      # Output formatters (subclass AbstractPrinter)
├── slithir/       # Intermediate representation for analysis
├── solc_parsing/  # Solidity AST parsing
└── tools/         # CLI tools (slither-read-storage, slither-mutate, etc.)

See CONTRIBUTING.md for detailed architecture and how to add detectors.

Development

tool purpose
uv deps & venv
ruff lint & format
prek pre-commit hooks
pytest tests
make dev                    # Setup dev environment + pre-commit hooks
make lint                   # Run ruff check
make reformat               # Run ruff format
make test                   # Run all tests
pytest tests/unit/ -q       # Fast unit tests only

Navigating the codebase

Use rg for text search and ast-grep for structural patterns:

# Find class definition
ast-grep --pattern 'class Contract($_): $$$' --lang py slither

# Find all detector implementations
ast-grep --pattern 'class $NAME(AbstractDetector): $$$' --lang py slither/detectors

# Find method usages
rg "\.is_interface" slither

# Find function signatures
ast-grep --pattern 'def _detect($$$)' --lang py slither/detectors

# Trace imports
rg "^from slither\.core" slither

Code Standards

Philosophy

  • No speculative features - Don't add "might be useful" functionality
  • No premature abstraction - Don't create utilities until you've written the same code three times
  • Clarity over cleverness - Prefer explicit, readable code over dense one-liners
  • Justify new dependencies - Each dependency is maintenance burden and complexity
  • Structured output first - New commands must support --json. Human-readable is secondary.
  • Atomic operations - Don't bundle decision logic; separate analyze → suggest → apply for composability.

Code quality

  • Comments - Code should be self-documenting. No commented-out code (delete it). No comments that repeat what code does.
  • Errors - Fail fast with clear, actionable messages. Include context: what failed, which file/contract, suggested fix. Never swallow exceptions.
  • When uncertain - State your assumption and proceed for small decisions. Ask before changes with significant consequences.

Hard limits

  1. ≤80 lines/function, cyclomatic complexity ≤8
  2. ≤5 positional params, ≤12 branches, ≤6 returns
  3. 100-char line length
  4. No relative (..) imports
  5. Tests in /tests/ mirroring package structure

Bash scripts must use strict mode:

#!/bin/bash
set -euo pipefail

Working on Code

Incremental improvement

When modifying a file, improve what you touch. Don't refactor unrelated code—keep PRs focused.

Modernization targets:

  • Type hints on function signatures (aspiration: ty --strict)
  • pathlib.Path over os.path string manipulation
  • f-strings over .format() or % formatting
  • Context managers (with) for file/resource handling
  • Early returns to reduce nesting
  • Fix lint issues you encounter

Git conventions

  • Commit messages: imperative mood, ≤72 char subject (e.g., "Fix reentrancy false positive")
  • One logical change per commit
  • Prefix: fix:, feat:, refactor:, test:, docs: as appropriate

Testing

  • Mock boundaries, not logic - Only mock slow things (network, filesystem), non-deterministic things (time), or external services. Don't mock the code you're testing.
  • Verify tests catch failures - Temporarily break code to verify the test fails, then fix it.

Slither-specific

  • Test detectors across Solidity 0.4.x–0.8.x
  • Update snapshots: tests/e2e/detectors/snapshots/
  • Use compile_force_framework="solc" when crytic-compile behavior changes
  • Run e2e tests early when changing core classes (Literal, Expression, etc.)—snapshots capture exact __str__ output, so behavioral changes break many tests

Slither Internals

APIs

  • Use contract.is_interface not contract.name.startswith("I")
  • Use source_mapping.content for source code access (handles byte/char offsets)
  • Use is / is not for enum comparisons (NodeType.X, not == NodeType.X)
  • CLI features should have Python API equivalents in the Slither class

Traversal patterns

  • Per-definition analysis (naming, arithmetic, structure): Use contracts_derived + functions_declared
  • Reachability analysis (call graphs, taint): Use contracts_derived + functions (inherited functions needed)
  • Global deduplication: Use compilation_unit.functions directly to process each function exactly once
  • Filter by function.contract_declarer == contract when iterating contract.functions
  • high_level_calls returns List[Tuple[Contract, Call]] - don't forget tuple unpacking

Type handling

  • Expand isinstance() checks rather than removing assertions
  • Add type guards before accessing type-specific attributes in AST visitors
  • Check local scope before broader scope when resolving identifiers
  • ElementaryType comparison pitfall: ElementaryType.__eq__ only matches other ElementaryType instances. ElementaryType("uint256") in ["uint256"] is always False. Convert to string first: str(t) in ["uint256"]

SlithIR and SSA

  • Use node.irs for most detectors—simpler, sufficient for most analyses
  • Use node.irs_ssa only when you need precise data flow (tracking reassignments, taint analysis)
  • SSA variables have .index (e.g., x_0, x_1) and .non_ssa_version to get the original
  • Phi operations merge SSA versions at control flow joins (if/else, loops)
  • Data dependency: Use is_dependent(var, source, context) from slither.analyses.data_dependency

Detector quality

Minimize false positives over catching edge cases. Noisy detectors get disabled. Output must be actionable.

Docstrings

Detectors use class attributes, not Google-style docstrings:

  • WIKI_TITLE, WIKI_DESCRIPTION, WIKI_EXPLOIT_SCENARIO, WIKI_RECOMMENDATION
  • Must be thorough—agents use these to decide which detectors apply
  • VULNERABLE_SOLC_VERSIONS restricts detector to specific compiler versions
  • Use make_solc_versions(minor, patch_min, patch_max) helper for version lists

Notes

Version verification: When adding dependencies or CI actions, web search for current stable versions. Training data is stale—never assume a version from memory is current.


Don't push until asked. Don't be hyperbolic in PR writeups.