A modular, extensible, and pythonic static analyzer for Solidity smart contracts. Designed for creativity, efficiency, and beauty. Easy to use, easy to extend, and a showcase of advanced Python features and best practices.
- Project Overview
- Features
- Project Structure
- Installation
- Usage
- Detectors & Categories
- Extending the Analyzer
- Configuration
- Testing
- Best Practices
- Support
This tool analyzes Solidity smart contracts for security vulnerabilities, best practices, gas optimizations, and documentation issues. It is:
- Modular: Add new detectors or plugins easily.
- Pythonic: Uses generators, decorators, dataclasses, and context managers.
- Extensible: Plugin system for user-contributed detectors.
- Beautiful: Rich, colorful output and clear findings.
- Security Analysis: Detects reentrancy, access control, signature replay, unchecked calls, and more (20 detectors).
- Best Practices: Flags missing events, poor error messages, redundant code, etc. (5 detectors).
- Gas Optimization: Identifies unbounded loops and other inefficiencies (1 detector).
- Documentation: Checks for missing docs and poor naming (3 detectors).
- Plugin System: Add your own detectors or output formatters.
- Rich Output: Table, JSON, and custom formats.
- Comprehensive Testing: Pytest-based suite for all detectors.
- Easy Extensibility: Decorator-based registration, plugin discovery, and config management.
smart_analyzer/
βββ analyzer.py # Main Analyzer class, AST walker, detector registration
βββ findings.py # Finding base class, subclasses, collector
βββ detectors/ # Built-in vulnerability detectors
β βββ reentrancy.py
β βββ signature.py
β βββ ...
βββ output.py # Output formatting, summary, logging
βββ plugins/ # User-contributed detectors
βββ utils.py # AST utilities, file helpers, decorators
βββ config.py # Configuration management
βββ main.py # CLI entrypoint
βββ requirements.txt # Python dependencies
βββ README.md # This file!
- Clone the repository
git clone https://github.com/mcastiglione/olympix-test.git cd olympix-test - Install dependencies
pip install -r requirements.txt
- (Optional) Set up a virtual environment:
python -m venv venv source venv/bin/activate
python main.py analyze contracts/-o, --output PATHOutput file for results-f, --format [table|json|csv]Output format-s, --severity [LOW|MEDIUM|HIGH|CRITICAL]Filter by severity-c, --categories TEXTDetector categories to run (security, best_practices, gas_optimization, documentation)-d, --detectors TEXTSpecific detectors to run-e, --exclude TEXTDetectors to exclude--debugEnable debug mode-v, --verboseVerbose output--helpShow help message
python main.py analyze contracts/ --severity HIGH --format json
python main.py analyze contracts/ --categories security best_practices
python main.py analyze contracts/ --detectors reentrancy oracle_manipulationfrom smart_analyzer.analyzer import Analyzer
from smart_analyzer.findings import FindingCollector
analyzer = Analyzer()
collector = FindingCollector()
for finding in analyzer.analyze_contracts('contracts/'):
collector.add(finding)
print(collector) # Uses __str__ for beautiful output- Reentrancy
- Access Control
- Flash Loan
- Front Running
- Timestamp
- Delegate Call
- Uninitialized
- Zero Address
- MEV
- Storage Collision
- Upgrade
- Cross Chain
- tx.origin
- Integer Overflow
- Oracle Manipulation
- Signature Replay
- Unchecked Call
- Signature in Loop
- Oracle Signature Reuse
- Oracle Price Manipulation
- Events
- Type Cast
- Modifier
- Redundant Code
- Error Messages
- Gas Limit
- Hardcoded
- Documentation
- Naming
python main.py analyze contracts/ --categories security
python main.py analyze contracts/ --categories best_practicespython main.py list-detectorsBuilt-in:
Create a new file in detectors/:
from typing import Dict, Any, List
from ..utils import detector, parse_src
from ..findings import Finding, Severity
from dataclasses import dataclass
@dataclass
class MyVulnerabilityFinding(Finding):
def __post_init__(self):
self.type = "My Vulnerability"
if not self.severity:
self.severity = Severity.MEDIUM
@detector("my_vulnerability", "π My Vulnerability", "Detects my custom vulnerability")
def detect_my_vulnerability(node: Dict[str, Any], findings: List, file_path: str = None) -> None:
if node.get("nodeType") == "FunctionCall":
expr = node.get("expression", {})
if expr.get("nodeType") == "Identifier" and expr.get("name") == "dangerousFunction":
line_num = parse_src(node.get("src"), file_path)
findings.append(MyVulnerabilityFinding(
message="Dangerous function call detected without proper checks.",
severity=Severity.HIGH,
line_number=line_num,
file_path=file_path,
source_code=node.get("src")
))Plugin:
Create a file in plugins/:
from smart_analyzer.utils import detector, parse_src
from smart_analyzer.findings import Finding, Severity
from dataclasses import dataclass
@dataclass
class CustomVulnerabilityFinding(Finding):
def __post_init__(self):
self.type = "Custom Vulnerability"
if not self.severity:
self.severity = Severity.CRITICAL
@detector("custom_vulnerability", "π¨ Custom", "Detects custom vulnerability patterns")
def detect_custom_vulnerability(node, findings, file_path=None):
if node.get("nodeType") == "FunctionCall":
expr = node.get("expression", {})
if (expr.get("nodeType") == "MemberAccess" and expr.get("memberName") == "delegatecall"):
line_num = parse_src(node.get("src"), file_path)
findings.append(CustomVulnerabilityFinding(
message="Unsafe delegatecall detected. Validate the target contract.",
severity=Severity.CRITICAL,
line_number=line_num,
file_path=file_path,
source_code=node.get("src")
))- Place your plugin in
plugins/ - Use the
@detectordecorator - Document your plugin with a docstring
- Import from
smart_analyzer
You can create custom output formatters by extending OutputFormatter in output.py.
Extend AnalyzerConfig in config.py for custom settings. See analyzer_config.yaml for examples.
Example analyzer_config.yaml:
output_format: rich
show_progress: true
show_summary: true
# Custom plugin settings
my_plugin_enabled: true
my_plugin_threshold: 10
my_plugin_patterns:
- "*.sol"
- "contracts/**/*.sol"
enabled_detectors:
- "my_vulnerability"
- "custom_vulnerability"
disabled_detectors:
- "tx_origin"# Run comprehensive test suite (recommended)
python main.py test-comprehensive
# Run specific test file with pytest
python -m pytest tests/test_comprehensive_detectors.py -v
# Run all tests with pytest
python -m pytest tests/ -v- Place test files in
tests/ - Use
pytestfor new detectors/plugins - Follow the existing test patterns in
test_comprehensive_detectors.py
- Single Responsibility: Each detector should focus on one vulnerability type
- Clear Messages: Provide actionable, specific error messages
- Proper Severity: Use appropriate severity levels (LOW, MEDIUM, HIGH, CRITICAL)
- Line Numbers: Always include accurate line numbers for findings
- Efficient AST Walking: Use generators for memory efficiency
- Early Exit: Return early when possible to avoid unnecessary processing
- Graceful Degradation: Handle parsing errors without crashing
- Comprehensive Coverage: Test all code paths in your detectors
- Clear Docstrings: Document all functions and classes
- Examples: Provide usage examples for complex detectors
- Issues: Report bugs and request features on GitHub
- Discussions: Join community discussions for help and ideas
- Documentation: See this README for all info
- Examples: Look at existing detectors and plugins for reference
Happy coding! πβ¨