Skip to content

Latest commit

 

History

History
131 lines (90 loc) · 5.19 KB

File metadata and controls

131 lines (90 loc) · 5.19 KB

Self-Hosting the FHEVM Relayer

What is the relayer?

The FHEVM Relayer bridges FHEVM host chains (e.g. Ethereum) and the Zama Gateway. It handles public decryption, user decryption, input proof verification, and FHE key material distribution. Anyone can self-host a relayer for permissionless access to the FHEVM network.

Why self-host?

Running your own relayer gives you permissionless, independent access to the FHEVM network without depending on third-party infrastructure.

Requirements

  • Rust toolchain + Cargo -- install via rustup
  • Docker + Docker Compose v2 -- for local PostgreSQL
  • Foundry (cast) -- for wallet operations during onboarding (install)
  • A funded wallet with ETH + $ZAMA tokens

Mainnet

Prerequisites

  • ETH on the Gateway chain for gas -- Bridge from Arbitrum One to Gateway via the Zama bridge
  • $ZAMA tokens on the Gateway chain -- Buy $ZAMA then bridge from Ethereum L1 to the Gateway chain via the Zama Bridge
  • An Ethereum L1 RPC endpoint

Step-by-step

All commands run from relayer/.

1. Start the database

make db-start

Starts a local PostgreSQL instance via Docker Compose (port 5433).

2. Apply migrations

make db-migrate

3. Run the preflight check

make preflight-mainnet

This interactive onboarding wizard:

  • Creates config/local.mainnet.yaml from the example template if missing
  • Prompts for your wallet private key
  • Derives your wallet address
  • Checks ETH balance
  • Checks $ZAMA balance
  • Checks that your wallet has approved the ProtocolPayment contract to spend $ZAMA (offers to grant max allowance via make approve-payment-mainnet if missing)

4. Run the relayer

make run-mainnet

Starts the relayer with cargo run using the mainnet config. Requires the local PostgreSQL to be running.

5. Verify health

make health

Checks /liveness, /healthz, /version, and /metrics endpoints.

Testnet

Testnet follows the same flow with different tokens:

  • ETH: Bridge from Arbitrum Sepolia via the Testnet bridge
  • $ZAMA: Ask the relayer team (not self-service on Testnet)
make db-start
make db-migrate
make preflight-testnet
make run-testnet
make health

Private key management

The config file stores the private key at gateway.tx_engine.private_key. Best practices:

  • Never commit config/local.mainnet.yaml or config/local.testnet.yaml to version control (they are already in .gitignore)
  • Environment variable override: Set APP_GATEWAY__TX_ENGINE__PRIVATE_KEY=0x... to avoid storing the key in the config file at all
  • Use a dedicated wallet for relayer operations

Configuration reference

Key operator-tunable fields in the config file:

Field Description Default
http.endpoint API listen address 0.0.0.0:3000
log.format Log format (compact, pretty, json) pretty
gateway.tx_engine.tx_throttlers.*.per_seconds TX throttle rate per operation type 20
storage.app_pool.max_connections Max database connections (app pool) 10
storage.cron.timeout_cron_interval How often the timeout worker runs 60s
storage.cron.public_decrypt_timeout Timeout for public decryption requests 30m
storage.cron.user_decrypt_timeout Timeout for user decryption requests 30m
storage.cron.input_proof_timeout Timeout for input proof requests 30m
storage.cron.expiry_enabled Enable automatic data cleanup false
storage.cron.public_decrypt_expiry Retention for public decrypt records 365d
storage.cron.user_decrypt_expiry Retention for user decrypt records 7d
storage.cron.input_proof_expiry Retention for input proof records 7d
http.retry_after.max_seconds Max Retry-After header value 300
http.enable_admin_endpoint Enable runtime config via /admin/config false

Configuration is hierarchical: YAML file -> environment variables (APP_ prefix, __ nesting) -> CLI args.

Monitoring

  • Prometheus metrics at :9898 (GET /metrics)
  • Application health at :3000 (/liveness, /healthz)
  • See src/metrics/docs_and_dashboards/ for Grafana dashboard queries and metric descriptions

Troubleshooting

See the Troubleshooting section in the main README.