Dexter joins the facilitator mix — first x402 settlement via Uniswap Permit2

Published

TL;DR

Why a fourth facilitator

Each facilitator we light up adds two things:

  1. Buyer choice. Buyers with a wallet on a chain we don't already advertise can pay us natively without bridging or swapping. Dexter today only ships Base, but their /supported advertises Polygon / Arbitrum / Optimism / Avalanche / OP / Linea / Scroll / Mode / zkSync Era — a one-env-knob expansion when we choose.
  2. Resilience. Any single facilitator going down (rate-limit, incident, key-rotation) used to mean some buyers couldn't pay. With four facilitators advertising overlapping chain coverage, a buyer SDK that retries down the accepts[] array on facilitator failure will almost always find a working route on the buyer's home chain.

The seller-side mental model stays the same: each facilitator has a distinct payTo address that we control; the buyer's EIP-712 signature (whether Permit2 or EIP-3009) commits to that address; when the signed payload comes back, the (network, payTo) pair uniquely identifies which facilitator's /verify and /settle to hit.

Permit2 vs EIP-3009 in the offer

The shape that changes is the EVM offer's extra block. Before Dexter, every EVM offer looked like this (illustration is the Base-mainnet xpay offer for /api/v1/events):

{
  "scheme": "exact",
  "network": "eip155:8453",
  "amount": "5000",
  "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  "payTo": "0x…xpay…",
  "maxTimeoutSeconds": 60,
  "extra": { "name": "USD Coin", "version": "2" }
}

The Dexter offer for the same route is identical except for the new assetTransferMethod hint:

{
  "scheme": "exact",
  "network": "eip155:8453",
  "amount": "5000",
  "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  "payTo": "0x…dexter…",
  "maxTimeoutSeconds": 60,
  "extra": {
    "name": "USD Coin",
    "version": "2",
    "assetTransferMethod": "permit2"
  }
}

Pre-Permit2 buyer SDKs that don't read extra.assetTransferMethod will try to sign an EIP-3009 transferWithAuthorization for a Dexter offer and the signature won't validate at /verify — they'll fall through to a sibling offer (xpay/CDP/PayAI) that they CAN sign. Modern SDKs read the hint, build a Permit2 PermitSingle + SignatureTransferDetails instead, and submit through Dexter's flow.

The seller side is Optional[str] on the Facilitator descriptor — one field, defaults to None to keep EIP-3009 the default for the other three. From telegram-worker/x402_gate.py:

@dataclass(frozen=True)
class Facilitator:
    id: str
    label: str
    url: str
    pay_to: str
    networks: Tuple[str, ...]
    fee_micro_usdc: int
    # ...
    asset_transfer_method_evm: Optional[str] = None

And the Dexter registration:

dexter = Facilitator(
    id="dexter",
    label="Dexter",
    url="https://x402.dexter.cash",
    pay_to=X402_PAY_TO_EVM_DEXTER,
    networks=dexter_networks,      # Base by default; env-extensible
    fee_micro_usdc=0,              # gas-sponsored on Base today
    priority=3,
    requires_auth=False,
    asset_transfer_method_evm="permit2",
)

That's the entire diff against the previous three facilitators — one field, no special-case dispatch in the gate's hot path.

What buyers have to install

If you're building against Dexter offers, two things matter:

  1. x402 Python SDK 0.5.x or later for assetTransferMethod dispatch on the buyer side.
  2. The extensions extra so the SDK can validate the extensions.bazaar block we attach to every offer:

bash pip install 'x402[extensions]'

If you skip the extra, the SDK rejects Dexter offers with PaymentError: Extensions validation requires jsonschema. This bit us during integration testing — the failure mode looks like a Dexter-specific bug but is actually a generic "your SDK can't validate any offer with extensions" error. The other three facilitators' offers also carry extensions.bazaar (it's part of how their discovery rolls into x402scan / agentic.market catalogs), so the [extensions] install is a good idea regardless of which facilitator you settle through.

If you're a TypeScript / Go / Rust buyer: same deal. Check that your SDK reads extra.assetTransferMethod and has a Permit2 codepath. The x402 reference TypeScript SDK does. If yours doesn't, the Dexter offer will be invisible to you and you'll settle through one of the EIP-3009 facilitators — slightly less chain coverage on /supported but everything else works the same.

Why Permit2

Permit2 (the Uniswap-deployed canonical permit contract on every major EVM chain) gives a facilitator two things that EIP-3009 doesn't:

  1. Single-signature multi-token approvals. A buyer can sign one Permit2 message that authorises the facilitator to pull N different tokens up to a per-token budget, valid until validUntil. EIP-3009 is per-token, per-amount, per-nonce. For repeat-business with a single facilitator this is a real UX win — sign once, settle many times within budget.
  2. No token-side opt-in required. EIP-3009 only works for tokens that implement the EIP-3009 interface (USDC, EURC, some others). Permit2 works for any ERC-20 because Permit2 is a separate canonical contract the user pre-approves once. That matters less for x402 today (everyone settles in USDC, which DOES implement EIP-3009) but expands the design space — a future "pay in USDT" or "pay in DAI" offer is trivially advertisable through Dexter.

For a single-shot $0.001 micropayment to read one /api/v1/vessels row, neither of those wins materially over EIP-3009 — the buyer-side UX is identical (one signature, one HTTP retry). But the plumbing is now in place for repeat-business flows that amortise the signature across many calls.

Network expansion

Dexter's /supported on 2026-05-17 advertises:

We default to Base mainnet only on first deploy because that matched the existing buyer-side smoke-test surface (we already proved Base settlement works end-to-end across xpay / CDP / PayAI before adding Dexter). The other chains are one env knob away:

# Light up Polygon + Arbitrum + Optimism on Dexter
X402_FACILITATOR_NETWORKS_DEXTER="eip155:8453,eip155:137,eip155:42161,eip155:10"

Solana settlement on Dexter is on the same TODO as the rest of the facilitator-Solana rollout — both CDP and PayAI also list Solana on their /supported today, so when we work out the Solana-native signing flow (it's a different transaction structure entirely — not EIP-712, not Permit2), we'll light all three Solana-capable facilitators up at once.

Economics

The economics work the same as the rest of the multi-facilitator mix (see the prior post for the full breakdown):

Operational notes

What this means for buyers

If you already settle on Base via xpay / CDP / PayAI: nothing changes. Your existing SDK keeps picking the offer that matches your signing capability, and you get one extra accepts[] entry per request that your SDK can ignore if it doesn't speak Permit2.

If your SDK speaks Permit2 (modern x402 Python with [extensions], modern x402 TypeScript): the Dexter offer is slightly cheaper on Base (no facilitator fee) and you'll start hitting it preferentially when the buyer SDK picks the lowest-amount offer for your chain.

If you're integrating fresh: install x402[extensions] from day one. The 200 KB extra dependency (jsonschema) is the difference between "your SDK validates every offer the gate emits" and "your SDK silently drops every Dexter offer and a chunk of legacy CDP / PayAI offers carrying extensions.bazaar".