Skip to main content
You want to run infrastructure that earns fees. A relayer fronts gas for a consumer’s already-signed order, transmits one transaction as msg.sender, and earns feeBps of the amount. By the end you will have a relayer serving POST /broker and GET /info with nothing but a gas key. There is no allowlist and no approval: relaying is permissionless because it is incentivized.

Run one in one command

The same binary the hosted service runs, with zero privileged config:
RELAYER_PK=0x<a-testnet-gas-key> RELAYER_CHAIN_ID=421614 RELAYER_PORT=8787 pnpm --filter @caplane/relayer start
# serves POST /broker + GET /info on http://localhost:8787
The relayer’s gas address prints on boot. Its key never does. A consumer points at your URL (or any other), shops relayers by reading each one’s GET /info, and submits. You can stand up a competing relayer in under a minute.

Why you cannot cheat the consumer, and why that is the point

The consumer signs the EIP-3009 authorization over nonce = keccak256(abi.encode(order)). If you change any order field (adapter, params, amount, payee, feeBps), the recomputed orderHash no longer equals the signed nonce, USDC rejects it, and the whole transaction reverts. You can only relay the order verbatim or reject it. This is cryptographic least-privilege, not a policy anyone maintains. See the binding. Your only economic lever is your local feeFloorBps: you may decline an order below your floor, but you cannot raise the fee, because that would change the orderHash and break the consumer’s signature. GET /info publishes that floor, your supported chain ids, and your gas address, so a consumer can shop on it.

The POST /broker pipeline

Every request runs the same pipeline. Each failure maps to a typed code, and error bodies carry only { ok: false, code, message }, never the order, the signature, or any key.
  1. Validate the body. A malformed order is rejected MALFORMED_ORDER (400).
  2. Recompute orderHash from the order itself. Never trust a client-supplied hash; a mismatch is ORDERHASH_MISMATCH (400).
  3. Enforce your local feeBps floor. Below it is FEE_BELOW_FLOOR (402).
  4. Check the signed auth window. Expired is AUTH_EXPIRED (422).
  5. Pre-simulate with eth_call. A would-revert order (sold out, tampered, feeBps over 10000) is WOULD_REVERT (422), rejected without spending gas.
  6. Broadcast from your gas key, wait for the receipt, and decode Brokered.
  7. Return a RelaySuccess: { txHash, orderHash, brokered, receipt, feeCollected }.
The access log prints method path -> status [code] and nothing else. The full request and response shapes are in the API reference; the codes are in the errors reference.

The economics, honestly

  • Revenue: feeBps of every order you successfully relay. Whoever transmits first earns the fee. It is an open market, not a yield.
  • Cost: gas. A reverted broadcast costs you gas for nothing, which is why the pipeline pre-simulates every order and rejects the doomed ones before broadcasting. Set feeFloorBps so the fee covers gas plus margin on your chain.
  • Graceful degradation: when the relayer key’s native balance drops below RELAYER_GAS_FLOOR_WEI, POST /broker pauses with 503 INSUFFICIENT_RELAYER_GAS, so abuse degrades to “out of gas, try another relayer or run your own” instead of broadcasting doomed transactions.

The hardened public edge (opt-in)

A bare relayer is right for local and in-process use. A public deployment opts into the hardened edge by setting RELAYER_HARDENED=1 (or any RELAYER_RATE_* / RELAYER_GAS_FLOOR_WEI / RELAYER_CORS_ORIGINS var). The edge wraps the unmodified settlement pipeline with:
  • a per-IP rate limit (token bucket), returning 429 with Retry-After;
  • a global concurrency cap, returning 429 SERVER_BUSY rather than an unbounded queue;
  • the relayer-gas circuit breaker described above;
  • CORS, where GET /info is readable from any origin and POST /broker is callable from the configured origins and from server-side agents.
The edge rejections (RATE_LIMITED, SERVER_BUSY) use a separate edge error code union, so the audited settlement RelayErrorCode taxonomy stays clean. The low-gas pause reuses the settlement INSUFFICIENT_RELAYER_GAS code, so a consumer’s error handling stays uniform. Public hosting (TLS, a URL) is an ops task, not part of the package.
No allowlist, no operator approval, no Caplane in the loop. One command, your own gas key, and you are a relayer earning the fee.

Verify

GET /info returns your policy. Have a consumer submit an order with feeBps at or above your floor (see the agent-builder lane). It settles through you, the Brokered event records your gas address as the relayer, and feeCollected is paid to that address in the same transaction.