284 lines
11 KiB
Python
284 lines
11 KiB
Python
"""x402 SENTINEL TIER 2/3 + visualization tools — flash loans, oracle, governance,
|
|
proxy, static analysis, decompilation, fund flow, contract diff.
|
|
|
|
Phase 3A of AUDIT-2026-Q3.md (split from app/routers/x402_tools.py).
|
|
|
|
Endpoints mounted on sub_router:
|
|
POST /api/v1/x402-tools/flash_loan_detect
|
|
POST /api/v1/x402-tools/pump_dump_detect
|
|
POST /api/v1/x402-tools/oracle_manipulation
|
|
POST /api/v1/x402-tools/governance_attack
|
|
POST /api/v1/x402-tools/proxy_detect
|
|
POST /api/v1/x402-tools/static_analysis
|
|
POST /api/v1/x402-tools/decompiler_analysis
|
|
POST /api/v1/x402-tools/fund_flow
|
|
POST /api/v1/x402-tools/contract_diff
|
|
|
|
Address labels live in tools/label_tools.py.
|
|
TIER 1 modules (holder analysis, bundle detect, etc.) live in
|
|
tools/evidence_tools.py.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from datetime import datetime
|
|
|
|
from fastapi import APIRouter, HTTPException
|
|
|
|
from app.domains.billing.x402.shared import (
|
|
SentinelModuleRequest,
|
|
record_x402_payment,
|
|
)
|
|
|
|
sub_router = APIRouter(tags=["x402-sentinel-t2-t3"])
|
|
|
|
|
|
@sub_router.post("/flash_loan_detect")
|
|
async def flash_loan_detect_endpoint(req: SentinelModuleRequest):
|
|
"""SENTINEL Flash Loan Detection - borrow-then-dump patterns, single-block exploits.
|
|
|
|
Pricing: $0.08
|
|
Detects wallet activity that matches flash loan attack patterns:
|
|
large buy/sell in consecutive blocks, near-zero pre-trade balance,
|
|
volume exceeding pool liquidity ratio.
|
|
"""
|
|
try:
|
|
from app.domains.scanners.sentinel_pipeline import run_flash_loan_detection
|
|
|
|
result = await run_flash_loan_detection(req.address, req.chain)
|
|
await record_x402_payment("flash_loan_detect", "0.08", req.address)
|
|
|
|
return {
|
|
"tool": "SENTINEL Flash Loan Detection",
|
|
"version": "1.0",
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"address": req.address,
|
|
"chain": req.chain,
|
|
**result,
|
|
"guarantee": "Data delivered or auto-refund via x402 receipt",
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e)) from e
|
|
|
|
|
|
@sub_router.post("/pump_dump_detect")
|
|
async def pump_dump_detect_endpoint(req: SentinelModuleRequest):
|
|
"""SENTINEL Pump-and-Dump Detection - volume spikes, coordinated buys, lifecycle stage.
|
|
|
|
Pricing: $0.08
|
|
Detects pump-and-dump patterns: sudden volume spikes (>5x average),
|
|
coordinated fresh-wallet buy clusters, price-volume divergence,
|
|
and rug pull lifecycle stage (deploy/pump/distribution/dump).
|
|
"""
|
|
try:
|
|
from app.domains.scanners.sentinel_pipeline import run_pump_dump_detection
|
|
|
|
result = await run_pump_dump_detection(req.address, req.chain)
|
|
await record_x402_payment("pump_dump_detect", "0.08", req.address)
|
|
|
|
return {
|
|
"tool": "SENTINEL Pump-and-Dump Detection",
|
|
"version": "1.0",
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"address": req.address,
|
|
"chain": req.chain,
|
|
**result,
|
|
"guarantee": "Data delivered or auto-refund via x402 receipt",
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e)) from e
|
|
|
|
|
|
@sub_router.post("/oracle_manipulation")
|
|
async def oracle_manipulation_endpoint(req: SentinelModuleRequest):
|
|
"""SENTINEL Oracle Manipulation - oracle source analysis, price manipulation vulnerability.
|
|
|
|
Pricing: $0.08
|
|
Analyzes oracle risk: single-source dependency, pool depth vulnerability,
|
|
DEX-vs-oracle price deviation, and overall manipulable score.
|
|
Critical for lending/borrowing protocols that rely on price feeds.
|
|
"""
|
|
try:
|
|
from app.domains.scanners.sentinel_pipeline import run_oracle_manipulation
|
|
|
|
result = await run_oracle_manipulation(req.address, req.chain)
|
|
await record_x402_payment("oracle_manipulation", "0.08", req.address)
|
|
|
|
return {
|
|
"tool": "SENTINEL Oracle Manipulation",
|
|
"version": "1.0",
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"address": req.address,
|
|
"chain": req.chain,
|
|
**result,
|
|
"guarantee": "Data delivered or auto-refund via x402 receipt",
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e)) from e
|
|
|
|
|
|
@sub_router.post("/governance_attack")
|
|
async def governance_attack_endpoint(req: SentinelModuleRequest):
|
|
"""x402 Governance Attack - governance concentration, timelock/quorum risk detection.
|
|
|
|
Pricing: $0.08 (x402 tool #44)
|
|
Detects governance risks: top holder dominance (>50%), missing timelock,
|
|
low quorum thresholds enabling flash-loan governance attacks,
|
|
and admin key concentration on Solana programs.
|
|
|
|
Standalone module: app/governance_attack_detector.py
|
|
"""
|
|
try:
|
|
from app.governance_attack_detector import detect_governance_attack
|
|
|
|
result = await detect_governance_attack(req.address, req.chain)
|
|
await record_x402_payment("governance_attack", "0.08", req.address)
|
|
|
|
return {
|
|
"tool": "Governance Attack & Concentration Risk Detector",
|
|
"version": "1.0",
|
|
"pricing": "$0.08 per analysis, 1 free trial",
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"token_address": req.address,
|
|
"chain": req.chain,
|
|
**result,
|
|
"guarantee": "Data delivered or auto-refund via x402 receipt",
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e)) from e
|
|
|
|
|
|
@sub_router.post("/proxy_detect")
|
|
async def proxy_detect_endpoint(req: SentinelModuleRequest):
|
|
"""SENTINEL Proxy Detection - proxy resolution, implementation fingerprinting, upgrade risk.
|
|
|
|
Pricing: $0.08
|
|
Resolves proxy contracts to their real implementation, checks upgrade authority
|
|
and timelock status, and fingerprints implementation bytecode against known
|
|
rug contract patterns. Essential for EVM tokens behind proxies.
|
|
"""
|
|
try:
|
|
from app.domains.scanners.sentinel_pipeline import run_proxy_detection
|
|
|
|
result = await run_proxy_detection(req.address, req.chain)
|
|
await record_x402_payment("proxy_detect", "0.08", req.address)
|
|
|
|
return {
|
|
"tool": "SENTINEL Proxy Detection",
|
|
"version": "1.0",
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"address": req.address,
|
|
"chain": req.chain,
|
|
**result,
|
|
"guarantee": "Data delivered or auto-refund via x402 receipt",
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e)) from e
|
|
|
|
|
|
@sub_router.post("/static_analysis")
|
|
async def static_analysis_endpoint(req: SentinelModuleRequest):
|
|
"""SENTINEL Static Analysis - Slither vulnerability detection + Forta alert integration.
|
|
|
|
Pricing: $0.12
|
|
Runs Slither static analysis on verified (or Heimdall-decompiled) contracts
|
|
and queries Forta public alerts for the address. Returns vulnerability findings
|
|
and active threat alerts.
|
|
"""
|
|
try:
|
|
from app.domains.scanners.sentinel_pipeline import run_static_analysis
|
|
|
|
result = await run_static_analysis(req.address, req.chain)
|
|
await record_x402_payment("static_analysis", "0.12", req.address)
|
|
|
|
return {
|
|
"tool": "SENTINEL Static Analysis",
|
|
"version": "1.0",
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"address": req.address,
|
|
"chain": req.chain,
|
|
**result,
|
|
"guarantee": "Data delivered or auto-refund via x402 receipt",
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e)) from e
|
|
|
|
|
|
@sub_router.post("/decompiler_analysis")
|
|
async def decompiler_analysis_endpoint(req: SentinelModuleRequest):
|
|
"""SENTINEL Decompiler Analysis - Heimdall decompilation + whatsABI function extraction.
|
|
|
|
Pricing: $0.10
|
|
Decompiles unverified contract bytecode using Heimdall-rs, extracts function
|
|
selectors via PUSH4 scanning, and identifies dangerous rug-pull function signatures.
|
|
Essential for tokens with unverified source code.
|
|
"""
|
|
try:
|
|
from app.domains.scanners.sentinel_pipeline import run_decompiler_analysis
|
|
|
|
result = await run_decompiler_analysis(req.address, req.chain)
|
|
await record_x402_payment("decompiler_analysis", "0.10", req.address)
|
|
|
|
return {
|
|
"tool": "SENTINEL Decompiler Analysis",
|
|
"version": "1.0",
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"address": req.address,
|
|
"chain": req.chain,
|
|
**result,
|
|
"guarantee": "Data delivered or auto-refund via x402 receipt",
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e)) from e
|
|
|
|
|
|
@sub_router.post("/fund_flow")
|
|
async def fund_flow_endpoint(req: SentinelModuleRequest):
|
|
"""SENTINEL Fund Flow Visualization - SVG fund flow graph for token analysis.
|
|
Pricing: $0.10
|
|
"""
|
|
try:
|
|
from app.domains.scanners.sentinel_pipeline import run_fund_flow
|
|
|
|
result = await run_fund_flow(req.address, req.chain)
|
|
await record_x402_payment("fund_flow", "0.10", req.address)
|
|
return {
|
|
"tool": "SENTINEL Fund Flow",
|
|
"version": "1.0",
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"address": req.address,
|
|
"chain": req.chain,
|
|
**result,
|
|
"guarantee": "Data delivered or auto-refund via x402 receipt",
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e)) from e
|
|
|
|
|
|
@sub_router.post("/contract_diff")
|
|
async def contract_diff_endpoint(req: SentinelModuleRequest):
|
|
"""SENTINEL Contract Diff - bytecode hash comparison against known rug contracts.
|
|
|
|
Pricing: $0.10
|
|
Compares a token's contract bytecode against a database of known rug contracts.
|
|
Detects clones, forks, and near-identical contracts by hashing function selectors,
|
|
bytecode sections, and metadata patterns. Identifies dangerous function signatures
|
|
(withdrawAll, drain, setOwner, emergencyWithdraw) and rug-specific bytecode patterns.
|
|
"""
|
|
try:
|
|
from app.domains.scanners.sentinel_pipeline import run_contract_diff
|
|
|
|
result = await run_contract_diff(req.address, req.chain)
|
|
await record_x402_payment("contract_diff", "0.10", req.address)
|
|
|
|
return {
|
|
"tool": "SENTINEL Contract Diff",
|
|
"version": "1.0",
|
|
"timestamp": datetime.utcnow().isoformat(),
|
|
"address": req.address,
|
|
"chain": req.chain,
|
|
**result,
|
|
"guarantee": "Data delivered or auto-refund via x402 receipt",
|
|
}
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e)) from e
|