Private Paymaster Relay
Anon's paymaster relay uses Oblivious HTTP (OHTTP) to separate a wallet's network identity from its paymaster request. The relay receives the browser connection but cannot decrypt the request. The paymaster decrypts and processes the request but receives it from the relay instead of directly from the browser.
The privacy goal is specific: no single operator should be able to connect a user's IP address to the transaction request submitted to the paymaster. OHTTP does not hide information that the resulting transaction publishes on-chain.
Wallet Independent relay Paymaster
| | |
| HPKE-encrypted request | |
|-------------------------->| opaque request |
| |----------------------------->|
| | decrypt, validate,
| | sponsor, and submit
| |<-----------------------------|
| encrypted response | |
|<--------------------------| |
sees: request + own IP sees: client IP + ciphertext sees: request + relay IP
What a private request contains
The wallet prepares the paymaster operation locally, including its signed transaction data, zero-knowledge proof, fee quote, and selected fee token. It encodes the operation as an inner request and encrypts it to the paymaster's current HPKE public key.
The relay only receives the encrypted OHTTP envelope. It cannot read the transaction, proof, fee token, addresses, or encrypted response. The paymaster opens the envelope because it holds the HPKE private key. On private Railgun operations, the proof still protects the shielded transfer details according to the Railgun protocol; the relay adds transport unlinkability between the browser connection and the paymaster submission.
Request flow
- The wallet starts with a relay URL and an independently pinned Ed25519 paymaster signing key. Anon's production values are also published in the well-known discovery document.
- The wallet fetches
GET /ohttp-configsthrough the relay and verifies the returned HPKE KeyConfig against the pinned signing key. This prevents a relay from substituting a key it controls. - Public, identity-free reads such as gas quotes and supported fee tokens are fetched through the relay. They are allowlisted and may be cached according to the paymaster's
Cache-Controlresponse. - The wallet seals the private execute or status request with HPKE and sends the envelope to
POST /gatewayasmessage/ohttp-req. - The relay forwards the opaque envelope to its fixed paymaster target. It does not choose a target from user input and is not an open proxy.
- The paymaster decrypts the inner request, validates the proof, signed quote, fee, and transaction, then submits accepted work on-chain.
- The paymaster encrypts its response to the wallet. The relay passes back
message/ohttp-reswithout being able to read it.
What each party can observe
| Party | Can observe | Cannot observe by design |
|---|---|---|
| Wallet | Its request, keys, response, and network connection | Other users' activity |
| Relay | Client IP, ciphertext size, timing, and allowlisted public-read paths and queries | OHTTP request or response plaintext; paymaster private keys |
| Paymaster | Decrypted request, result, timing, and relay IP | Client IP, when the relay and ingress remove client-IP forwarding |
| Chain observer | Data and timing published by the resulting transaction | OHTTP plaintext while it is in transit |
Security guarantees
- Content confidentiality at the relay. OHTTP encrypts each private request and response using HPKE. The relay holds no decryption or signing key.
- Network-identity separation at the paymaster. The paymaster receives a connection from the relay, not the wallet, provided no client-IP header is forwarded.
- Key-substitution resistance. Clients verify rotating HPKE configurations with an Ed25519 key pinned outside the relay channel. Discovery is convenient, but it is not a replacement for a pinned trust anchor.
- Ciphertext integrity. Authenticated encryption causes modified ciphertext to fail validation. A relay can still drop, delay, or replay traffic, so the application must remain safe under retries.
- Constrained forwarding. The implementations use a fixed paymaster target, explicit public-read paths, a 1 MiB request limit in the Go service, and strict OHTTP media types. They are not general-purpose proxies.
- No browser credentials. Public relay responses use wildcard CORS and no cookies, authorization headers, or browser credentials.
Limits and assumptions
The relay is a split-trust privacy tool, not a full anonymity network.
- The relay and paymaster must be operated by different, non-colluding parties. If they combine their observations, they can reconnect client IPs with requests.
- A global observer may correlate request size and timing across the relay and paymaster. OHTTP does not provide mixnet-style traffic-analysis resistance.
- The relay operator can log client IPs and traffic metadata. Choose an operator whose independence and data-handling policy match your threat model.
- Direct calls to the paymaster reveal the caller's network address. Clients need to route configuration, public quotes, execute requests, and status requests through the relay.
- OHTTP does not conceal public blockchain metadata, transaction timing, address reuse, or values that the transaction itself reveals.
- Availability is not guaranteed. A relay can block, delay, rate-limit, or selectively refuse requests.
Use a public relay
Anon publishes a browser-compatible relay at https://relay.anon.inc. Its current URL and paymaster signing key are discoverable at https://anon.inc/.well-known/anon-paymaster.json.
You can use another public relay when it:
- targets the paymaster you intend to use;
- implements the same
/ohttp-configs,/gateway, gas-quote, and supported-token routes; - permits your client origin or provides compatible browser CORS;
- is operated independently from the paymaster; and
- has an acceptable availability, logging, and retention policy.
A public relay cannot be pointed at an arbitrary paymaster by the client. That fixed-target property is intentional: it prevents the service from becoming an open proxy. A relay operator must configure and deploy a compatible instance for each paymaster target.
Run your own relay
The complete Go, Docker, and Cloudflare Worker implementations are public at github.com/anondotinc/paymaster-relay. The repository contains tests, deployment configuration, health checks, and browser preflight verification.
Go and Docker
The Go service provides the strongest client-IP separation because it constructs fresh upstream requests and forwards no client headers. It can run in any container platform, virtual machine, or Kubernetes account:
git clone https://github.com/anondotinc/paymaster-relay.git
cd paymaster-relay
docker build -t anon-ohttp-relay .
docker run --rm -p 8080:8080 \
-e OHTTP_GATEWAY_URL="https://paymaster.example.com" \
anon-ohttp-relay
Terminate TLS in front of the container, expose only the relay routes, apply reasonable body and rate limits, and avoid request-body logging.
Cloudflare Worker
The Worker can be deployed from any Cloudflare account with a zone and custom domain you control. Fork the repository, then edit worker/wrangler.toml:
- choose a unique Worker
name; - replace the custom-domain
routes[].pattern; - set
TARGETto the intended paymaster's HTTPS OHTTP gateway.
Deploy and verify it from the repository root:
make cloudflare-login
make deploy RELAY_URL=https://relay.example.com
Cloudflare manages the custom-domain DNS record and certificate during deployment.
Cloudflare client-IP caveat: for Worker subrequests to a non-Cloudflare origin, Cloudflare documents that
CF-Connecting-IPcontains the client address and cannot be altered by the Worker. The paymaster ingress must remove visitor-IP headers before logging or application processing. If you cannot guarantee that, use the Go relay. See Cloudflare's HTTP header reference.
Operator checklist
- Operate independently from the paymaster organization.
- Point the relay only at the intended HTTPS paymaster gateway.
- Forward no browser cookies, authorization values, user agents, or client-IP headers.
- Disable request and response body logging; minimize metadata retention.
- Preserve the exact OHTTP request and response media types.
- Keep the public-read allowlist narrow and honor upstream cache lifetimes.
- Add rate limits that do not create stable per-user identifiers.
- Monitor
/healthand verify the/gatewaybrowser preflight after deployment. - Publish the relay URL, operator identity, logging policy, and supported paymaster target.