Configuration
Overview
Most configuration files should live under ./config
, including the signer configurations, under ./config/keys
.
Please ensure appropriate access permissions on all configuration files (for ./config/keys/*
, we recommend 0500
.
The OpenZeppelin Relayer supports two configuration approaches: File-based Configuration:
1. API-based Configuration: - Full CRUD operations for relayers, signers, and notifications via REST API - Changes take effect immediately (no container restart required) - See the API Reference page for detailed endpoints documentation See Storage Configuration for detailed information about how file-based and API-based configurations work together, storage behavior, and best practices. For quick setup examples with pre-configured files, see the examples directory in our GitHub repository. |
Environment configuration (.env)
This defines some base configurations for the Relayer application:
Copy the example environment file and update values according to your needs
cp .env.example .env
This table lists the environment variables and their default values.
Environment Variable | Default Value | Accepted Values | Description |
---|---|---|---|
|
|
|
Log level. |
|
|
|
Type of storage used for storing repository config and resources. See Storage Configuration for detailed information. |
|
|
|
Clears all resources from storage on startup and reloads entries from the config file. See Storage Configuration for usage details. |
|
|
|
Number of hours after which transactions in a final state are removed from storage. See Storage Configuration for more information. |
|
|
|
Relative path of directory where config files reside |
|
|
|
File Name of the configuration file. |
|
|
|
Rate limit for the API in requests per second. |
|
|
|
Rate limit burst size. |
|
`` |
|
API key to use for authentication to the relayer server. Minimum length 32 characters. |
|
`` |
|
Signing key to use for webhook notifications. Minimum length 32 characters. |
|
|
|
Write logs either to console or to file. |
|
|
|
Directory to persist log files on host. |
|
|
|
Size after which logs needs to be rolled. |
|
|
|
Enable metrics server for external tools to scrape metrics. |
|
|
|
Port to use for metrics server. |
|
|
|
Redis connection URL for the relayer. See Storage Configuration for Redis setup details. |
|
|
|
Connection timeout for Redis in milliseconds. See Storage Configuration for Redis configuration. |
|
|
|
Redis key prefix for namespacing. See Storage Configuration for more information. |
|
`` |
|
Encryption key used to encrypt data at rest in Redis storage. See Storage Configuration for security details. |
|
|
|
Sets the maximum time to wait for RPC connections before timing out. |
|
|
|
Maximum number of retry attempts for provider operations. |
|
|
|
Base delay between retry attempts in milliseconds. |
|
|
|
Maximum delay between retry attempts in milliseconds. |
|
|
|
Maximum number of failovers (switching to different providers). |
|
|
|
Enable or disable Swagger UI for API documentation. |
|
`` |
|
Passphrase for the keystore file used for signing transactions. |
Environment configuration example
.env
file config example:
RUST_LOG=DEBUG
CONFIG_DIR=./config
CONFIG_FILE_NAME=config.json
WEBHOOK_SIGNING_KEY=e1d42480-6f74-4d0b-85f4-b7f0bb690fae
API_KEY=5eefd216-0e44-4ca7-b421-2925f90d30d5
RATE_LIMIT_RPS=100
RATE_LIMIT_BURST_SIZE=300
METRICS_ENABLED=true
METRICS_PORT=8081
REDIS_URL=redis://localhost:6379
REDIS_CONNECTION_TIMEOUT_MS=10000
REDIS_KEY_PREFIX=oz-relayer
RPC_TIMEOUT_MS=10000
PROVIDER_MAX_RETRIES=3
PROVIDER_RETRY_BASE_DELAY_MS=100
PROVIDER_RETRY_MAX_DELAY_MS=2000
PROVIDER_MAX_FAILOVERS=3
ENABLE_SWAGGER=false
KEYSTORE_PASSPHRASE=your_keystore_passphrase
STORAGE_ENCRYPTION_KEY=X67aXacJB+krEldv9i2w7NCSFwwOzVV/1ELM2KJJjQw=
REPOSITORY_STORAGE_TYPE=redis
RESET_STORAGE_ON_START=false
TRANSACTION_EXPIRATION_HOURS=8
Main configuration file (config.json)
This file can exist in any directory, but the default location is ./config/config.json
.
All components defined in |
Key sections in this file include:
-
Signers: Defines transaction signing methods.
-
Notifications: Sets up status alerts
-
Relayers: Configures networks, notifications channels, policies & singers.
-
Networks: Defines blockchain network configurations.
-
Plugins: Configures plugins.
1. Signers
Transaction signers are responsible for cryptographically signing transactions before they are submitted to blockchain networks.
For comprehensive details on configuring all supported signer types including:
-
Local keystore file signers
-
HashiCorp Vault (secret and transit)
-
Cloud KMS providers (Google Cloud, AWS)
-
Turnkey signers
-
Security best practices and troubleshooting
See the dedicated Signers Configuration guide.
Signers can also be managed via API endpoints. See the API Reference page for detailed endpoints documentation. |
2. Notifications
-
notifications
array containing notification entries:
"notifications": [
{
"id": "notification-test",
"type": "webhook",
"url": "https://webhook.site/f95cf78d-742d-4b21-88b7-d683e6fd147b",
"signing_key": {
"type": "env",
"value": "WEBHOOK_SIGNING_KEY"
}
}
]
Available configuration fields
Field | Type | Description |
---|---|---|
id |
String |
Unique id for the notification |
type |
String |
Type of notification (only |
url |
String |
Notification URL |
signing_key.type |
String |
Type of key used in signing the notification ( |
signing_key.value |
String |
Signing key value, env variable name, … |
Notifications can also be managed via API endpoints. See the API Reference page for detailed endpoints documentation. |
3. Relayers
-
relayers
array, containing relayer entries:
"relayers": [
{
"id": "solana-testnet",
"name": "Solana Testnet",
"paused": false,
"notification_id": "notification-test",
"signer_id": "local-signer",
"network_type": "solana",
"network": "testnet",
"custom_rpc_urls": [
{
"url": "https://primary-rpc.example.com",
"weight": 2 // Higher weight routes more requests to this endpoint. The value must be an integer between 0 and 100 (inclusive).
},
{
"url": "https://backup-rpc.example.com",
"weight": 1
}
],
"policies": {
"allowed_programs": [
"11111111111111111111111111111111",
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
"BPFLoaderUpgradeab1e11111111111111111111111"
]
}
}
]
Available configuration fields
Field | Type | Description |
---|---|---|
id |
String |
Unique id for the relayer |
name |
String |
Human readable name for the relayer |
paused |
Boolean |
Whether or not the relayer is paused ( |
notification_id |
String |
ID of a configured notification object |
signer_id |
String |
ID of a configured signer |
network_type |
String |
Type of network the relayer will connect to ( |
network |
String |
Network the relayer will connect to. Must match a network identifier defined in your network configuration files. See Network Configuration for details on defining networks. |
custom_rpc_urls |
list |
Optional custom RPC URLs for the network. If provided, this will be used instead of the public RPC URLs. This is useful for using your own RPC node or a paid service provider. The first url of the list is going to be used as the default |
policies |
list |
Overrides default policies. Please refer to the |
Policies
Network type | Policy | Type | Description |
---|---|---|---|
solana, evm |
min_balance |
unsigned 128 |
Minimum balance (in lamports or wei) required for the relayer to operate. Optional. |
solana |
fee_payment_strategy |
enum(user,relayer) |
Specifies who pays the fee. "user" (default) means the sender pays; "relayer" means the relayer pays. For "user", RPC methods add an instruction to transfer SPL tokens (calculated from the current SOL price plus a configurable margin) from the user to the relayer, ensuring fees are sustainably covered in tokens rather than SOL. |
solana |
swap_config |
SwapConfig |
Optional object configuring automated token‐swaps on Solana. |
solana |
fee_margin_percentage |
f32 |
Additional margin percentage added to estimated transaction fees to account for price fluctuations. For example, a value of 10 will add 10% to estimated fees. Optional. |
solana |
max_allowed_fee_lamports |
unsigned 64 |
Maximum allowed fee (in lamports) for a transaction. Optional. |
solana |
allowed_tokens |
Vector<AllowedToken> |
List of allowed tokens. Only these tokens are supported if provided. Optional. |
solana |
allowed_programs |
Vector<String> |
List of allowed programs by their identifiers. Only these programs are supported if provided. |
solana |
allowed_accounts |
Vector<String> |
List of allowed accounts by their public keys. The relayer will only operate with these accounts if provided. |
solana |
disallowed_accounts |
Vector<String> |
List of disallowed accounts by their public keys. These accounts will be explicitly blocked. |
solana |
max_tx_data_size |
unsigned 16 |
Maximum transaction size. Optional. |
solana |
max_signatures |
unsigned 8 |
Maximum supported signatures. Optional. |
evm |
gas_price_cap |
unsigned 128 |
Specify a maximum gas price for every transaction sent with the Relayer. When enabled, any transaction exceeding the cap will have its gasPrice or maxFeePerGas overwritten. (Optional) |
evm |
gas_limit_estimation |
bool |
Automatic gas_limit calculation. Enabled by default. (Optional) |
evm |
whitelist_receivers |
Vector<String> |
A list of authorized contracts for each transaction sent using the Relayer. Transactions will be rejected if the destination address is not on the list. (Optional) |
RPC URL Configuration
The relayer supports two ways to configure RPC URLs:
-
Public RPC URLs: These are the default RPC endpoints provided by the network. They are automatically selected based on the network configuration.
-
Custom RPC URLs: You can specify custom RPC URLs using the
custom_rpc_urls
field in the relayer configuration. Each URL can be configured with an optional weight for high availability:
"custom_rpc_urls": [
{
"url": "https://primary-rpc.example.com",
"weight": 2 // Higher weight routes more requests to this endpoint. The value must be an integer between 0 and 100 (inclusive).
},
{
"url": "https://secondary-rpc.example.com",
"weight": 100, // Max allowed weight
},
{
"url": "https://backup-rpc.example.com" // No weight specified, defaults to 100
},
{
"url": "https://backup2-rpc.example.com",
"weight": 0, // A value of 0 disables the endpoint.
}
]
This is useful when you want to: * Use your own RPC nodes with load balancing * Use a paid service provider for better reliability and performance * Override the default public RPC URLs * Access custom network endpoints * Configure primary and backup endpoints with different weights
When both are available, the relayer will:
1. First attempt to use the custom_rpc_urls
if configured.
2. Fall back to the public RPC URLs if no custom URL is configured.
For backward compatibility, string arrays are still supported:
"custom_rpc_urls": ["https://your-rpc.example.com"]
When using custom RPC URLs:
|
Relayers could also be managed via API endpoints. See the API Reference page for detailed endpoints documentation. |
4. Plugins
For more information on how to write a plugin, please refer to the Plugins page.
-
plugins
array, containing plugin configurations:
"plugins": [
{
"id": "my-plugin",
"path": "my-plugin.ts"
}
]
Available configuration fields
Field | Type | Description |
---|---|---|
id |
String |
Unique id for the plugin |
path |
String |
Path to the plugin file |
5. Networks
You can configure networks either:
-
In separate JSON files (recommended for better organization)
-
Directly in your main
config.json
For comprehensive network configuration details, including:
-
Network field reference
-
Configuration examples for all network types
-
Network inheritance
-
Special tags and their behavior
-
Best practices and troubleshooting
See the dedicated Network Configuration guide.
Configuration File Example
Full config/config.json
example with evm and solana relayers definitions using keystore signer:
{
"relayers": [
{
"id": "sepolia-example",
"name": "Sepolia Example",
"network": "sepolia",
"paused": false,
"notification_id": "notification-example",
"signer_id": "local-signer",
"network_type": "evm",
"custom_rpc_urls": [
{
"url": "https://primary-rpc.example.com",
"weight": 2
},
{
"url": "https://backup-rpc.example.com",
"weight": 1
}
],
"policies": {
"gas_price_cap": 30000000000000,
"eip1559_pricing": true
}
},
{
"id": "solana-example",
"name": "Solana Example",
"network": "devnet",
"paused": false,
"notification_id": "notification-example",
"signer_id": "local-signer",
"network_type": "solana",
"custom_rpc_urls": [
{
"url": "https://primary-solana-rpc.example.com",
"weight": 2
},
{
"url": "https://backup-solana-rpc.example.com",
"weight": 1
}
],
"policies": {
"fee_payment_strategy": "user",
"min_balance": 0,
"allowed_tokens": [
{
"mint": "Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr",
"max_allowed_fee": 100000000
},
{
"mint": "So11111111111111111111111111111111111111112"
}
]
}
},
{
"id": "solana-mainnet-example",
"name": "Solana Mainnet Example",
"network": "mainnet-beta",
"paused": false,
"notification_id": "notification-example",
"signer_id": "local-signer",
"network_type": "solana",
"custom_rpc_urls": ["https://your-private-solana-rpc.example.com"],
"policies": {
"fee_payment_strategy": "user",
"min_balance": 0,
"swap_config": {
"cron_schedule": "0 0 * * * *",
"min_balance_threshold": 0,
"strategy": "jupiter-ultra"
},
"allowed_tokens": [
{
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"max_allowed_fee": 100000000,
"swap_config": {
"min_amount": 0,
"max_amount": 0,
"retain_min_amount": 0
}
},
{
"mint": "So11111111111111111111111111111111111111112"
}
]
}
}
],
"notifications": [
{
"id": "notification-example",
"type": "webhook",
"url": "https://webhook.site/1384d4d9-21b1-40a0-bcd1-d3f3b66be955",
"signing_key": {
"type": "env",
"value": "WEBHOOK_SIGNING_KEY"
}
}
],
"signers": [
{
"id": "local-signer",
"type": "local",
"config": {
"path": "config/keys/local-signer.json",
"passphrase": {
"type": "env",
"value": "KEYSTORE_PASSPHRASE"
}
}
}
],
"networks": [
{
"average_blocktime_ms": 12000,
"chain_id": 11155111,
"explorer_urls": [
"https://api-sepolia.etherscan.io/api",
"https://sepolia.etherscan.io"
],
"features": [
"eip1559"
],
"is_testnet": true,
"network": "sepolia",
"required_confirmations": 6,
"rpc_urls": [
"https://sepolia.drpc.org",
"https://1rpc.io/sepolia",
"https://ethereum-sepolia-rpc.publicnode.com",
"https://ethereum-sepolia-public.nodies.app"
],
"symbol": "ETH",
"tags": [
"deprecated"
],
"type": "evm"
},
{
"type": "solana",
"network": "devnet",
"rpc_urls": ["https://api.devnet.solana.com"],
"explorer_urls": ["https://explorer.solana.com?cluster=devnet"],
"average_blocktime_ms": 400,
"is_testnet": true
},
{
"type": "solana",
"network": "mainnet-beta",
"rpc_urls": ["https://api.mainnet-beta.solana.com"],
"explorer_urls": ["https://explorer.solana.com"],
"average_blocktime_ms": 400,
"is_testnet": false
}
]
}
Configuration Management Approaches
The OpenZeppelin Relayer supports two complementary approaches for configuration management:
File-based Configuration
-
Ideal for initial setup and deployment
-
Configuration persists across restarts
-
Requires container restart for changes to take effect
-
Suitable for infrastructure-as-code workflows
API-based Configuration
-
Enables runtime configuration changes
-
No service restarts required
-
Perfect for dynamic environments
-
Supports automated configuration management
See Storage Configuration for detailed information about how file-based and API-based configurations work together, storage behavior, and best practices. |