← Blog
August 9, 2026 · 13 min

Self-Hosting the x402 Settlement Plane: an x402-rs Audit

Every x402 payment ends at a facilitator: the server that verifies a signed authorization and executes it on-chain. Our deep dive on the facilitator API closed with a one-line escape hatch — you can self-host with x402-rs. This is the follow-up: we cloned the repo at HEAD, read the config parser, and probed the maintainer's live instance.

The question behind this audit is not academic. A gateway that routes model calls and settles them in stablecoins depends on a facilitator for every x402 walk-up payment. If that facilitator is a hosted third party, you inherit its fee schedule, its uptime, its censorship surface, and its view of your transaction metadata. Self-hosting removes all four — and replaces them with signer custody, RPC reliability, and a gas float you now have to manage. x402-rs is the most complete open-source answer to that trade, so we treated it the way we treated the fifteen network bindings: clone, read, verify, and report what is actually there rather than what the README promises.

The role you are taking over

A quick recap of the contract, because everything below hangs off it. In x402 v2, the seller's middleware calls POST /verify before doing work (a pre-flight that costs no gas) and POST /settle after (the on-chain execution). GET /supported advertises which scheme and network combinations the facilitator can execute, and — critically for Solana-style bindings — which signer addresses it will use, so sellers can pin the fee payer. The facilitator is non-custodial by construction: it only ever executes transfer authorizations that the buyer signed, with destination and amount fixed by the signature. What it can do is refuse, delay, or observe. Those are the three properties self-hosting buys back.

It also inherits a fourth job that is easy to miss: on EVM chains the facilitator is the transaction sender for EIP-3009's transferWithAuthorization, which means it pays gas on every settlement. A self-hosted facilitator is not free infrastructure. It is a hot wallet with an operational budget.

The economics of the trade are concrete. When we surveyed the hosted market in July, Coinbase's CDP facilitator priced at 1,000 transactions per month free and $0.001 per transaction after that, with a directory of a dozen alternatives at similar or unpublished rates. At agent-scale call volumes — millions of sub-cent settlements — a fixed per-transaction fee is a second gas bill that grows linearly with your success. Self-hosting converts it into a flat operational cost: the gas itself, the RPC subscription, and the engineering time this audit is trying to price.

What the repo actually ships

x402-rs lives at x402-rs/x402-rs on GitHub, Apache-2.0, with the tagline "a comprehensive Rust toolkit for the x402 protocol." At our clone date (2026-08-09, HEAD e75adda, last commit 2026-07-13) the repo showed 284 stars, 166 forks and 21 open issues. It is, in practice, a one-person project: of the 51 most recent commits, 50 are by Sergey Ukustov, the author listed in the workspace manifest. That is worth stating plainly before any dependency decision — this is high-quality solo work, not a foundation-backed team.

The workspace is at version 2.0.2 (Rust 1.93, edition 2024) and splits cleanly into four layers. x402-types holds the protocol types, the facilitator traits, and the v1 network-name registry. x402-axum and x402-reqwest are the seller and buyer middleware — the Rust equivalents of the seller and buyer stacks we audited in the TypeScript SDK. x402-facilitator-local implements the verify/settle/supported logic as a library. And a facilitator crate wraps it all into a runnable Axum server binary, distributed via cargo install --git or the Docker image ghcr.io/x402-rs/x402-facilitator — the binary itself is not on crates.io. The chain layer is four crates: x402-chain-eip155, x402-chain-solana, x402-chain-tron, and x402-chain-aptos — the last one git-only because it drags in Aptos core libraries that require two [patch] entries in your manifest to even compile.

Adoption is measurable and recent: x402-types was first published to crates.io on 2026-02-01 and sits at 31,716 total downloads (17,877 recent) as of this writing. Version 2.0.0 landed on 2026-06-16 with breaking changes, 2.0.1 on 2026-06-19, and 2.0.2 on 2026-07-12, followed the next day by the TRON crate at 0.2.2. The cadence through June and July was roughly a commit-cluster per week.

The configuration model

The facilitator is driven by a single JSON file, keyed by CAIP-2 chain identifiers — the same convention the v2 spec uses on the wire. A minimal working config for Base plus Solana looks like this:

{
  "port": 8080,
  "host": "0.0.0.0",
  "chains": {
    "eip155:8453": {
      "eip1559": true,
      "signers": ["$FACILITATOR_PRIVATE_KEY"],
      "rpc": [{ "http": "https://mainnet.base.org", "rate_limit": 100 }]
    },
    "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp": {
      "signers": ["$SOLANA_PRIVATE_KEY"],
      "rpc": [{ "http": "https://api.mainnet-beta.solana.com" }]
    }
  },
  "schemes": [
    { "id": "v2-eip155-exact", "chains": "eip155:*" },
    { "id": "v2-solana-exact", "chains": "solana:*" }
  ]
}

Three details make this better than it looks. First, any string value can be an environment-variable reference ("$FACILITATOR_PRIVATE_KEY") resolved at load time via a LiteralOrEnv wrapper type, so keys stay out of the file. Second, signers is an array — the facilitator supports a pool of signing keys per chain, and the changelog for 1.5.4 documents random selection of the facilitator address in the upto flow, which spreads nonce pressure across keys. Third, rpc is also an array, with per-endpoint rate_limit, giving you multi-provider failover in config rather than in code. Scheme entries take chain patterns: an exact CAIP-2 id, a wildcard like eip155:*, or a set like eip155:{1,8453}. Per-chain defaults are sensible — eip1559 on, flashblocks off, a 30-second receipt timeout.

The HTTP surface is exactly the spec's three endpoints plus operational trim: GET/POST on /verify and /settle (the GET variants return schema information), GET /supported, a root greeting, and GET /health — which simply delegates to /supported, so a healthy response means the scheme registry actually built. CORS is wide open (Any origin), shutdown is graceful on SIGTERM/SIGINT, and OpenTelemetry tracing and metrics ship behind a telemetry feature flag configured with the standard OTEL_* variables.

Scheme coverage: what is implemented, and what is not

The facilitator registers seven scheme implementations: v1-eip155-exact, v2-eip155-exact, v2-eip155-upto, v1-solana-exact, v2-solana-exact, v2-aptos-exact, and v2-tron-exact. Two things stand out against the TypeScript reference implementation.

The first is that uptothe metered-billing scheme built on Permit2 — is implemented on the facilitator side, not just the client side. Version 2.0.0 shipped the full Rust client (V2Eip155UptoClient) and the settlement path against the x402UptoPermit2Proxy contract, including enforcement of facilitator authorization in the Permit2 witness. On top of it sits an extension we have not seen elsewhere: eip2612GasSponsoring, which lets a client ask the facilitator to sponsor the one-time Permit2 approval via an EIP-2612 permit — with an allowance check first, so no redundant permits are created. That closes the coldest cold-start problem in the upto flow: a fresh wallet can go from zero to metered payments without ever holding gas.

The second is what is absent: there is no batch-settlement or deferred scheme. The README's roadmap still lists "Deferred Scheme" as planned. If your architecture needs Cloudflare-style commit-accumulate-redeem credit rails, x402-rs does not provide them today — it is a capital-backed, settle-per-call plane. Relatedly, the v1 schemes still resolve human network names ("base-sepolia", "polygon-amoy") through a registry of about sixteen known EVM networks in x402-types, while the v2 schemes take any CAIP-2 identifier with no registry at all — a clean illustration of why v2's addressing was worth the break.

TRON is the quiet headline

The newest chain crate is the most strategically interesting. x402-chain-tron (merged as PR #98, "Facilitation on TRON," current version 0.2.2) brings x402 settlement to the chain that carries the largest USDT float — and it does so with almost no new cryptography. TRON's TIP-712 is byte-identical to EIP-712, so the authorization struct is the same as on EVM; the crate supports both EIP-3009-style transferWithAuthorization and Permit2 transfers through SUN.io's Permit2 deployment, with a dedicated X402ExactPermit2Proxy contract on mainnet and the Nile testnet. The differences are all operational: addresses travel as Base58Check on the wire but EVM hex inside the typed data, settlement goes through TronGrid's REST API rather than JSON-RPC, and TRON has no contract wallets — secp256k1 ecrecover only, so smart-account buyers are out.

Recall from the network bindings audit that the TypeScript SDK ships a tvm mechanism package but the spec repo's per-network documents don't make TRON a headline. In Rust it is now a first-class facilitator target with USDT — not USDC — as the documented token. For machine-to-machine payments, that matters: an agent economy that settles where the stablecoin liquidity actually is looks different from one confined to USDC-on-Base.

Probing the live instance

The project runs a free public testnet facilitator at facilitator.x402.rs. We queried GET /supported on 2026-08-09. The response advertised 31 payment kinds across 19 distinct networks: 26 v2 entries (14 exact, 12 upto) and 5 v1 entries still addressed by network name. The v2 EVM coverage spans Base Sepolia, Ethereum Sepolia, Arbitrum Sepolia, Polygon Amoy, BSC testnet and Monad testnet among others, plus Solana devnet under its CAIP-2 genesis hash and TRON Nile under tron:0xcd8690dc. Nearly every EVM exact entry advertises the eip2612GasSponsoring extension.

The signers map — the field we flagged in the facilitator API deep dive as the seller's defense for pinning fee payers — showed an asymmetry worth noting: the Solana devnet fee payer and the TRON Nile signer are disclosed (they must be, since buyers embed them in transactions), while all twelve EVM chains return empty signer arrays. Nothing in the spec requires disclosure on EVM, where the facilitator is just the transaction sender. But it means a seller cannot pre-authorize specific EVM facilitator addresses from /supported alone — a small, real gap between what the endpoint can express and what this deployment shares.

What the audit found

We read the config parser before trying the documented examples, which turned out to be the right order. Three findings, all verified against HEAD e75adda:

Finding 1 — the shipped example config is invalid JSON. facilitator/config.json.example fails to parse (jq: "Expected separator between values at line 7") because two _comment entries are missing trailing commas. Anyone who starts from the example file gets a parse error on first boot.

Finding 2 — the facilitator README documents a config key the parser rejects. Its example uses {"scheme": "v2-eip155-exact", ...}, but the SchemeConfig struct in x402-types requires the field to be named id, with no serde alias. The same wrong key appears in the doc comment of x402-types/src/config.rs itself. Deserialization fails with a missing-field error.

Finding 3 — a third, phantom config format. The doc comment in facilitator/src/config.rs shows chains configured with flat rpc_url and signer_private_key keys. The actual Eip155ChainConfigInner struct requires signers (an array) and rpc (an array of objects). That format never parses either. In total the repo documents three different config shapes, and only one of them — the shape in the example file, minus its syntax errors — is real.

Add a softer fourth: the README roadmap still lists the "Upto Scheme" and "Gasless Approval Flow" as planned, even though both shipped in 2.0.0 and both are live on the public instance. None of this is a correctness problem in the settlement path — the code we read is careful, the traits are clean, and a TypeScript-vs-Rust protocol-conformance harness in the repo spins up real facilitator, seller and buyer binaries to test cross-implementation interop. It is documentation debt of exactly the kind solo projects accumulate, and it lands on the worst possible page: the first thirty minutes of a new operator's deployment.

Built to be extended, not just deployed

The part of the repo that best predicts its longevity is the documentation aimed at people who want to change it. Two guides in docs/ — "Build Your Own Facilitator" and "How to Write a Scheme for x402-rs" — describe the extension surface in detail, and the code matches them. A new payment scheme is four traits: X402SchemeId names it, X402SchemeFacilitatorBuilder constructs it from a chain provider, X402SchemeBlueprint registers it, and X402SchemeFacilitator implements the async verify and settle pair. The facilitator binary itself is a thin composition: build a ChainRegistry from config, register blueprints into a SchemeRegistry, wrap it in FacilitatorLocal, and mount the stock Axum routes. That is the whole server.

For a gateway operator this is the difference between a product and a platform. Custom pre- and post-settlement hooks — access control, billing export, anomaly detection on settlement patterns — slot in at the FacilitatorLocal boundary without forking the protocol logic. And if a scheme we need is missing (batch settlement being the obvious candidate), the guide's step-by-step is a realistic path to implementing it against upstream traits rather than in a private fork.

Operating it, and the managed escape hatch

Deployment is genuinely simple once past the config: one Docker container, one mounted JSON file, port 8080, feature flags to compile only the chains you need, OTLP export if you want traces. The pieces you must bring are the ones no binary can solve — funded signer keys per chain and their custody story, RPC endpoints you trust (with the built-in failover as mitigation, not absolution), and monitoring on the gas balance that silently determines whether /settle keeps working. For teams that want the codebase without the pager, the maintainer also operates FareSide, a hosted facilitator built on x402-rs whose pitch is the honest version of the trade: no lock-in, because switching facilitators is changing one URL.

What it means for LLM4Agents

LLM4Agents settles x402 walk-up calls through facilitator infrastructure today, which makes this repo a direct strategic input. Three consequences. First, self-hosting the settlement plane is now a realistic, bounded project: a single audited binary covers exact and upto on every EVM chain we care about, plus Solana — meaning our per-call billing path could run with no third-party facilitator in the loop, no per-transaction fee, and no external party observing our settlement metadata. Second, the TRON crate opens a rail we do not currently price: USDT settlement where the deepest stablecoin liquidity lives, with the same EIP-712 signing stack we already run. Third, the risk profile is legible: a solo-maintained dependency argues for pinning versions, running the repo's own conformance harness in our CI, and treating our deployment config as tested code — precisely because the project's documentation is its weakest layer.

Staying on the frontier

Concrete steps, in order. Stand up x402-rs against Base Sepolia and Solana devnet and point a staging gateway's walk-up path at it, using the conformance harness as the acceptance gate. Wire our boot-time /supported sync against the self-hosted instance and alert on drift, the same way the TypeScript seller middleware does. Upstream fixes for the three config findings — small patches, and the cheapest credibility available in an ecosystem this young. Prototype a TRON exact price tag on one internal endpoint to learn the TronGrid operational surface before USDT demand arrives. And keep the gap list honest: if our roadmap ever needs credit-backed batch settlement at the edge, x402-rs does not provide it, and we should know that before an architecture assumes otherwise.

Settlement you can run yourself

LLM4Agents meters model calls per use and settles in stablecoins over x402 — on infrastructure we audit before we trust.

Register your agent