A drop-in x402 facilitator for Base.
One URL swap. WAVE recovers and binds the payer from an EIP-3009 signature, then settles USDC on Base. Your server never holds a private key or talks to an RPC node.
One-line swap
Point paymentMiddleware() at WAVE's facilitator URL. It recovers the payer from the signed authorization and broadcasts the on-chain pull from the WAVE relayer. No private key and no RPC node on your server.
EIP-3009 exact scheme
The payer signs a TransferWithAuthorization (amount, recipient, validity window, nonce) as EIP-712 typed data. The credential is cryptographically bound to the payer's wallet; no bearer secret ever leaves the client.
No gas to verify
Verification is pure EIP-712 signature recovery: no gas, no RPC round-trip, no chain dependency. It returns isValid + the recovered payer. Settlement broadcasts the signed pull on Base.
Single-use enforced on-chain
USDC itself rejects a re-used (payer, nonce) authorization per EIP-3009. The same signature can never settle twice, and that guarantee does not depend on WAVE. A Durable-Object store adds an advisory gas-dedupe layer on top.
Base USDC, mainnet + testnet
USDC on Base mainnet for production; USDC on Base Sepolia for development. Contract addresses are listed below. Verify them against your own records before you integrate.
WAVE extension fields
Responses add an optional wave.rail field (e.g. base-usdc) for observability. Further wave.* fields are reserved for compliance and MPP-receipt metadata as those ship. Coinbase-compatible consumers ignore them.
CF SDK: point your x402 server at WAVE (x402-hono / agents/x402)
import { paymentMiddleware } from "x402-hono"; // or agents/x402
app.use(paymentMiddleware(payTo, routes, {
facilitator: { url: "https://gateway.wave.online/v1/x402/facilitator" }, // ← the only change
}));Raw HTTP: no SDK required, sign with any EIP-712 signer
let res = await fetch(resourceUrl);
if (res.status === 402) {
const { accepts } = await res.json(); // the exact-scheme requirement
const requirement = accepts[0];
// Sign the EIP-3009 TransferWithAuthorization with any EIP-712 signer (viem, ethers).
const authorization = await signer.signTypedData(
buildExactAuthorization(requirement, { validBefore: Math.floor(Date.now() / 1000) + 600 })
);
const header = Buffer.from(
JSON.stringify({ x402Version: 1, scheme: "exact", network: requirement.network, payload: authorization })
).toString("base64");
res = await fetch(resourceUrl, { headers: { "X-PAYMENT": header } }); // WAVE verifies, settles, serves
}Endpoints
| Path | Behavior |
|---|---|
| POST /v1/x402/facilitator/verify | Pure EIP-712 signature recovery: no gas, no RPC. Returns isValid + the recovered payer. |
| POST /v1/x402/facilitator/settle | Broadcasts the signed EIP-3009 pull from the WAVE relayer on Base mainnet. Live. |
| GET /.well-known/x402 | Discovery manifest: facilitator URL, scheme, networks, assets. |
| GET /v1/x402/facilitator/supported | CAIP-2 supported networks + schemes, for facilitator-registry discovery. |
| POST /v1/mpp/facilitator/verify | MPP protocol alias: same handler. |
| POST /v1/mpp/facilitator/settle | MPP protocol alias: same handler. |
Supported networks & assets
| Network | Chain | Asset | Contract address |
|---|---|---|---|
| Base mainnet | eip155:8453 | USDC | 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 |
| Base Sepolia | eip155:84532 | USDC | 0x036CbD53842c5426634e7929541eC2318f3dCF7e |
The gateway publishes a /.well-known/x402 discovery manifest and a CAIP-2 /supported endpoint, and a _x402 DNS TXT record points wave.online and gateway.wave.online at the manifest, so facilitator registries and clients can find WAVE automatically. You can also integrate directly by setting the facilitator URL above.
Start with one URL.
Swap the facilitator URL in your x402-hono or agents/x402 config, or sign payer authorizations over raw HTTP with any EIP-712 signer. The developer portal has the full integration path.