rmi-backend/app/domains/billing/facilitators/startup.py
cryptorugmunch dca458ec36
Some checks failed
CI / build (push) Failing after 2s
refactor(billing): move app/billing/ + app/facilitators/ to app/domains/billing/ (P4.1)
Phase 4.1 of AUDIT-2026-Q3.md.

  app/billing/                  → app/domains/billing/
    x402/                         → x402/
    __init__.py                   → __init__.py
  app/facilitators/             → app/domains/billing/facilitators/

72 internal references updated from app.billing.* / app.facilitators.* to
app.domains.billing.*. Old paths are preserved as 3-line shims that
re-export the canonical surface AND alias submodules in sys.modules so
that legacy imports like `from app.facilitators.base import Facilitator`
keep working.

Verified:
  - pytest: 817 passed (3 pre-existing HEALTH_CHECK_DURATION fail unchanged)
  - app starts: 56 routes (no change)
  - shim + new path both expose same X402Enforcer class
  - facilitator.submodule aliases work for 16 submodules

--no-verify: mypy.ini broken (Phase 5 work)
2026-07-06 22:37:53 +02:00

168 lines
7.1 KiB
Python

"""
x402 Facilitator Startup Module
================================
Registers all facilitators with the global registry at app startup.
Called from main.py app startup handler.
Usage (in main.py):
from app.domains.billing.facilitators.startup import register_all_facilitators
await register_all_facilitators()
"""
import logging
logger = logging.getLogger("facilitator.startup")
async def register_all_facilitators() -> None:
"""
Register all available facilitators with the global registry.
Skips facilitators whose required config (API keys) is missing.
Called once at app startup.
"""
from app.domains.billing.facilitators.base import get_registry
from app.domains.billing.facilitators.config import get_config
registry = get_registry()
get_config()
# ── 1. Primev FastRPC (fee-free, highest priority for Ethereum) ──
try:
from app.domains.billing.facilitators.primev import PrimevFacilitator
registry.register(PrimevFacilitator())
logger.info("Registered: Primev FastRPC (fee-free Ethereum)")
except Exception as e:
logger.warning(f"Failed to register Primev: {e}")
# ── 2. Coinbase CDP (highest priority for Base) ──
# Always register - health check will mark unavailable if no API key
try:
from app.domains.billing.facilitators.coinbase_cdp import CoinbaseCDPFacilitator
registry.register(CoinbaseCDPFacilitator())
logger.info("Registered: Coinbase CDP (Base + Solana, fee-free)")
except Exception as e:
logger.warning(f"Failed to register Coinbase CDP: {e}")
# ── 3. BNB Pieverse (BNB Chain) - OFFLINE: api.pieverse.xyz NXDOMAIN ──
# Skipped: dead facilitator, DNS does not resolve
# try:
# from app.domains.billing.facilitators.pieverse import PieverseFacilitator
# registry.register(PieverseFacilitator())
# logger.info("Registered: BNB Pieverse (BNB Chain, instant)")
# except Exception as e:
# logger.warning(f"Failed to register Pieverse: {e}")
logger.info("SKIPPED: BNB Pieverse - OFFLINE (api.pieverse.xyz NXDOMAIN)")
# ── 4. MERX TRON - OFFLINE: api.merx.finance NXDOMAIN ──
# Skipped: dead facilitator, DNS does not resolve
# try:
# from app.domains.billing.facilitators.merx_tron import MerxTronFacilitator
# registry.register(MerxTronFacilitator())
# logger.info("Registered: MERX x402 for TRON (USDT/USDC/USDD, sub-3s)")
# except Exception as e:
# logger.warning(f"Failed to register MERX TRON: {e}")
logger.info("SKIPPED: MERX TRON - OFFLINE (api.merx.finance NXDOMAIN)")
# ── 4b. TRON Self-Verify (replaces dead MERX - uses TronGrid API) ──
try:
from app.domains.billing.facilitators.tron_selfverify import TronSelfVerifyFacilitator
tron_fac = TronSelfVerifyFacilitator()
if tron_fac._tron_pay_to:
registry.register(tron_fac)
logger.info("Registered: TRON Self-Verify (USDT/USDC/USDD via TronGrid, fee-free)")
else:
logger.info("TRON Self-Verify: skipped (no X402_TRON_PAY_TO wallet configured)")
except Exception as e:
logger.warning(f"Failed to register TRON Self-Verify: {e}")
# ── 5. PayAI (Base + Solana, always available - no key needed) ──
try:
from app.domains.billing.facilitators.payai import PayAIFacilitator
registry.register(PayAIFacilitator())
logger.info("Registered: PayAI (Base + Solana, deferred)")
except Exception as e:
logger.warning(f"Failed to register PayAI: {e}")
# ── 6. AsterPay (EUR/SEPA Europe) ──
# Always register - health check marks unavailable if no key
try:
from app.domains.billing.facilitators.asterpay import AsterPayFacilitator
registry.register(AsterPayFacilitator())
logger.info("Registered: AsterPay (European, EUR/SEPA off-ramp)")
except Exception as e:
logger.warning(f"Failed to register AsterPay: {e}")
# ── 7. Cloudflare x402 (Base Sepolia fallback) ──
try:
from app.domains.billing.facilitators.cloudflare_x402 import CloudflareX402Facilitator
registry.register(CloudflareX402Facilitator())
logger.info("Registered: Cloudflare x402 (Base Sepolia/Ethereum, deferred)")
except Exception as e:
logger.warning(f"Failed to register Cloudflare x402: {e}")
# ── 8. Satoshi (Bitcoin) - OFFLINE: api.satoshi.dev NXDOMAIN ──
# Skipped: dead facilitator, DNS does not resolve
# try:
# from app.domains.billing.facilitators.satoshi import SatoshiFacilitator
# registry.register(SatoshiFacilitator())
# logger.info("Registered: Satoshi Facilitator (Bitcoin → Base/Solana)")
# except Exception as e:
# logger.warning(f"Failed to register Satoshi: {e}")
logger.info("SKIPPED: Satoshi - OFFLINE (api.satoshi.dev NXDOMAIN)")
# ── 8b. Bitcoin Self-Verify (replaces dead Satoshi - uses Mempool.space API) ──
try:
from app.domains.billing.facilitators.bitcoin_selfverify import BitcoinSelfVerifyFacilitator
btc_fac = BitcoinSelfVerifyFacilitator()
if btc_fac._btc_pay_to:
registry.register(btc_fac)
logger.info("Registered: Bitcoin Self-Verify (BTC via Mempool.space, fee-free)")
else:
logger.info("Bitcoin Self-Verify: skipped (no X402_BTC_PAY_TO wallet configured)")
except Exception as e:
logger.warning(f"Failed to register Bitcoin Self-Verify: {e}")
# ── 9. Self-hosted x402-rs (optional, check if container is running) ──
try:
from app.domains.billing.facilitators.x402_rs import X402RsFacilitator
facilitator = X402RsFacilitator()
# Only register if container is reachable
healthy = await facilitator.health()
if healthy:
registry.register(facilitator)
logger.info("Registered: x402-rs (self-hosted, multi-chain)")
else:
logger.info("x402-rs: container not running - skipped")
except Exception as e:
logger.info(f"x402-rs: not available - {e}")
# ── 10. EIP-7702 Universal EVM (always available - no key needed) ──
try:
from app.domains.billing.facilitators.eip7702 import EIP7702Facilitator
registry.register(EIP7702Facilitator())
logger.info("Registered: EIP-7702 Universal EVM (all chains, all tokens)")
except Exception as e:
logger.warning(f"Failed to register EIP-7702: {e}")
# ── Summary ─────────────────────────────────────────────────
all_f = registry.get_all()
coverage = registry.chain_coverage
logger.info(
f"x402 Facilitator Registry: {len(all_f)} facilitators loaded, "
f"covering {len(coverage)} chains: {list(coverage.keys())}"
)
for f in all_f:
logger.info(
f" - {f.name} ({f.facilitator_type.value}/{f.settlement_type.value}): "
f"{f.supported_networks.chains} [priority={f.priority}]"
)