A JSON-RPC proxy service that aggregates blockchain RPC endpoints from ethereum-lists/chains and exposes them through a unified FastAPI interface.
Single endpoint, any chain. Instead of managing a separate RPC URL per network, clients POST to /{chain_key} and omni-rpc handles endpoint selection, failover, caching, and rate limiting transparently.
- Unified
POST /{chain_key}endpoint for any chain loaded from ethereum-lists GET /chainslists all registered chains with metadata- JSON-RPC request normalisation (fills missing
jsonrpc,id,paramsfields; strips unknown fields) - Blocked namespaces:
trace_*anddebug_*methods are rejected before they reach any provider
ProviderPortinterface (send/health) decouples the HTTP layer from outbound transportHttpxProvidersends requests to a single RPC endpoint with a configurable hard timeout and per-provider retriesFailoverProviderwraps multiple providers per chain and tries each in order, masking individual failures from the caller
- Failover across all RPC endpoints for a chain on timeout, network error, or upstream 4xx/5xx
- Per-request overall timeout independent of per-provider timeout
- Rate limiting via slowapi (configurable per environment)
- Redis-backed cache for deterministic methods (
eth_chainId,net_version,web3_clientVersion,web3_sha3,net_listening) - Per-chain cache namespacing and per-method TTLs
- Graceful degradation to no-op cache when Redis is unavailable
- Loads chain definitions from the ethereum-lists git repo at startup
- Validates schema, detects duplicate chain IDs and names, logs checksum
- Read-only registry for consumers; atomic swap on reload with rollback on failure
- Background sync loop keeps chain data fresh without restarts
GET /metricsexposes Prometheus metrics (no authentication required; restrict at the network/proxy level)omni_rpc_requests_total{chain, status}— request count per chain and HTTP statusomni_rpc_request_duration_seconds{chain}— end-to-end request latency histogramomni_rpc_provider_errors_total{chain, error_type}— provider-level errors (timeout,provider_timeout,provider_error)
- Every log record includes a
request_idfield (UUID, echoed asX-Request-IDresponse header; passX-Request-IDon the request to correlate logs with your own tracing) - JSON structured logging available by setting
logging.formatter: jsonin the environment config
- Rejects unknown chains (404) and chains with no configured endpoints (502)
- Enforces configurable max payload size
- Validates JSON-RPC structure before forwarding
Hexagonal (ports & adapters): domain model and port interfaces are framework-free; adapters are injected at startup. This makes all layers independently testable.
domain/
model/ — Chain, RpcEndpoint, VmType (immutable dataclasses)
ports/ — ChainLoaderPort, ChainRegistryPort, CachePort, ProviderPort, Logger
application/ — LoadChainsUseCase, SyncChainsUseCase, BootstrapEthereumLists
adapters/
inbound/ — FastAPI router
outbound/ — EthereumListsChainLoader, InMemoryChainRegistry,
HttpxProvider, FailoverProvider,
RedisCacheAdapter, NullCacheAdapter
poetry install
poetry run omni-rpc init-chains
This will install the dependencies and download the ethereum-lists/chains repository.
poetry run python -m omni_rpc.main
By default this starts the server on 127.0.0.1:8000 using the dev environment config.
To use a different environment:
poetry run python -m omni_rpc.main --environment staging
poetry run python -m omni_rpc.main --environment prod
poetry run pytest
Environment-specific config files live in config/:
config/
├── config.template.yaml # Documented template
├── dev.yaml
├── staging.yaml
└── prod.yaml
See config/config.template.yaml for available settings and their descriptions.