AI-assisted smart contract development tool — not an audit platform.
Paste a contract address, a GitHub repository URL, or a local Solidity file. Three analysis engines run in parallel, and an LLM synthesizes the findings into a prioritized, human-readable security and quality report — in minutes, not days.
Disclaimer: This tool is designed to assist developers during coding, self-testing, and pre-audit preparation. Results depend on static analysis, symbolic execution, and LLM reasoning — all of which can produce false positives and miss vulnerabilities. It does not replace a professional security audit before mainnet deployment.
Live demo: https://analysis.snome.xyz
Smart contract bugs are expensive. The typical developer workflow has no fast feedback loop between writing code and getting a meaningful security signal. Formal audits are slow and costly; running individual tools manually is tedious and the output is noisy.
This project sits in that gap: a lightweight, self-hostable assistant you can run during development to catch common issues before they reach an auditor — or worse, production.
It is not a replacement for human review. It is a first pass that helps you ask better questions.
- On-chain address — fetches verified source from Etherscan V2 API; handles plain Solidity, Standard JSON, and multi-file projects
- GitHub repository — clones and scans public repos (enable with
ENABLE_GIT_INPUT=true) - Local file / directory — analyze files on disk (enable with
ENABLE_LOCAL_INPUT=true)
- Slither — static analysis: data flow, control flow, 90+ vulnerability detectors; auto-selects the correct
solcversion per contract - Mythril — symbolic execution: models EVM memory and reachability to find logic-level bugs
- Solhint — style and best-practice linting
- All three run concurrently via
ThreadPoolExecutor
- LLM layer (via LiteLLM) synthesizes multi-tool output into confirmed findings, deduplicates noise, and assigns severity ratings (Critical / High / Medium / Low)
- Per-file deep analysis and gas optimization pass run as separate graph nodes
- Supports OpenAI, Anthropic, DeepSeek, Groq, Ollama and any other LiteLLM-compatible provider
- Structured Markdown report: risk overview, confirmed vulnerabilities, fix recommendations, gas optimization suggestions
- Optional JSON summary for programmatic consumption
- Readable in-browser or downloadable
- Async task queue (BullMQ + Redis) with real-time SSE progress streaming
- LangGraph agent pipeline with SqliteSaver checkpoint — supports task resume after interruption
- Web UI (Next.js) with analysis history and in-browser report viewer
- Docker Compose for local and cloud (HTTPS) deployment
- Per-IP rate limiting on the analyze endpoint
flowchart TD
A([User Input]) --> B{Input Type}
B -- "on-chain address" --> C[Fetch from Etherscan]
B -- "GitHub repo URL" --> D[Clone Repository]
B -- "local file / dir" --> E[Load from Disk]
C --> F[Parallel Tool Scan]
D --> F
E --> F
F --> G[Slither\nStatic Analysis]
F --> H[Mythril\nSymbolic Execution]
F --> I[Solhint\nLint Checks]
G --> J[LLM Security Analysis\nper file loop]
H --> J
I --> J
J --> K[Gas Optimization Analysis\nper file loop]
K --> L[Generate Report]
L --> M([Markdown Report\n+ JSON Summary])
M --> N[Web UI / Download]
graph LR
subgraph Web["Web (Next.js 15)"]
UI[React UI\nAnalyzeForm · ProgressPanel\nHistoryList · ReportViewer]
API[API Routes\nPOST /api/analyze\nGET /api/stream/:id SSE\nGET /api/report/:id]
end
subgraph Queue["Task Queue"]
BQ[BullMQ]
RD[(Redis)]
BQ <--> RD
end
subgraph Engine["Analysis Engine (Python)"]
WK[BullMQ Worker]
LG[LangGraph Pipeline]
TL[Tool Runners\nSlither · Mythril · Solhint]
LLM[LiteLLM\nOpenAI · Anthropic · DeepSeek\nGroq · Ollama]
CP[(SQLite\nCheckpoints)]
RP[(Filesystem\nReports)]
end
UI --> API
API --> BQ
BQ --> WK
WK --> LG
LG --> TL
LG --> LLM
LG --> CP
LG --> RP
API -- "SSE stream" --> UI
RP -- "report URL" --> API
| Layer | Technology |
|---|---|
| Frontend | Next.js 15, React 18, TypeScript, Tailwind CSS |
| API | Next.js API Routes |
| Job Queue | BullMQ, IORedis |
| Agent Pipeline | LangGraph, SqliteSaver (checkpoint) |
| LLM Integration | LiteLLM |
| Static Analysis | Slither, solc-select |
| Symbolic Execution | Mythril |
| Linting | Solhint |
| On-chain Source | Etherscan V2 API |
| Deployment | Docker, Docker Compose, Caddy (TLS) |
| Storage | SQLite (checkpoints), filesystem (reports) |
Prerequisites: Docker and Docker Compose installed.
# 1. Clone the repository
git clone https://github.com/your-username/smart-contract-analyzer.git
cd smart-contract-analyzer
# 2. Configure environment
cp .env.example .env
# Open .env and fill in your LLM API key and (optionally) ETHERSCAN_API_KEY
# 3. Start all services
docker compose up -d
# 4. Open the UI
open http://localhost:8926Prerequisites: Python 3.10+, Node.js (for Solhint).
bash setup.sh # creates .venv, installs deps, solc, solhint
source .venv/bin/activate
# Edit .env — set LLM_MODEL and the corresponding API key
# Analyze a local Solidity file
python main.py analyze --path test_contracts/VulnerableVault.sol
# Analyze an on-chain contract (requires ETHERSCAN_API_KEY)
python main.py analyze --address 0xdAC17F958D2ee523a2206206994597C13D831ec7 --network mainnet
# With checkpoint (saves state to checkpoints.db for resume)
python main.py analyze --path foo.sol --checkpoint
# Also save a JSON summary
python main.py analyze --path foo.sol --json
# Pipeline smoke test
python -m src.graph.graph
# Run tests
pytest| Variable | Required | Default | Description |
|---|---|---|---|
LLM_MODEL |
Yes | deepseek/deepseek-chat |
LiteLLM model identifier |
DEEPSEEK_API_KEY |
Conditional | — | API key for DeepSeek |
OPENAI_API_KEY |
Conditional | — | API key for OpenAI |
ANTHROPIC_API_KEY |
Conditional | — | API key for Anthropic |
GROQ_API_KEY |
Conditional | — | API key for Groq |
ETHERSCAN_API_KEY |
No | — | Required for on-chain contract fetching |
PORT |
No | 8926 |
Host port for the web UI |
DOMAIN |
No | — | Domain name for cloud TLS deployment |
REDIS_URL |
No | redis://redis:6379 |
Redis connection URL |
REPORT_DIR |
No | /app/reports |
Directory where reports are saved |
TRACE_DIR |
No | /app/traces |
Directory where execution traces are saved |
WORKER_CONCURRENCY |
No | 1 |
Number of concurrent analysis workers |
ENABLE_GIT_INPUT |
No | false |
Enable GitHub repository analysis |
ENABLE_LOCAL_INPUT |
No | false |
Enable local file path analysis |
ANALYZE_RATE_LIMIT_MAX |
No | 5 |
Max analysis requests per IP per window |
ANALYZE_RATE_LIMIT_WINDOW_MS |
No | 600000 |
Rate limit window in milliseconds (10 min) |
For LLM_MODEL, set only the API key corresponding to your chosen provider. The others can be left blank.
Paste any 0x... address into the web UI, select the network (mainnet / sepolia), and submit. The engine fetches verified source from Etherscan and runs the full pipeline.
Requires ETHERSCAN_API_KEY in .env.
Set ENABLE_GIT_INPUT=true (and NEXT_PUBLIC_ENABLE_GIT_INPUT=true for the frontend build) in .env, then paste a public https://github.com/... URL into the UI.
Set ENABLE_LOCAL_INPUT=true in .env, then provide a file path. This is primarily useful for self-hosted deployments where you control the server environment. The CLI (python main.py analyze --path ...) works without this flag.
The web UI stores completed analyses in browser local storage. Click any entry in the history panel to reload its report. Reports are also available as Markdown files in REPORT_DIR and downloadable directly from the UI.
Each completed analysis produces a Markdown report containing:
| Section | Contents |
|---|---|
| Executive Summary | Overall risk rating (Critical / High / Medium / Low), issue counts by severity |
| LLM Security Analysis | Per-file deep analysis: confirmed vulnerabilities with classification, description, impact scope, source tool, and fix recommendations |
| Gas Optimization | Actionable suggestions to reduce transaction costs per file |
Reports are saved as {stem}_{timestamp}.md in REPORT_DIR. An optional {stem}_{timestamp}.summary.json is written when --json is passed via CLI.
Example finding structure:
[Critical] F-001 — Reentrancy
- Category: reentrancy | Source: slither + manual
- Description: withdraw() sends ETH before updating balances...
- Impact: Attacker can drain the contract...
- Location: VulnerableVault.sol L45-56
- Fix: Apply Checks-Effects-Interactions pattern...
cp .env.example .env # fill in your API key
docker compose up -d
# UI at http://localhost:8926Point a DNS A record at your server, then:
# On your server
cp .env.example .env
# Set DOMAIN=yourdomain.com and your API keys in .env
docker compose -f docker-compose.cloud.yml up -d
# Caddy auto-provisions TLS — accessible at https://yourdomain.com# Build and push images (from project root)
docker buildx build -f Dockerfile.web \
--platform linux/amd64 \
-t snome/scsa-web:latest \
--no-cache \
--push .
docker buildx build -f Dockerfile.engine \
--platform linux/amd64 \
-t snome/scsa-engine:latest \
--no-cache \
--push .
# On the server
docker compose -f docker-compose.cloud.yml pull
docker compose -f docker-compose.cloud.yml up -d --force-recreatesrc/
├── graph/
│ ├── state.py AnalysisState TypedDict — shared data contract
│ ├── graph.py build_graph(), pipeline construction
│ └── nodes/
│ ├── input_nodes.py input_router, load_local, fetch_onchain
│ ├── tool_nodes.py tool_scan (parallel Slither/Mythril/Solhint)
│ ├── llm_nodes.py llm_analyze_file (per-file LLM loop)
│ ├── gas_nodes.py gas_analyze_file (per-file gas loop)
│ ├── report_nodes.py generate_report
│ └── routes.py conditional edge functions
├── tools/
│ ├── slither_runner.py auto-selects solc version, returns uniform dict
│ ├── mythril_runner.py symbolic execution via myth analyze
│ ├── solhint_runner.py style/best-practice lint
│ └── etherscan.py Etherscan V2 source fetcher
├── prompts/
│ ├── security_analysis.py
│ └── gas_optimization.py
├── report/
│ └── generator.py Markdown report writer
└── tracing/
└── tracer.py execution trace + token accounting
web/src/
├── app/
│ ├── page.tsx main UI page
│ ├── components/
│ │ ├── AnalyzeForm.tsx input form
│ │ ├── ProgressPanel.tsx SSE progress tracking
│ │ ├── HistoryList.tsx past analysis history
│ │ └── ReportViewer.tsx in-browser Markdown viewer
│ └── api/
│ ├── analyze/ POST — enqueue job
│ ├── stream/[taskId]/ GET — SSE progress stream
│ ├── task/[taskId]/ GET — task snapshot
│ ├── report/[taskId]/ GET — report content
│ ├── tasks/active/ GET — restore in-flight task
│ └── health/ GET — health check
└── lib/
└── queue.ts BullMQ queue + Redis client
- This tool is a development aid, not a security certification or audit service.
- Findings are generated by automated static analysis, symbolic execution, and LLM inference. All three techniques have known limitations: false positives are common, and subtle or novel vulnerabilities may be missed entirely.
- LLM outputs are non-deterministic and may vary between runs.
- Do not treat a clean report as proof of security. Always conduct manual code review, comprehensive testing, and a professional security audit before deploying contracts that hold real value.
- Foundry / Hardhat test case generation from findings
- CI integration — GitHub Actions workflow template
- Report diff — compare analysis runs across commits
- Additional scanner integrations (e.g. Aderyn, 4naly3er)
- Custom rule support for project-specific checks
- Vulnerability knowledge base with curated fix patterns
- Team workspace — shared history and report collaboration
No license file is currently present in this repository. If you intend to open-source this project, please add a LICENSE file (e.g. MIT, Apache 2.0). Without one, default copyright law applies and others cannot legally use, copy, or distribute the code.
The following details could not be verified from the code alone and may need your input before publishing:
- GitHub repository URL — the README uses a placeholder (
your-username/smart-contract-analyzer). Replace with the actual repo URL. - Docker Hub images —
docker-compose.cloud.ymlreferencessnome/scsa-web:latestandsnome/scsa-engine:latest. If these are not publicly available, the cloud quick-start instructions will not work for others without a build step. - Git input support — the
fetch_onchainnode ingraph.pyonly handles on-chain addresses; there is no correspondingfetch_gitnode visible in the source. TheENABLE_GIT_INPUTflag exists in the web layer but it is unclear whether the engine-side implementation is complete. Please verify before documenting it as a supported input type. - License — no
LICENSEfile exists in the repository. Adding one is strongly recommended before open-sourcing.