94 lines
3.5 KiB
Python
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.domain.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),
|
|
)
|