Docs/Relayer/Setup Guide

Relayer Setup Guide

How to run your own ZKMix relayer

Relayer Setup Guide

This guide walks through the process of setting up and running your own ZKMix relayer. By operating a relayer, you provide an essential service to the ZKMix ecosystem -- enabling users to withdraw funds to fresh addresses without creating on-chain links -- and earn fees for each withdrawal you process.

Requirements

Hardware

ResourceMinimumRecommended
CPU2 cores4+ cores
RAM2 GB4 GB
Storage10 GB SSD20 GB SSD
Network100 Mbps1 Gbps

The relayer is not computationally intensive. It does not generate proofs -- it only validates and submits transactions. The primary resource requirements are network bandwidth and reliable uptime.

Software

  • Node.js v18.0 or later (LTS recommended)
  • npm v9.0 or later (included with Node.js)
  • Solana CLI v1.17 or later (for key management)

SOL Balance

The relayer needs SOL to pay transaction fees on behalf of users. Each withdrawal transaction costs approximately 0.000005 SOL in base fees plus priority fees.

ScenarioRecommended Balance
Low volume (< 100/day)0.5 SOL
Medium volume2 SOL
High volume (1000+/day)10+ SOL

The relayer earns back more than this amount through fees, but it needs an initial float to cover gas costs before fee revenue accumulates.

Installation

Step 1: Install Node.js

If Node.js is not already installed, download it from nodejs.org or use a version manager:

bash
# Using nvm (Linux/macOS)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
nvm install 18
nvm use 18

# Verify installation
node --version  # Should output v18.x.x or later
npm --version   # Should output v9.x.x or later

Step 2: Install the ZKMix Relayer

bash
# Install globally
npm install -g @zkmix/relayer

# Verify installation
zkmix-relayer --version

Alternatively, clone the repository and build from source:

bash
git clone https://github.com/zkmix/zkmix-relayer.git
cd zkmix-relayer
npm install
npm run build

Step 3: Generate a Relayer Keypair

The relayer needs a Solana keypair for signing transactions and receiving fees. You can generate a new keypair or use an existing one.

bash
# Generate a new keypair
solana-keygen new --outfile ~/.config/zkmix/relayer-keypair.json

# Or if you have an existing keypair, note its path
# The relayer will use this keypair to:
# 1. Pay transaction fees (gas)
# 2. Receive relayer fees from withdrawals

Fund the relayer address with SOL:

bash
# Get the relayer's public key
solana-keygen pubkey ~/.config/zkmix/relayer-keypair.json

# Fund it (devnet)
solana airdrop 2 <RELAYER_ADDRESS> --url devnet

# Fund it (mainnet) - transfer from your wallet
solana transfer <RELAYER_ADDRESS> 2 --url mainnet-beta

Configuration

Create a configuration file at ~/.config/zkmix/relayer-config.json:

json
{
  "network": {
    "cluster": "mainnet-beta",
    "rpcUrl": "https://api.mainnet-beta.solana.com",
    "wsUrl": "wss://api.mainnet-beta.solana.com",
    "commitment": "confirmed"
  },
  "relayer": {
    "keypairPath": "~/.config/zkmix/relayer-keypair.json",
    "port": 8080,
    "host": "0.0.0.0",
    "feePercentage": 0.3,
    "minFee": 10000,
    "maxPendingTransactions": 50,
    "transactionTimeout": 60000
  },
  "pools": {
    "supportAll": true,
    "whitelist": []
  },
  "rateLimit": {
    "maxRequestsPerMinute": 60,
    "maxRequestsPerIp": 10
  },
  "logging": {
    "level": "info",
    "file": "~/.config/zkmix/relayer.log",
    "maxFileSize": "50m",
    "maxFiles": 5
  },
  "monitoring": {
    "healthCheckInterval": 30000,
    "balanceAlertThreshold": 100000000,
    "metricsEnabled": true,
    "metricsPort": 9090
  }
}

Configuration Options Explained

Network settings:

FieldDescriptionDefault
clusterSolana cluster to connect to"mainnet-beta"
rpcUrlHTTP RPC endpoint URLPublic endpoint
wsUrlWebSocket endpoint for subscriptionPublic endpoint
commitmentTransaction confirmation level"confirmed"

Using a dedicated RPC provider is strongly recommended for mainnet relayer operation. Public endpoints have rate limits that can cause failed transactions during high volume.

Relayer settings:

FieldDescriptionDefault
keypairPathPath to the relayer's Solana keypair fileRequired
portHTTP server port8080
hostHTTP server bind address0.0.0.0
feePercentageFee as a percentage of the denomination0.3
minFeeMinimum fee in lamports regardless of percentage10000
maxPendingTransactionsMaximum concurrent in-flight transactions50
transactionTimeoutTimeout for transaction confirmation in ms60000

Pool settings:

FieldDescription
supportAllIf true, relay withdrawals for all active pools
whitelistIf supportAll is false, list of pool addresses to serve

Rate limiting:

FieldDescription
maxRequestsPerMinuteGlobal rate limit across all clients
maxRequestsPerIpPer-IP rate limit to prevent abuse

Running the Relayer

Start the Relayer

bash
# Using the globally installed package
zkmix-relayer start --config ~/.config/zkmix/relayer-config.json

# Or from the cloned repository
npm start -- --config ~/.config/zkmix/relayer-config.json

Expected output on successful startup:

[INFO] ZKMix Relayer v1.2.0
[INFO] Loading keypair from ~/.config/zkmix/relayer-keypair.json
[INFO] Relayer address: 7xKp...3nQm
[INFO] SOL balance: 2.45 SOL
[INFO] Connecting to mainnet-beta at https://api.mainnet-beta.solana.com
[INFO] Loaded 7 active pools
[INFO] Fee: 0.3% (min 10,000 lamports)
[INFO] HTTP server listening on 0.0.0.0:8080
[INFO] Health check: OK
[INFO] Relayer is ready to accept requests

Running as a System Service

For production deployment, run the relayer as a systemd service (Linux) to ensure automatic restarts and boot persistence:

ini
# /etc/systemd/system/zkmix-relayer.service
[Unit]
Description=ZKMix Relayer
After=network.target

[Service]
Type=simple
User=zkmix
ExecStart=/usr/bin/node /opt/zkmix-relayer/dist/index.js --config /etc/zkmix/relayer-config.json
Restart=always
RestartSec=10
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target
bash
sudo systemctl enable zkmix-relayer
sudo systemctl start zkmix-relayer
sudo systemctl status zkmix-relayer

Running with Docker

A Docker image is also available:

bash
docker run -d \
  --name zkmix-relayer \
  -p 8080:8080 \
  -p 9090:9090 \
  -v ~/.config/zkmix:/config \
  zkmix/relayer:latest \
  --config /config/relayer-config.json

Monitoring

Health Check Endpoint

The relayer exposes a health check endpoint at GET /health:

bash
curl http://localhost:8080/health
json
{
  "status": "healthy",
  "uptime": 86400,
  "version": "1.2.0",
  "solBalance": 2450000000,
  "pendingTransactions": 3,
  "totalRelayed": 1247,
  "totalFeesEarned": 3741000000
}

Prometheus Metrics

When metrics are enabled, the relayer exposes a Prometheus-compatible metrics endpoint at the configured metricsPort:

bash
curl http://localhost:9090/metrics

Available metrics include:

MetricTypeDescription
zkmix_relayer_requests_totalCounterTotal relay requests received
zkmix_relayer_success_totalCounterSuccessfully relayed transactions
zkmix_relayer_errors_totalCounterFailed relay attempts
zkmix_relayer_fees_earned_totalCounterTotal fees earned in lamports
zkmix_relayer_sol_balanceGaugeCurrent SOL balance
zkmix_relayer_pending_transactionsGaugeCurrently in-flight transactions
zkmix_relayer_request_duration_secondsHistogramRequest processing time

Balance Alerts

The relayer monitors its SOL balance and logs a warning when it drops below the configured balanceAlertThreshold. You can integrate this with external alerting systems by monitoring the log file or the Prometheus metrics.

Logs

The relayer outputs structured JSON logs that can be consumed by log aggregation tools like ELK, Loki, or Datadog.

Log Levels

LevelDescription
errorFailed transactions, RPC errors, out-of-balance conditions
warnLow balance warnings, rate limit hits, retried transactions
infoSuccessful relays, startup/shutdown events, balance reports
debugDetailed request/response data, transaction construction

Log Format

json
{
  "timestamp": "2025-03-15T14:30:22.451Z",
  "level": "info",
  "message": "Withdrawal relayed successfully",
  "txSignature": "5K7p...2xNm",
  "pool": "SOL-1",
  "recipient": "8xQm...4vRk",
  "fee": 3000000,
  "processingTime": 2340
}

Log Rotation

When using the file logger, logs are automatically rotated based on the maxFileSize and maxFiles configuration. Old log files are compressed and eventually deleted when the maximum number of retained files is reached.

Registering Your Relayer

After your relayer is running and publicly accessible, register it in the on-chain relayer registry so that SDK users can discover it automatically:

bash
zkmix-relayer register \
  --config ~/.config/zkmix/relayer-config.json \
  --url "https://your-relayer-domain.com"

This submits a transaction to the relayer registry program, making your relayer discoverable by the ZKMix SDK. The registration includes your fee percentage, supported pools, and endpoint URL.

Updating Registration

If you change your fee or endpoint URL, update your registration:

bash
zkmix-relayer update-registration \
  --config ~/.config/zkmix/relayer-config.json \
  --url "https://new-domain.com" \
  --fee 0.25

Deregistering

To remove your relayer from the registry:

bash
zkmix-relayer deregister --config ~/.config/zkmix/relayer-config.json