mirror of
https://github.com/0xbow-io/privacy-pools-core.git
synced 2026-01-09 01:17:58 -05:00
docs: add documentation to relayer specific README (#79)
This commit is contained in:
@@ -1,102 +1,302 @@
|
||||
# ts-turborepo-boilerplate: relayer package
|
||||
# Privacy Pools Relayer
|
||||
|
||||
Description of your package goes here.
|
||||
A relayer service that facilitates private withdrawals and fee quoting for Privacy Pools.
|
||||
|
||||
## Setup
|
||||
It provides an API for users or frontends to:
|
||||
|
||||
1. Install dependencies running `pnpm install`
|
||||
- Submit withdrawal requests
|
||||
- Get real-time fee quotes (including gas cost, relayer margin, and swap fees)
|
||||
- Retrieve relayer fee configuration details
|
||||
|
||||
## Available Scripts
|
||||
Built with TypeScript, Express.js, and SQLite. Supports multi-chain configurations.
|
||||
|
||||
Available scripts that can be run using `pnpm`:
|
||||
---
|
||||
|
||||
| Script | Description |
|
||||
| ------------- | ------------------------------------------------------- |
|
||||
| `build` | Build library using tsc |
|
||||
| `check-types` | Check types issues using tsc |
|
||||
| `clean` | Remove `dist` folder |
|
||||
| `lint` | Run ESLint to check for coding standards |
|
||||
| `lint:fix` | Run linter and automatically fix code formatting issues |
|
||||
| `format` | Check code formatting and style using Prettier |
|
||||
| `format:fix` | Run formatter and automatically fix issues |
|
||||
| `test` | Run tests using vitest |
|
||||
| `test:cov` | Run tests with coverage report |
|
||||
# Setup
|
||||
|
||||
## Usage
|
||||
## 1. Install Dependencies
|
||||
|
||||
Describe how to use your package here.
|
||||
```bash
|
||||
yarn install
|
||||
```
|
||||
|
||||
## API
|
||||
## 2. Environment Variables
|
||||
|
||||
Describe your package's API here.
|
||||
You must set the following environment variables before running:
|
||||
|
||||
## Configuration
|
||||
| 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 |
|
||||
|
||||
The relayer service uses a JSON configuration file. A sample configuration file is provided as `config.example.json`. To set up your own configuration, copy this file to `config.json` and modify it according to your needs.
|
||||
*(You can create a `.env` file locally if you prefer.)*
|
||||
|
||||
### Configuration Structure
|
||||
## 3. Build and Start
|
||||
|
||||
```bash
|
||||
yarn build:start
|
||||
```
|
||||
|
||||
For TypeScript live mode:
|
||||
|
||||
```bash
|
||||
yarn start:ts
|
||||
```
|
||||
|
||||
Or using Docker:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
```json
|
||||
{
|
||||
"defaults": {
|
||||
"fee_receiver_address": "0x...",
|
||||
"signer_private_key": "0x...",
|
||||
"entrypoint_address": "0x..."
|
||||
},
|
||||
"chains": [
|
||||
// Chain configurations...
|
||||
],
|
||||
"sqlite_db_path": "/path/to/database.sqlite",
|
||||
"cors_allow_all": true,
|
||||
"allowed_domains": ["https://example.com"]
|
||||
"chainId": 11155111,
|
||||
"amount": "1000000000000000000",
|
||||
"asset": "0xTokenAddress",
|
||||
"recipient": "0xRecipientAddress"
|
||||
}
|
||||
```
|
||||
|
||||
### Default Configuration
|
||||
### Response
|
||||
|
||||
The `defaults` section provides global default values that apply across all chains unless overridden:
|
||||
```json
|
||||
{
|
||||
"baseFeeBPS": "200",
|
||||
"feeBPS": "291",
|
||||
"feeCommitment": {
|
||||
"expiration": 1744676669549,
|
||||
"withdrawalData": "0x...",
|
||||
"signedRelayerCommitment": "0x..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| `fee_receiver_address` | Address (0x-prefixed) | Ethereum address where transaction fees will be sent |
|
||||
| `signer_private_key` | Private Key (0x-prefixed) | Private key used for signing transactions |
|
||||
| `entrypoint_address` | Address (0x-prefixed) | Address of the entrypoint contract |
|
||||
If `recipient` is provided, a signed relayer commitment is returned, valid for 20 seconds.
|
||||
|
||||
### Chain Configuration
|
||||
---
|
||||
|
||||
Each entry in the `chains` array configures support for a specific blockchain:
|
||||
## POST /relayer/request
|
||||
|
||||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| `chain_id` | String/Number | The chain ID of the blockchain network |
|
||||
| `chain_name` | String | Human-readable name of the blockchain |
|
||||
| `rpc_url` | URL String | JSON-RPC endpoint URL for the blockchain |
|
||||
| `fee_receiver_address` | Address (optional) | Chain-specific fee receiver address (overrides defaults) |
|
||||
| `signer_private_key` | Private Key (optional) | Chain-specific signer private key (overrides defaults) |
|
||||
| `entrypoint_address` | Address (optional) | Chain-specific entrypoint address (overrides defaults) |
|
||||
| `max_gas_price` | String/Number (optional) | Max gas price for accepting relay operations, in WEI |
|
||||
| `native_currency` | Object | Information about the chain's native currency |
|
||||
| `supported_assets` | Array | List of supported assets on this chain |
|
||||
Submits a full withdrawal payload for execution, optionally using a previously signed fee commitment.
|
||||
|
||||
#### Asset Configuration
|
||||
### Request Body
|
||||
|
||||
Each entry in the `supported_assets` array configures a token that can be used with Privacy Pools:
|
||||
```json
|
||||
{
|
||||
"chainId": 11155111,
|
||||
"scope": "0x123...",
|
||||
"withdrawal": {
|
||||
"processooor": "0x...",
|
||||
"data": "0x..."
|
||||
},
|
||||
"proof": {
|
||||
"pi_a": ["..."],
|
||||
"pi_b": [["...", "..."], ["...", "..."]],
|
||||
"pi_c": ["..."]
|
||||
},
|
||||
"publicSignals": [...],
|
||||
"feeCommitment": {
|
||||
"expiration": 1744676669549,
|
||||
"withdrawalData": "0x...",
|
||||
"signedRelayerCommitment": "0x..."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| `asset_address` | Address | Contract address of the token |
|
||||
| `asset_name` | String | Human-readable name of the token |
|
||||
| `fee_bps` | String/Number | Fee in basis points (1/100 of a percent, so 100 = 1%) |
|
||||
| `min_withdraw_amount` | String/Number | Minimum amount that can be withdrawn |
|
||||
### Response
|
||||
|
||||
### Global Settings
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"txHash": "0x...",
|
||||
"timestamp": 1744676669549,
|
||||
"requestId": "uuid"
|
||||
}
|
||||
```
|
||||
|
||||
| Field | Type | Description |
|
||||
| ----- | ---- | ----------- |
|
||||
| `sqlite_db_path` | String | Path to the SQLite database file |
|
||||
| `cors_allow_all` | Boolean | Whether to allow all CORS requests (true) or only from specified domains (false) |
|
||||
| `allowed_domains` | Array of URLs | List of domains allowed to access the API when CORS is restricted |
|
||||
If no `feeCommitment` is provided, the relayer checks if the feeBPS in the payload is high enough. Otherwise, it validates the signed commitment.
|
||||
|
||||
## References
|
||||
---
|
||||
|
||||
Add any relevant references here.
|
||||
## 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
|
||||
|
||||
```json
|
||||
{
|
||||
"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 |
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user