Some checks failed
CI / build (push) Failing after 3s
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.
97 lines
3.4 KiB
Python
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
|