rmi-backend/app/domain/x402/models.py

86 lines
2 KiB
Python

"""Pydantic v2 models for the x402 domain."""
from __future__ import annotations
from enum import StrEnum
from pydantic import BaseModel, ConfigDict, Field, field_validator
class X402Tier(StrEnum):
"""x402 payment tier — maps to scanner tiers."""
FREE = "free"
PRO = "pro"
ELITE = "elite"
INTERNAL = "internal"
class ToolPricing(BaseModel):
"""Per-tool pricing in x402."""
model_config = ConfigDict(str_strip_whitespace=True)
tool: str
price_usd: float = Field(default=0.0, ge=0)
price_crypto: dict[str, str] = Field(
default_factory=dict,
description="Crypto amounts: {'sol': '0.01', 'eth': '0.001', 'btc': '0.00001', 'trx': '5'}",
)
tier_required: X402Tier = X402Tier.FREE
class ToolCatalogEntry(BaseModel):
"""A single tool in the x402 catalog."""
name: str
description: str = ""
category: str = ""
tier_required: X402Tier = X402Tier.FREE
price_usd: float = 0.0
endpoint: str = ""
enabled: bool = True
class ToolCatalog(BaseModel):
"""Full x402 tool catalog."""
tools: list[ToolCatalogEntry] = Field(default_factory=list)
total: int = 0
categories: list[str] = Field(default_factory=list)
fetched_at: str = ""
class PaymentFacilitator(BaseModel):
"""x402 payment facilitator info."""
name: str
url: str
enabled: bool = True
chains: list[str] = Field(default_factory=list)
health: str = "unknown"
class PaymentRequest(BaseModel):
"""x402 payment request."""
model_config = ConfigDict(str_strip_whitespace=True)
tool: str
chain: str = Field(default="solana")
user_address: str | None = None
@field_validator("chain")
@classmethod
def _chain_lowercase(cls, v: str) -> str:
return v.lower().strip()
class PaymentReceipt(BaseModel):
"""x402 payment receipt."""
tool: str
chain: str
tx_hash: str | None = None
amount_paid: dict[str, str] = Field(default_factory=dict)
status: str = "pending" # pending | confirmed | failed
timestamp: str = ""