#!/usr/bin/env python3 """#10 - DataBus Public API Gateway. Free tier + x402 paid tier. 102 chains, 119 providers.""" import hashlib import logging import os import time from dataclasses import dataclass from typing import Any import httpx logger = logging.getLogger(__name__) DATABUS_BASE = os.environ.get("DATABUS_URL", "http://localhost:8000/api/v1/databus") X402_VERIFY_URL = os.environ.get("X402_VERIFY_URL", "http://localhost:8000/api/v1/x402/verify") RATE_LIMIT_FREE = int(os.environ.get("DATABUS_FREE_RATE", "100")) # req/hour RATE_LIMIT_PAID = int(os.environ.get("DATABUS_PAID_RATE", "5000")) # Simple in-memory rate limiter (Redis-backed in prod) _rate_store: dict[str, list[float]] = {} def _check_rate(key: str, limit: int, window: int = 3600) -> bool: now = time.time() bucket = _rate_store.setdefault(key, []) bucket[:] = [t for t in bucket if now - t < window] if len(bucket) >= limit: return False bucket.append(now) return True @dataclass class DatabusQueryResult: chain: str data: dict[str, Any] source: str cached: bool latency_ms: float async def databus_get(chain: str, endpoint: str, params: dict | None = None, tier: str = "free") -> DatabusQueryResult: """Single-chain DataBus query with tier-appropriate caching.""" t0 = time.monotonic() url = f"{DATABUS_BASE}/{chain}/{endpoint}" async with httpx.AsyncClient(timeout=15) as client: resp = await client.get(url, params=params or {}) resp.raise_for_status() data = resp.json() elapsed = (time.monotonic() - t0) * 1000 return DatabusQueryResult( chain=chain, data=data, source="databus", cached=data.get("cached", False), latency_ms=elapsed ) async def databus_cross_chain( query: str, chains: list[str] | None = None, tier: str = "free" ) -> dict[str, DatabusQueryResult]: """Query multiple DataBus chains in parallel.""" if chains is None: chains = ["solana", "ethereum", "bsc", "base", "arbitrum"] tasks = {c: databus_get(c, query, tier=tier) for c in chains} results = {} for c, task in tasks.items(): try: results[c] = await task except Exception as e: logger.warning(f"DataBus query failed for {c}: {e}") results[c] = DatabusQueryResult( chain=c, data={"error": str(e)}, source="databus", cached=False, latency_ms=0 ) return results async def verify_x402_payment(signature: str, payload: str, chain: str = "solana") -> bool: """Verify x402 micropayment signature.""" async with httpx.AsyncClient(timeout=10) as client: resp = await client.post(X402_VERIFY_URL, json={"sig": signature, "payload": payload, "chain": chain}) return resp.status_code == 200 and resp.json().get("valid", False) def generate_api_key() -> str: return "rmi_databus_" + hashlib.sha256(os.urandom(32)).hexdigest()[:32] # Chain availability SUPPORTED_CHAINS = [ "solana", "ethereum", "bsc", "base", "arbitrum", "polygon", "avalanche", "optimism", "fantom", "linea", "zksync", "scroll", "mantle", "near", "tron", "ton", "bitcoin", "cardano", "xrp", "sui", "aptos", "sei", ] TIER_LIMITS = { "free": {"requests_per_hour": 100, "chains": 5, "cache_ttl": 300}, "pro": {"requests_per_hour": 1000, "chains": 20, "cache_ttl": 60}, "elite": {"requests_per_hour": 5000, "chains": 102, "cache_ttl": 15}, }