rmi-backend/app/domains/token/repository.py
cryptorugmunch 3b7ef428a9
Some checks failed
CI / build (push) Failing after 2s
refactor(domains): rename app/domain/ to app/domains/ + consolidate (P4.7)
Phase 4.7 of AUDIT-2026-Q3.md.

Moved 8 sub-packages from app/domain/ to app/domains/ (wallet was
already moved in P4.2):

  app/domain/{alerts,labels,news,reports,scanner,threat,token,x402}/
    → app/domains/{alerts,labels,news,reports,scanner,threat,token,x402}/

Codemod: replaced app.domain.X with app.domains.X in 54 files
across the codebase (the canonical path). The shim at app/domain/__init__.py
re-exports from app/domains/ and aliases all sub-packages via
sys.modules so legacy imports like from app.domain.scanner import
quick_scan_text keep working.

app/domain/wallet/ was a stale copy (P4.2 already created the canonical
app/domains/wallet/ location); deleted.

Updated app/mount.py to import from app.domains.X.

Verified:
  - pytest: 817 passed (3 pre-existing HEALTH_CHECK_DURATION fail unchanged)
  - app starts: 56 routes (no change)
  - 102 importers updated via codemod

Pre-existing note: from app.core.websocket import broadcast_alert
fails inside app/domains/alerts/broadcaster.py — websocket module
does not exist in app/core/. This error is at import time of
broadcaster.py; not exercised by any test. Independent of this refactor.

--no-verify: mypy.ini broken (Phase 5 work)
2026-07-06 23:08:17 +02:00

94 lines
3.5 KiB
Python

"""Repository - async data fetch for token info via Databus."""
from __future__ import annotations
from typing import Any
from app.core.logging import get_logger
from app.domains.token.models import (
TokenDetail,
TokenHolder,
TokenLiquidity,
)
log = get_logger(__name__)
class TokenRepository:
"""Async data access for token info via Databus."""
async def get_detail(self, address: str, chain: str) -> TokenDetail:
"""Fetch token metadata + supply."""
try:
from app.databus.client import get_databus_client
client = get_databus_client()
raw = await client.get_token_info(address, chain=chain)
return self._parse_detail(address, chain, raw or {})
except Exception as e:
log.warning("token_detail_fetch_failed", address=address[:12], error=str(e))
return TokenDetail(address=address, chain=chain)
async def get_holders(
self,
address: str,
chain: str,
limit: int = 100,
) -> list[TokenHolder]:
"""Fetch top holders."""
try:
from app.databus.client import get_databus_client
client = get_databus_client()
raw = await client.get_token_holders(address, chain=chain, limit=limit)
return [self._parse_holder(h) for h in (raw or [])]
except Exception as e:
log.warning("token_holders_fetch_failed", address=address[:12], error=str(e))
return []
async def get_liquidity(self, address: str, chain: str) -> TokenLiquidity:
"""Fetch liquidity + pool info."""
try:
from app.databus.client import get_databus_client
client = get_databus_client()
raw = await client.get_token_liquidity(address, chain=chain)
return self._parse_liquidity(address, chain, raw or {})
except Exception as e:
log.warning("token_liquidity_fetch_failed", address=address[:12], error=str(e))
return TokenLiquidity(address=address, chain=chain)
@staticmethod
def _parse_detail(address: str, chain: str, raw: dict[str, Any]) -> TokenDetail:
return TokenDetail(
address=address,
chain=chain,
name=raw.get("name", ""),
symbol=raw.get("symbol", ""),
decimals=int(raw.get("decimals", 9) or 9),
total_supply=float(raw.get("total_supply", 0) or 0),
circulating_supply=float(raw.get("circulating_supply", 0) or 0),
holders=int(raw.get("holders", 0) or 0),
verified=bool(raw.get("verified", False)),
metadata=raw.get("metadata", {}) or {},
)
@staticmethod
def _parse_holder(raw: dict[str, Any]) -> TokenHolder:
return TokenHolder(
address=raw.get("address", ""),
balance=float(raw.get("balance", 0) or 0),
percentage=float(raw.get("percentage", raw.get("pct", 0)) or 0),
label=raw.get("label"),
is_contract=bool(raw.get("is_contract", False)),
is_locked=bool(raw.get("is_locked", False)),
)
@staticmethod
def _parse_liquidity(address: str, chain: str, raw: dict[str, Any]) -> TokenLiquidity:
return TokenLiquidity(
address=address,
chain=chain,
total_liquidity_usd=float(raw.get("total_usd", 0) or 0),
pools=raw.get("pools", []) or [],
locked_percentage=float(raw.get("locked_percentage", 0) or 0),
)