Client for the solver capability matrix -- the single source of truth for which chains, tokens, and pull methods the Xochi/Riddler stack can settle right now.
The Xochi worker proxies Riddler's GET /xochi/capabilities at
GET /api/capabilities, wrapping the solver's wire payload verbatim in
%{"source" => "live" | "fallback", "capabilities" => matrix}. This module
fetches that route (never riddler.axol.io directly -- the worker is the
sole agent surface), parses the matrix tolerantly, and exposes the corridor
predicates ACP offerings route through instead of the hardcoded
Raxol.Payments.Assets tables. New solver chains (Tron, Solana) then light
up for the agent with zero raxol redeploy.
Wire tolerance
- The current matrix emits chains as
chain_id+chain_nameonly;vm_typeandaddress_formatarrive with Riddler's WP-E. Absentvm_typedefaults to:evm. - Unknown keys are dropped; individually malformed chain/token entries are
skipped; a structurally unusable body parses to
:errorand callers fall back tofallback/0. - Both the worker-wrapped shape and a bare matrix are accepted.
Degrade policy
fallback/0 is derived from Raxol.Payments.Assets (the legacy hardcoded
mirror of Riddler's token registry), so an unreachable capabilities endpoint
degrades to exactly today's behavior -- never to rejecting jobs the solver
could fill yesterday.
Caching
get/1 is an ETS-backed read-through with a TTL (default 300s), following
the Raxol.Payments.Checkpoint.ETS lazy-table pattern. Pure fetch/1 /
parse/1 stay side-effect-free for tests and callers that manage their own
lifetime.
Summary
Functions
Chain ids the solver currently offers.
The pinned deposit-route attestation signer (lowercased 0x), or nil when
the matrix does not publish one (a deposit-route verify then fails closed).
Static fallback derived from Raxol.Payments.Assets -- the six EVM chains
and the solver-fillable token set, direction-blind (both roles), exactly
reproducing the pre-capabilities gate.
Fetch and parse the capability matrix from the Xochi worker.
True when (chain_id, token_address) is a solver-fillable corridor leg for
role. A token qualifies when the matrix registers that address on that
chain with the given role. Address comparison is case-insensitive for EVM
legs and case-sensitive otherwise (base58 is case-significant).
Cached capabilities: serve the ETS-cached matrix while fresh, refresh from
the worker when stale, and degrade to the previous cached value -- or
fallback/0 when nothing was ever fetched -- on any failure.
Parse a capability payload -- the worker's wrapped shape or a bare matrix.
Drop the cached matrix (tests / operator refresh).
Structural address validity for a chain, dispatched on the chain's VM
family: EVM -> 0x + 40 hex; TVM -> full Base58Check verification via
Raxol.Payments.Tron.Address.valid?/1; SVM -> base58, 32-44 chars.
VM family for a chain id; :evm when the chain is unknown.
Types
@type chain() :: %{ chain_id: pos_integer(), chain_name: String.t(), vm_type: vm_type() }
@type role() :: :origin | :destination
@type token() :: %{ symbol: String.t(), roles: [role()], addresses: %{optional(pos_integer()) => String.t()} }
@type vm_type() :: :evm | :tvm | :svm
Functions
@spec chain_ids(t()) :: [pos_integer()]
Chain ids the solver currently offers.
The pinned deposit-route attestation signer (lowercased 0x), or nil when
the matrix does not publish one (a deposit-route verify then fails closed).
@spec fallback() :: t()
Static fallback derived from Raxol.Payments.Assets -- the six EVM chains
and the solver-fillable token set, direction-blind (both roles), exactly
reproducing the pre-capabilities gate.
Fetch and parse the capability matrix from the Xochi worker.
config needs :base_url (e.g. %{base_url: "https://api.xochi.fi"});
optional :req_options merge into the request (e.g. plug: for
Req.Test). Auth is not required -- the route is public.
Returns {:ok, t()} or {:error, reason}; callers wanting the degrade
behavior use get/1 or fallback/0 instead of handling the error.
True when (chain_id, token_address) is a solver-fillable corridor leg for
role. A token qualifies when the matrix registers that address on that
chain with the given role. Address comparison is case-insensitive for EVM
legs and case-sensitive otherwise (base58 is case-significant).
Cached capabilities: serve the ETS-cached matrix while fresh, refresh from
the worker when stale, and degrade to the previous cached value -- or
fallback/0 when nothing was ever fetched -- on any failure.
config as in fetch/1; nil config skips the network entirely and
returns fallback/0, so callers without a configured worker keep the
static behavior. Options: :ttl_ms (default 300000).
Parse a capability payload -- the worker's wrapped shape or a bare matrix.
Returns {:ok, t()} or :error when the body is structurally unusable
(callers fall back). Individually malformed entries are dropped, not fatal.
@spec reset() :: :ok
Drop the cached matrix (tests / operator refresh).
@spec valid_address?(t(), pos_integer() | String.t() | nil, String.t() | nil) :: boolean()
Structural address validity for a chain, dispatched on the chain's VM
family: EVM -> 0x + 40 hex; TVM -> full Base58Check verification via
Raxol.Payments.Tron.Address.valid?/1; SVM -> base58, 32-44 chars.
@spec vm_type(t(), pos_integer() | String.t() | nil) :: vm_type()
VM family for a chain id; :evm when the chain is unknown.