rmi-backend/app/routers/unified_scanner_router.py
cryptorugmunch f1d357e70a
Some checks failed
CI / build (push) Failing after 3s
fix(rmi-backend,audit): re-apply Wave 3 mount + pyproject excludes (P2.3 lost+recovered)
The previous P2.3 commit (628c1d2) only captured the file renames; the
mount.py + pyproject.toml + unified_scanner_router.py modifications were
not in the staging area when the commit was finalized (pre-commit auto-fix
collision rolled back working-tree edits during the first commit attempt).

This follow-up restores the missing pieces:

- app/mount.py: adds app.routers.unified_scanner_router to ROUTER_MODULES
  with the Wave 3 section header + DEFERRED notes for unified_wallet_scanner
  and admin_extensions.
- app/routers/unified_scanner_router.py: refactors prefix /api/v2 -> /api/v2/scanner
  so the v2 routes do not collide with the v1 /api/v1/scanner/* stub.
- pyproject.toml: setuptools.packages.find, ruff.extend-exclude, and
  mypy.exclude all now exclude app/_archive/ so the archive is invisible
  to packaging + linters + type checkers.

Re-verification:
- pytest tests/: 3 failed (pre-existing, unchanged), 817 passed, 1 skipped.
- mount.py mounts 52 routers; /api/v2/scanner/{token,wallet}/scan live.
2026-07-06 21:02:58 +02:00

97 lines
3.4 KiB
Python

"""Unified Scanner Router v3 - matches WalletScanner v3 fields."""
import logging
from fastapi import APIRouter, HTTPException, Request
from pydantic import BaseModel
from app.unified_token_scanner import get_token_scanner
from app.unified_wallet_scanner import get_wallet_scanner
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/v2/scanner", tags=["scanner-v2"])
class TokenScanRequest(BaseModel):
address: str
chain: str = "solana"
class WalletScanRequest(BaseModel):
address: str
chain: str = "solana"
def _get_tier(request):
if request.headers.get("X-RMI-Key") == "rmi-internal-2026":
return "admin"
if request.headers.get("X-Payment-Verified") == "true":
return "pro"
return "free"
def _get_admin_key(request):
return request.headers.get("X-Admin-Key") or request.headers.get("X-RMI-Key")
@router.post("/token/scan")
async def scan_token(request: Request, body: TokenScanRequest):
tier = _get_tier(request)
admin_key = _get_admin_key(request)
try:
scanner = get_token_scanner()
result = await scanner.scan(address=body.address, chain=body.chain, tier=tier, admin_key=admin_key)
return {
"status": "ok",
"token": result.token_address,
"chain": result.chain,
"name": result.name,
"symbol": result.symbol,
"price_usd": result.price_usd,
"safety_score": result.safety_score,
"confidence": result.confidence,
"risk_level": result.risk_level,
"risk_flags": result.risk_flags,
"green_flags": result.green_flags,
"modules_run": result.modules_run,
"scan_duration_ms": result.scan_duration_ms,
"tier": result.tier,
"scanned_at": result.scanned_at,
}
except Exception as e:
raise HTTPException(500, f"Scan failed: {str(e)[:200]}") from e
@router.post("/wallet/scan")
async def scan_wallet(request: Request, body: WalletScanRequest):
tier = _get_tier(request)
admin_key = _get_admin_key(request)
try:
scanner = get_wallet_scanner()
result = await scanner.scan(address=body.address, chain=body.chain, tier=tier, admin_key=admin_key)
return {
"status": "ok",
"address": result.address,
"chain": result.chain,
"labels": result.labels,
"entity_name": result.entity_name,
"entity_type": result.entity_type,
"persona": result.persona,
"persona_confidence": result.persona_confidence,
"total_value_usd": result.total_value_usd,
"token_count": result.token_count,
"scam_tokens_held": result.scam_tokens_held,
"scam_exposure_pct": result.scam_exposure_pct,
"risk_score": result.risk_score,
"risk_flags": result.risk_flags,
"rag_matches": len(result.rag_matches),
"behavior_patterns": result.behavior_patterns,
"smart_money_overlap": result.smart_money_overlap,
"risk_forecast": result.risk_forecast,
"modules_run": result.modules_run,
"scan_duration_ms": result.scan_duration_ms,
"tier": result.tier,
"scanned_at": result.scanned_at,
}
except Exception as e:
raise HTTPException(500, f"Scan failed: {str(e)[:200]}") from e