Join our community of builders on

Telegram!Telegram

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. config.json: Contains relayer definitions, signer configurations, and network policies
  2. .env file: Contains environment variables like API keys and connection strings

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 VariableDefault ValueAccepted ValuesDescription
RUST_LOGinfoinfo, debug, warn, error, traceLog level.
REPOSITORY_STORAGE_TYPEin-memoryin-memory, redisType of storage used for storing repository config and resources. See Storage Configuration for detailed information.
RESET_STORAGE_ON_STARTfalseboolClears all resources from storage on startup and reloads entries from the config file. See Storage Configuration for usage details.
TRANSACTION_EXPIRATION_HOURS4numberNumber of hours after which transactions in a final state are removed from storage. See Storage Configuration for more information.
CONFIG_DIR./config<any relative file path where config.json is located>Relative path of directory where config files reside
CONFIG_FILE_NAMEconfig.json<any file name>File Name of the configuration file.
RATE_LIMIT_REQUESTS_PER_SECOND100<any value>Rate limit for the API in requests per second.
RATE_LIMIT_BURST_SIZE300<any value>Rate limit burst size.
API_KEY``string,API key to use for authentication to the relayer server. Minimum length 32 characters.
WEBHOOK_SIGNING_KEY``stringSigning key to use for webhook notifications. Minimum length 32 characters.
LOG_MODEstdoutstdout, fileWrite logs either to console or to file.
LOG_DATA_DIR./logs<any file path>Directory to persist log files on host.
LOG_MAX_SIZE (in bytes)1073741824<any value in bytes>Size after which logs needs to be rolled.
METRICS_ENABLEDfalseboolEnable metrics server for external tools to scrape metrics.
METRICS_PORT8081<any tcp port (preferably choose non-privileged ports i.e. (1024-65535))>Port to use for metrics server.
REDIS_URLredis://localhost:6379<redis connection string>Redis connection URL for the primary instance. Used for all write operations and read operations when REDIS_READER_URL is not set. See Storage Configuration for Redis setup details.
REDIS_READER_URL(none)<redis connection string>Optional separate endpoint for read operations. When set, read operations use this endpoint while writes use REDIS_URL. Useful for AWS ElastiCache with read replicas. See Storage Configuration for configuration examples.
REDIS_CONNECTION_TIMEOUT_MS10000<timeout in milliseconds>Connection timeout for Redis in milliseconds. See Storage Configuration for Redis configuration.
REDIS_POOL_MAX_SIZE500<number>Maximum number of connections in the primary Redis connection pool. See Storage Configuration for tuning guidance.
REDIS_READER_POOL_MAX_SIZE1000<number>Maximum number of connections in the reader Redis connection pool. Only used when REDIS_READER_URL is set. Useful for read-heavy workloads. See Storage Configuration for pool sizing recommendations.
REDIS_POOL_TIMEOUT_MS10000<timeout in milliseconds>Maximum time to wait for a connection from the pool. See Storage Configuration for performance tuning.
REDIS_KEY_PREFIXoz-relayerstringRedis key prefix for namespacing. See Storage Configuration for more information.
QUEUE_BACKENDredisredis, sqsQueue backend implementation. redis uses Apalis + Redis queues. sqs uses AWS SQS workers and queue backend abstraction.
AWS_REGION(none)<aws region>Required when QUEUE_BACKEND=sqs. Used to build/resolve SQS queue endpoints.
AWS_ACCOUNT_ID(none)<aws account id>Required when QUEUE_BACKEND=sqs and SQS_QUEUE_URL_PREFIX is not set. Used to construct default SQS queue URLs.
SQS_QUEUE_URL_PREFIX(none)<sqs queue url prefix>Optional override for SQS queue URL prefix (example: https://sqs.us-east-1.amazonaws.com/123456789012/relayer-). When set, AWS_ACCOUNT_ID is not required.
SQS_QUEUE_TYPEautoauto, standard, fifoSQS queue type. auto (default) probes the transaction-request queue at startup to detect the type. standard and fifo skip probing and use the specified type directly.
DISTRIBUTED_MODEfalsebool (true/false, 1/0)Enables Redis-based distributed locks for cron/cleanup tasks in multi-instance deployments, preventing duplicate scheduled execution across nodes.
STORAGE_ENCRYPTION_KEY``stringEncryption key used to encrypt data at rest in Redis storage. See Storage Configuration for security details.
RPC_TIMEOUT_MS10000<timeout in milliseconds>Sets the maximum time to wait for RPC connections before timing out.
PROVIDER_MAX_RETRIES3<number of retries>Maximum number of retry attempts for provider operations.
PROVIDER_RETRY_BASE_DELAY_MS100<delay in milliseconds>Base delay between retry attempts in milliseconds.
PROVIDER_RETRY_MAX_DELAY_MS2000<delay in milliseconds>Maximum delay between retry attempts in milliseconds.
PROVIDER_MAX_FAILOVERS3<number of failovers>Maximum number of failovers (switching to different providers).
PROVIDER_FAILURE_THRESHOLD3<number>Number of consecutive failures before a provider is temporarily paused. When a provider reaches this threshold, it will be paused for the duration specified by PROVIDER_PAUSE_DURATION_SECS. Supports legacy env var RPC_FAILURE_THRESHOLD.
PROVIDER_PAUSE_DURATION_SECS60<seconds>Duration in seconds that a provider remains paused after reaching the failure threshold. During this time, the relayer will attempt to use other available providers. Supports legacy env var RPC_PAUSE_DURATION_SECS.
PROVIDER_FAILURE_EXPIRATION_SECS60<seconds>Duration in seconds after which individual failure records are considered stale and automatically removed. This allows providers to naturally recover over time even without explicit success calls. Failures older than this duration are not counted toward the failure threshold.
RPC_ALLOWED_HOSTS``<comma-separated hostnames>Comma-separated list of allowed RPC hostnames/IPs. If non-empty, only URLs with these hosts are permitted. Example: eth-mainnet.g.alchemy.com,mainnet.infura.io
RPC_BLOCK_PRIVATE_IPSfalseboolBlock private IP addresses (RFC 1918, loopback, link-local) in RPC URLs. Set to true to prevent RPC URLs from targeting private networks.
CONNECTION_BACKLOG511<number>TCP listen backlog size (pending connections queue). Higher values allow more connections to be queued during traffic bursts, preventing connection drops. Default of 511 is a production-ready value that balances memory usage with burst capacity.
REQUEST_TIMEOUT_SECONDS30<seconds>Request handler timeout in seconds for API endpoints. This is a security measure to prevent resource exhaustion attacks (DoS). It limits how long a request handler can run, preventing slowloris-style attacks and ensuring resources are freed promptly.
RELAYER_CONCURRENCY_LIMIT100<any positive number>Maximum number of concurrent requests allowed for /api/v1/relayers/* endpoints. When this limit is reached, additional requests will be rejected with a 429 Too Many Requests error. This helps prevent resource exhaustion and ensures fair resource allocation.
MAX_CONNECTIONS256<any positive number>Maximum number of concurrent TCP connections allowed server-wide. This is a safety net that prevents the server from accepting more connections than it can handle. When this limit is reached, new connections will be rejected.
ENABLE_SWAGGERfalsetrue, falseEnable or disable Swagger UI for API documentation.
KEYSTORE_PASSPHRASE``<keystore passphrase>Passphrase for the keystore file used for signing transactions.
BACKGROUND_WORKER_TRANSACTION_REQUEST_CONCURRENCY50<any positive number>Maximum number of concurrent transaction request jobs that can be processed simultaneously.
BACKGROUND_WORKER_TRANSACTION_SENDER_CONCURRENCY75<any positive number>Maximum number of concurrent transaction submission jobs that can be processed simultaneously.
BACKGROUND_WORKER_TRANSACTION_STATUS_CHECKER_CONCURRENCY50<any positive number>Maximum number of concurrent generic/default transaction status check jobs that can be processed simultaneously. This worker handles Solana and any future networks that don’t have dedicated status checkers.
BACKGROUND_WORKER_TRANSACTION_STATUS_CHECKER_EVM_CONCURRENCY100<any positive number>Maximum number of concurrent EVM transaction status check invocations that can be processed simultaneously. EVM handles the highest volume (~75% of all status checks) and uses optimized retries (8-20s) to avoid triggering premature resubmission.
BACKGROUND_WORKER_TRANSACTION_STATUS_CHECKER_STELLAR_CONCURRENCY50<any positive number>Maximum number of concurrent Stellar transaction status checks that can be processed simultaneously. Stellar status checker uses fast retries (2-3s) optimized for Stellar’s faster block times.
BACKGROUND_WORKER_NOTIFICATION_SENDER_CONCURRENCY30<any positive number>Maximum number of concurrent notifications that can be processed simultaneously.
BACKGROUND_WORKER_SOLANA_TOKEN_SWAP_REQUEST_CONCURRENCY10<any positive number>Maximum number of concurrent Solana token swap requests that can be processed simultaneously. Low volume worker.
BACKGROUND_WORKER_TRANSACTION_CLEANUP_CONCURRENCY1<any positive number>Maximum number of concurrent transaction cleanup invocations that can be processed simultaneously. Defaults to 1 to avoid database conflicts.
BACKGROUND_WORKER_RELAYER_HEALTH_CHECK_CONCURRENCY10<any positive number>Maximum number of concurrent relayer health check invocations that can be processed simultaneously. Low volume worker.

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_REQUESTS_PER_SECOND=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
PROVIDER_FAILURE_THRESHOLD=3
PROVIDER_PAUSE_DURATION_SECS=60
PROVIDER_FAILURE_EXPIRATION_SECS=60
RPC_BLOCK_PRIVATE_IPS=true
RPC_ALLOWED_HOSTS=eth-mainnet.g.alchemy.com,mainnet.infura.io
CONNECTION_BACKLOG=511
REQUEST_TIMEOUT_SECONDS=30
RELAYER_CONCURRENCY_LIMIT=100
MAX_CONNECTIONS=256
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

Queue backend configuration

Set QUEUE_BACKEND to choose the queue system:

  • redis (default): Redis queue backend via Apalis workers
  • sqs: AWS SQS queue backend (standard or FIFO queues)

Example for SQS:

QUEUE_BACKEND=sqs
AWS_REGION=us-east-1
AWS_ACCOUNT_ID=123456789012
# Optional: "auto" (default), "standard", or "fifo"
# SQS_QUEUE_TYPE=auto
# Optional alternative to AWS_ACCOUNT_ID:
# SQS_QUEUE_URL_PREFIX=https://sqs.us-east-1.amazonaws.com/123456789012/relayer-

By default (SQS_QUEUE_TYPE=auto), the relayer auto-detects whether your queues are standard or FIFO at startup by probing the transaction-request queue. Set SQS_QUEUE_TYPE=standard or SQS_QUEUE_TYPE=fifo to skip probing and use the specified type directly.

For distributed deployments (multiple relayer instances), set:

DISTRIBUTED_MODE=true

This enables distributed locking for cron/cleanup tasks so only one instance executes each scheduled job at a time.

SQS queue provisioning guide

When QUEUE_BACKEND=sqs, create queues with the relayer- prefix (or your custom SQS_QUEUE_URL_PREFIX). By default (SQS_QUEUE_TYPE=auto), the relayer auto-detects the queue type at startup by probing a reference queue. You can also set SQS_QUEUE_TYPE=standard or SQS_QUEUE_TYPE=fifo to skip probing.

Standard queues

Standard queues offer higher throughput, native per-message DelaySeconds, and simpler setup. Duplicate deliveries are possible but harmless since all handlers are idempotent.

Required queue names:

  • relayer-transaction-request
  • relayer-transaction-submission
  • relayer-status-check
  • relayer-status-check-evm
  • relayer-status-check-stellar
  • relayer-notification
  • relayer-token-swap-request
  • relayer-relayer-health-check

AWS CLI example (replace <ACCOUNT_ID>):

aws sqs create-queue \
  --queue-name relayer-transaction-request \
  --attributes VisibilityTimeout=30

FIFO queues

FIFO queues provide message ordering per group and exactly-once delivery via deduplication. The relayer sets MessageGroupId and MessageDeduplicationId on send.

Required queue names:

  • relayer-transaction-request.fifo
  • relayer-transaction-submission.fifo
  • relayer-status-check.fifo
  • relayer-status-check-evm.fifo
  • relayer-status-check-stellar.fifo
  • relayer-notification.fifo
  • relayer-token-swap-request.fifo
  • relayer-relayer-health-check.fifo

AWS CLI example (replace <ACCOUNT_ID>):

aws sqs create-queue \
  --queue-name relayer-transaction-request.fifo \
  --attributes \
FifoQueue=true,ContentBasedDeduplication=false,VisibilityTimeout=30,DeduplicationScope=messageGroup,FifoThroughputLimit=perMessageGroupId

For production workloads, enable high-throughput FIFO on high-volume queues (transaction-request, transaction-submission, status-check). Set DeduplicationScope=messageGroup and FifoThroughputLimit=perMessageGroupId to raise throughput from 300 to 70,000 messages/second per queue.

These settings apply to both standard and FIFO queues:

QueueVisibility timeout (seconds)Suggested maxReceiveCount (DLQ redrive)
transaction-request306
transaction-submission302
status-check301000 (or a high value)
status-check-evm301000 (or a high value)
status-check-stellar201000 (or a high value)
notification606
token-swap-request603
relayer-health-check603

Notes:

  • Status-check queues use short-delay re-enqueue for retries; use a high maxReceiveCount to avoid premature DLQ movement.
  • Configure a DLQ per queue in production. For FIFO queues, the DLQ must also be FIFO.

Set redrive policy to attach a DLQ:

aws sqs set-queue-attributes \
  --queue-url "https://sqs.us-east-1.amazonaws.com/<ACCOUNT_ID>/relayer-transaction-request" \
  --attributes '{"RedrivePolicy":"{\"deadLetterTargetArn\":\"<DLQ_ARN>\",\"maxReceiveCount\":\"6\"}"}'

Main configuration file (config.json)

This file can exist in any directory, but the default location is ./config/config.json.

All components defined in config.json can also be managed via REST API endpoints. This provides runtime flexibility for adding, updating, or removing relayers, signers, and notifications without restarting the service. See the API Reference page for detailed endpoints documentation.

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
  • CDP 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

FieldTypeDescription
idStringUnique id for the notification
typeStringType of notification (only webhook available, for now)
urlStringNotification URL
signing_key.typeStringType of key used in signing the notification (env or plain)
signing_key.valueStringSigning 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

FieldTypeDescription
idStringUnique id for the relayer
nameStringHuman readable name for the relayer
pausedBooleanWhether or not the relayer is paused (true, false)
notification_idStringID of a configured notification object
signer_idStringID of a configured signer
network_typeStringType of network the relayer will connect to (evm, solana)
networkStringNetwork 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_urlslistOptional 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
policieslistOverrides default policies. Please refer to the Policies table

Policies

Network typePolicyTypeDescription
solana, evm, stellarmin_balanceunsigned 128 (evm/solana), unsigned 64 (stellar)Minimum balance (in lamports, wei, or stroops) required for the relayer to operate. Optional.
solanafee_payment_strategyenum(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.
stellarfee_payment_strategyenum(user,relayer)Specifies who pays the fee. "user" enables sponsored transactions (users pay fees in tokens), "relayer" means relayer pays all fees in XLM. Optional.
solanaswap_configSwapConfigOptional object configuring automated token‐swaps on Solana.
stellarswap_configSwapConfigOptional object configuring automated token swaps on Stellar. Includes strategies (order-book, soroswap), cron_schedule, and min_balance_threshold.
solanafee_margin_percentagef32Additional 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.
stellarfee_margin_percentagef32Fee margin percentage applied when converting XLM fees to token amounts for sponsored transactions. Optional.
stellarslippage_percentagef32Maximum slippage percentage allowed when swapping tokens via DEX for sponsored transactions. Optional.
solanamax_allowed_fee_lamportsunsigned 64Maximum allowed fee (in lamports) for a transaction. Optional.
solanaallowed_tokensVector<AllowedToken>List of allowed tokens. Only these tokens are supported if provided. Optional.
stellarallowed_tokensVector<StellarAllowedToken>List of tokens allowed for fee payments in sponsored transactions. Each token includes asset, max_allowed_fee (optional), and swap_config (optional). Optional.
solanaallowed_programsVector<String>List of allowed programs by their identifiers. Only these programs are supported if provided.
solanaallowed_accountsVector<String>List of allowed accounts by their public keys. The relayer will only operate with these accounts if provided.
solanadisallowed_accountsVector<String>List of disallowed accounts by their public keys. These accounts will be explicitly blocked.
solanamax_tx_data_sizeunsigned 16Maximum transaction size. Optional.
solanamax_signaturesunsigned 8Maximum supported signatures. Optional.
stellarmax_feeunsigned 32Maximum transaction fee in stroops (1 XLM = 10,000,000 stroops) the relayer is willing to pay. Optional.
stellartimeout_secondsunsigned 64Transaction timeout in seconds. Optional.
stellarconcurrent_transactionsboolEnable concurrent transaction processing. When enabled, bypasses the lane gating mechanism that normally ensures sequential processing for each relayer. Only enable this when your relayer manages transactions from multiple accounts with independent sequence number pools. Optional.
evmgas_price_capunsigned 128Specify 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)
evmgas_limit_estimationboolAutomatic gas_limit calculation. Enabled by default. (Optional)
evmwhitelist_receiversVector<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:

  1. Public RPC URLs: These are the default RPC endpoints provided by the network. They are automatically selected based on the network configuration.
  2. 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"]

Provider Health Management

The relayer automatically tracks the health of RPC providers and manages failover:

  • Failure Tracking: When a provider fails, the failure is recorded with a timestamp. Failures older than PROVIDER_FAILURE_EXPIRATION_SECS (default: 60 seconds) are automatically considered stale and removed.

  • Automatic Pausing: When a provider reaches PROVIDER_FAILURE_THRESHOLD (default: 3) failures within the expiration window, it is automatically paused for PROVIDER_PAUSE_DURATION_SECS (default: 60 seconds). During this pause period, the relayer will attempt to use other available providers.

  • Automatic Recovery: After the pause duration expires, the provider becomes available again. Additionally, if all failures expire (older than PROVIDER_FAILURE_EXPIRATION_SECS), the provider automatically recovers even if it hasn't reached the pause expiration time.

  • Fallback Behavior: If all non-paused providers are unavailable, the relayer will fall back to paused providers as a last resort, ensuring maximum availability.

You can configure these behaviors using the environment variables:

  • PROVIDER_FAILURE_THRESHOLD: Number of failures before pausing (default: 3)
  • PROVIDER_PAUSE_DURATION_SECS: How long to pause a failed provider (default: 60 seconds)
  • PROVIDER_FAILURE_EXPIRATION_SECS: How long failures are remembered (default: 60 seconds)

RPC URL Security

You can configure the following security features via environment variables:

  • RPC_ALLOWED_HOSTS: Comma-separated list of allowed RPC hostnames/IPs. If non-empty, only URLs with these hosts are permitted.

    • Example: RPC_ALLOWED_HOSTS=eth-mainnet.g.alchemy.com,mainnet.infura.io
  • RPC_BLOCK_PRIVATE_IPS: Block private IP addresses (RFC 1918, loopback, link-local). Set to true to prevent RPC URLs from targeting private networks.

    • Example: RPC_BLOCK_PRIVATE_IPS=true
    • Default: false (for backwards compatibility)

Cloud metadata endpoints (169.254.169.254, fd00:ec2::254) are always blocked to prevent credential theft, regardless of configuration.

Recommended Production Configuration:

RPC_BLOCK_PRIVATE_IPS=true
RPC_ALLOWED_HOSTS=eth-mainnet.g.alchemy.com,mainnet.infura.io,eth.llamarpc.com

When using custom RPC URLs:

  • Ensure the URLs are secure (HTTPS) when accessing over public networks
  • Keep your API keys and authentication tokens secure
  • Test the RPC endpoints' reliability and performance before using it in production
  • Configure weights to prioritize endpoints, assigning higher values to more reliable or performant ones.
  • The weight must be an integer between 0 and 100 (inclusive).
  • A weight of 0 disables the endpoint.
  • If a weight is not specified for an endpoint, it defaults to 100.

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

FieldTypeDescription
idStringUnique id for the plugin
pathStringPath 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.