BUILD
Run the services
Two small stateless services back the product. Run your own, or point your app at a shared deployment.
What they do
- Relayer pays user fees so a fresh address never originates one. It is constrained to only ever pay gas: it refuses any transaction it is not the fee payer of, that touches an unlisted program, that references the relayer inside a System instruction, or whose simulated cost exceeds a cap, plus a balance floor and rate limits.
- Indexer serves public data only: announcements and pool leaves. Clients rebuild their own Merkle paths, so it never learns which payment or leaf is yours.
Host both
# fund a fresh keypair for the relayer, saved OUTSIDE the repo
export RELAYER_WALLET_FILE=/secure/relayer-wallet.json
export RPC_URL=https://your-rpc
docker compose -f ops/docker-compose.yml up --build -dThen point your app at them:
NEXT_PUBLIC_RELAYER_URL=https://relayer.yourdomain
NEXT_PUBLIC_INDEXER_URL=https://indexer.yourdomain Keys
The relayer keypair is a secret. It is mounted as a Docker secret, never baked into the image or committed. Keep it funded, and rotate it if exposed.
Warning
Use a dedicated RPC. Public RPCs rate-limit
getProgramAccounts and getTransaction, which the indexer relies on. Put a reverse proxy in front for TLS and a second rate-limit layer.Circuit artifacts
Withdrawal proofs are generated in the browser, so the two circuit files are served as static assets: withdraw.wasm and withdraw_final.zkey under /circuits.
Run it locally
RELAYER_WALLET=./relayer.json RPC_URL=https://api.devnet.solana.com node sdk/relayer.mjs # :8789
RPC_URL=https://api.devnet.solana.com node sdk/indexer.mjs # :8788See Embed to add the pay flow to your own site.