Files

Privacy Pools Relayer

A relayer service that facilitates private withdrawals and fee quoting for Privacy Pools.

It provides an API for users or frontends to:

  • Submit withdrawal requests
  • Get real-time fee quotes (including gas cost, relayer margin, and swap fees)
  • Retrieve relayer fee configuration details

Built with TypeScript, Express.js, and SQLite. Supports multi-chain configurations.


Setup

1. Install Dependencies

yarn install

2. Environment Variables

You must set the following environment variables before running:

Variable Purpose
INFURA_API_KEY For accessing Sepolia RPC (and Uniswap quoting)
RPC_URL RPC URL fallback if not configured in config.json
RELAYER_PRIVATE_KEY Private key used to sign fee commitments
SQLITE_DB_PATH (optional) Override path to SQLite DB

(You can create a .env file locally if you prefer.)

3. Build and Start

yarn build:start

For TypeScript live mode:

yarn start:ts

Or using Docker:

yarn docker:build
yarn docker:run

Configuration

Important Considerations for Relayer Fee Setup

When configuring your relayer, keep the following in mind:

  • In the config file, you define a fee_bps (basis points) value, e.g., 100 BPS for 0.1%.
  • This represents the desired profit margin over the value withdrawn.
  • During operation:
    • The relayer estimates the transaction cost (tx_cost) for executing a relay (gas used × gas price).
    • It calculates the effective feeBPS needed to fully cover tx_cost and still achieve the configured fee_bps margin.
    • This "effective" fee is dynamically adjusted upwards if gas prices spike.
  • If the value withdrawn is too small and the relayer cannot achieve at least the configured margin, the transaction will be rejected.

TLDR: fee_bps will be your profit over the withdrawn value. If the value is too small to cover the tx_fees and the relayer cut, it will reject the tx.


The relayer uses a config.json file to manage chains, assets, fees, and operational settings.

For setting up your config, use config.example.json as a basic template.

Configuration Reference

The relayer is configured through a config.json file.
This file defines global defaults, per-chain settings, supported assets, and operational parameters.

Below is the complete description of all fields, their types, and behaviors.


Top-Level Fields

Field Type Required Description
defaults Object Yes Default addresses and private keys for all chains unless overridden.
chains Array of Objects Yes List of supported chains and their specific settings.
sqlite_db_path String (absolute or relative path) Yes Path to the SQLite database file.
cors_allow_all Boolean Yes (default: false) Whether to allow all CORS origins or restrict to allowed domains.
allowed_domains Array of Strings (URLs) Yes List of allowed CORS domains if cors_allow_all is false.

defaults Object

Field Type Required Description
fee_receiver_address String (0x-prefixed address) Yes Address where relayer fees are collected.
signer_private_key String (0x-prefixed private key) Yes Private key used to sign fee commitments.
entrypoint_address String (0x-prefixed address) Yes Entrypoint contract address for relayer operations.

chains Array

Each entry represents a supported chain configuration.

Field Type Required Description
chain_id Number or String Yes Chain ID (e.g., 1 for Ethereum, 11155111 for Sepolia).
chain_name String Yes Human-readable chain name.
rpc_url String (URL) Yes JSON-RPC endpoint to connect to the chain.
max_gas_price String or Number (wei) Optional Maximum gas price allowed for relaying (in wei). If exceeded, relayer rejects transaction.
fee_receiver_address String (0x-prefixed address) Optional Chain-specific fee receiver. Overrides defaults.fee_receiver_address if set.
signer_private_key String (0x-prefixed private key) Optional Chain-specific signer. Overrides defaults.signer_private_key if set.
entrypoint_address String (0x-prefixed address) Optional Chain-specific entrypoint. Overrides defaults.entrypoint_address if set.
native_currency Object Optional Info about the chain's native currency (ETH, MATIC, etc).
supported_assets Array of Objects Optional List of ERC-20 or native assets supported for withdrawals on this chain.

chains[].native_currency Object

Field Type Required Description
name String No (default: "Ether") Full name of the native currency.
symbol String No (default: "ETH") Ticker symbol for the native currency.
decimals Number No (default: 18) Number of decimals used by the native currency.

chains[].supported_assets Array

Each entry represents a supported ERC-20 token (or native token).

Field Type Required Description
asset_address String (0x-prefixed address) Yes Token contract address. Use 0xEeeee... for native assets.
asset_name String Yes Human-readable name of the token.
fee_bps String or Number Yes Fee in basis points (1/100th of a percent). 100 = 1%.
min_withdraw_amount String or Number Yes Minimum withdrawal amount allowed for this asset (in base units, not decimals).

Behavior and Fallbacks

  • If fee_receiver_address, signer_private_key, or entrypoint_address are missing in a chain config, the relayer falls back to defaults and logs a warning.
  • If max_gas_price is not set, no gas price limits are enforced (relayer accepts any gas price).
  • If supported_assets is missing, no assets are available for withdrawal on that chain.
  • If native_currency is missing, defaults to:
    • Name: "Ether"
    • Symbol: "ETH"
    • Decimals: 18
  • If withdrawal or quote transactions cannot meet the configured profit margin (fee_bps), the request will be rejected.

Notes

  • All addresses must be valid EVM addresses (0x-prefixed, checksummed).
  • All private keys must be valid hex strings starting with 0x.
  • Fee calculations automatically adjust based on gas costs and swap rates when quoting.

Configuration Fields

  • fee_receiver_address: Where relayer fees are collected.
  • signer_private_key: Used to sign fee commitments.
  • entrypoint_address: Contract address handling withdrawals.
  • chains: Supported blockchain networks.
  • supported_assets: Supported ERC-20 or native assets with:
    • fee_bps: Relayer profit margin (in basis points).
    • min_withdraw_amount: Minimum withdrawal size allowed.

API Endpoints

POST /relayer/quote

Returns a fee quote for a withdrawal, including dynamic feeBPS adjusted for gas costs.

Request Body

{
  "chainId": 11155111,
  "amount": "1000000000000000000",
  "asset": "0xTokenAddress",
  "recipient": "0xRecipientAddress"
}

Response

{
  "baseFeeBPS": "200",
  "feeBPS": "291",
  "feeCommitment": {
    "expiration": 1744676669549,
    "withdrawalData": "0x...",
    "signedRelayerCommitment": "0x..."
  }
}

If recipient is provided, a signed relayer commitment is returned, valid for 20 seconds.


POST /relayer/request

Submits a full withdrawal payload for execution, optionally using a previously signed fee commitment.

Request Body

{
  "chainId": 11155111,
  "scope": "0x123...",
  "withdrawal": {
    "processooor": "0x...",
    "data": "0x..."
  },
  "proof": {
    "pi_a": ["..."],
    "pi_b": [["...", "..."], ["...", "..."]],
    "pi_c": ["..."]
  },
  "publicSignals": [...],
  "feeCommitment": {
    "expiration": 1744676669549,
    "withdrawalData": "0x...",
    "signedRelayerCommitment": "0x..."
  }
}

Response

{
  "success": true,
  "txHash": "0x...",
  "timestamp": 1744676669549,
  "requestId": "uuid"
}

If no feeCommitment is provided, the relayer checks if the feeBPS in the payload is high enough. Otherwise, it validates the signed commitment.


GET /relayer/details

Returns configuration for a given chain and asset.

Query Parameters

Parameter Required Description
chainId Yes Chain ID as number
assetAddress Yes Asset address (0x hex format)

Response

{
  "chainId": 11155111,
  "feeBPS": "200",
  "minWithdrawAmount": "1000",
  "feeReceiverAddress": "0x...",
  "assetAddress": "0x...",
  "maxGasPrice": "2392000000"
}

Available Scripts

Script Description
build Compile code with tsc
start Run the compiled server
build:start Compile and run in one command
start:ts Run using ts-node (dev mode)
check-types Type-check the codebase
lint / lint:fix Check or fix ESLint violations
format / format:fix Check or fix Prettier formatting
test / test:cov Run tests or generate coverage
docker:build / docker:run Build or run the relayer using Docker