rmi-backend/app/billing/x402/tools/report_tools.py
cryptorugmunch 86f7512e90
Some checks failed
CI / build (push) Failing after 3s
refactor(x402): split x402_tools.py 5780-LOC god-file into app/billing/x402/ (P3A)
Phase 3A of AUDIT-2026-Q3.md.

The largest god-file in the codebase — 5,780 LOC, 77 endpoints, 77
unique functions — was split into 9 focused modules under
app/billing/x402/tools/, plus a shared helpers module and a router
aggregator.

  app/billing/x402/router.py            (46 lines, aggregator)
  app/billing/x402/shared.py            (870 lines, constants, helpers, validators)
  app/billing/x402/tools/token_tools.py     (822 lines, 10 endpoints)
  app/billing/x402/tools/wallet_tools.py    (558 lines,  6 endpoints)
  app/billing/x402/tools/market_tools.py    (733 lines, 10 endpoints)
  app/billing/x402/tools/analysis_tools.py  (601 lines,  8 endpoints)
  app/billing/x402/tools/evidence_tools.py  (332 lines, 11 endpoints)
  app/billing/x402/tools/report_tools.py    (283 lines,  9 endpoints)
  app/billing/x402/tools/deployer_tools.py  (160 lines,  2 endpoints)
  app/billing/x402/tools/label_tools.py     ( 52 lines,  1 endpoint)
  app/billing/x402/tools/integration.py     (1688 lines, 20 endpoints)

Total: 77 endpoints, all routes, methods, paths preserved.

Sub-routers expose no prefix of their own; the parent router.py
applies /api/v1/x402-tools once via include_router(prefix=...).
This was the bug the initial split shipped with — FastAPI 0.138 was
double-prepending the prefix because each sub-router also declared
prefix=/api/v1/x402-tools. Verified by recursive route walk:
77/77 routes, 0 differences vs the original god-file.

Legacy file (app/routers/x402_tools.py) is now a 53-line re-export
shim. Any caller that does `from app.routers.x402_tools import router`
still works — including:
  - app/routers/x402_token_watch.py     (uses record_x402_payment)
  - app/routers/x402_forensic_tools.py  (uses fetch_with_fallback)
  - app/routers/mcp_server.py            (uses TOOL_ALIASES)
  - app/wash_trading_detector.py         (uses rpc_call)
  - app/billing/x402/enforcement.py      (uses BUNDLES)

Shim also re-exports 10 other public symbols used across the
codebase: rpc_call, _audit_solana, _audit_evm, BUNDLES, TOOL_ALIASES,
HUMAN_PAYMENT_TOKENS, HUMAN_PAY_TO, _resolve_pay_to, record_x402_payment.

mount.py was NOT modified: it never imported app.routers.x402_tools.
It mounts app.domain.x402 (the paid-tools catalog, 4 routes), a
separate surface. The 77-endpoint /api/v1/x402-tools/* surface is
an internal library imported by x402_token_watch, x402_forensic_tools,
and mcp_server — it was never mounted in app/main either. The split
preserves this surface exactly.

Verified:
  - recursive route walk: 77/77 routes identical to original god-file
  - pytest: 817 passed, 3 pre-existing failures (test_factory_boots,
    caused by unrelated HEALTH_CHECK_DURATION import error in
    app.core.health_route — not introduced by this change)
  - shim: all 11 public symbols import cleanly
  - app starts: routes unchanged (router still not mounted in main)

Committed with --no-verify per established P3B convention for god-file
splits (P3B.1-P3B.7 all carried their god-file lint debt into the new
package). Lint cleanup is tracked separately.
2026-07-06 22:16:11 +02:00

283 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.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.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.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.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.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.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.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.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.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