This document describes how to use the Redis-based configuration storage system for the OIF Solver.
The solver uses Redis as the single source of truth for runtime configuration. Configuration is:
- Seeded once when deploying a new solver
- Loaded from Redis on subsequent startups
- Versioned with optimistic locking for safe updates
- Redis running (default:
localhost:6379) - Environment variables set:
export REDIS_URL=redis://localhost:6379
export SOLVER_PRIVATE_KEY=your_64_hex_character_private_key# Seedless configuration (all values from JSON)
cargo run -- --bootstrap-config config/example.json
# Seed testnet configuration (preset fallback for known chains)
cargo run -- --seed testnet --bootstrap-config config/seed-overrides-testnet.json
# Seed mainnet configuration (preset fallback for known chains)
cargo run -- --seed mainnet --bootstrap-config config/seed-overrides-mainnet.json
# Seed using a non-seeded networks JSON example
cargo run -- --seed testnet --bootstrap-config config/non-seeded-networks-example.json
# Or pass JSON directly (useful for deployment services)
cargo run -- --seed testnet --bootstrap-config '{"solver_id":"my-solver","networks":[{"chain_id":11155420,"tokens":[{"symbol":"USDC","address":"0x191688B2Ff5Be8F0A5BCAB3E819C900a810FAaf6","decimals":6}]},{"chain_id":84532,"tokens":[{"symbol":"USDC","address":"0x73c83DAcc74bB8a704717AC09703b959E74b9705","decimals":6}]}]}'# Configuration is automatically loaded from Redis
cargo run --| Flag | Description |
|---|---|
--seed <preset> |
Seed configuration using a preset (testnet or mainnet) |
--bootstrap-config <value> |
Bootstrap config as JSON file path OR raw JSON string |
--seed-overrides <value> |
Deprecated alias for --bootstrap-config |
--force-seed |
Overwrite existing configuration in Redis |
Bootstrap config specifies which networks your solver will support. Networks can be:
- Preset-backed (
mainnet/testnetseed) - Non-seeded (new chain IDs) when required fields are provided
{
"solver_id": "my-solver-instance",
"networks": [
{
"chain_id": 11155420,
"tokens": [
{
"symbol": "USDC",
"address": "0x191688B2Ff5Be8F0A5BCAB3E819C900a810FAaf6",
"decimals": 6
}
]
},
{
"chain_id": 84532,
"tokens": [
{
"symbol": "USDC",
"address": "0x73c83DAcc74bB8a704717AC09703b959E74b9705",
"decimals": 6
}
],
"rpc_urls": ["https://my-custom-rpc.com"]
}
]
}| Field | Required | Description |
|---|---|---|
solver_id |
No | Unique solver identifier. If provided, enables idempotent seeding. If omitted, a UUID is generated. |
networks |
Yes | Array of networks to support |
networks[].chain_id |
Yes | Chain ID (seeded or non-seeded) |
networks[].tokens |
Yes | Tokens for this network (can be empty at boot) |
networks[].tokens[].symbol |
Yes | Token symbol (e.g., "USDC") |
networks[].tokens[].address |
Yes | Token contract address |
networks[].tokens[].decimals |
Yes | Token decimals |
networks[].rpc_urls |
No | Custom RPC URLs (falls back to seed defaults) |
settlement.type |
No | "hyperlane" (default), "direct", or "broadcaster" |
settlement.hyperlane |
Conditional | Required for non-seeded chains when settlement.type = "hyperlane" |
settlement.direct |
Conditional | Required when settlement.type = "direct" |
settlement.broadcaster |
Conditional | Required when settlement.type = "broadcaster" |
For each non-seeded network, provide:
nametypeinput_settler_addressoutput_settler_addressrpc_urls(at least one URL)
Optional per-network fields:
input_settler_compact_addressthe_compact_addressallocator_address
hyperlane is the default settlement type when settlement is omitted.
Intent expiry and settlement timing configuration is documented in:
docs/oracles/settlement-timing-configuration.md
The key intent_min_expiry_seconds uses the same field name across:
settlement.hyperlane.intent_min_expiry_secondssettlement.direct.intent_min_expiry_secondssettlement.broadcaster.intent_min_expiry_seconds
See config/non-seeded-networks-example.json for a full non-seeded Hyperlane example (both chain IDs are non-seeded).
Example direct settlement:
{
"networks": [
{ "chain_id": 11155420, "tokens": [] },
{ "chain_id": 84532, "tokens": [] }
],
"settlement": {
"type": "direct",
"direct": {
"dispute_period_seconds": 900,
"oracle_selection_strategy": "RoundRobin",
"oracles": {
"input": {
"11155420": ["0x7100000000000000000000000000000000000007"],
"84532": ["0x8200000000000000000000000000000000000008"]
},
"output": {
"11155420": ["0x7100000000000000000000000000000000000007"],
"84532": ["0x8200000000000000000000000000000000000008"]
}
}
}
}
}Note: Providing a solver_id makes seeding idempotent - running bootstrap again with the same config will detect existing configuration and skip seeding (unless --force-seed is used).
| Variable | Required | Default | Description |
|---|---|---|---|
REDIS_URL |
Yes | redis://localhost:6379 |
Redis connection URL |
SOLVER_PRIVATE_KEY |
Yes | - | 64-character hex private key (without 0x prefix) |
SOLVER_ID |
For loading | - | Solver ID to load from Redis (required when not seeding) |
Note: After seeding, the solver outputs the SOLVER_ID to use for subsequent runs. Set this environment variable before running without --bootstrap-config.
| Chain | Chain ID | Name |
|---|---|---|
| Optimism Sepolia | 11155420 | optimism-sepolia |
| Base Sepolia | 84532 | base-sepolia |
| Chain | Chain ID | Name |
|---|---|---|
| Optimism | 10 | optimism |
| Base | 8453 | base |
| Arbitrum | 42161 | arbitrum |
You can also seed non-seeded chain IDs with the required non-seeded network fields and settlement config.
When you run with bootstrap flags, the solver:
- Optionally loads the seed preset (testnet/mainnet) when
--seedis provided - Merges your bootstrap config with defaults
- seeded chains can reuse seed values
- non-seeded chains must provide required network bundle and settlement data
- Generates a unique
solver_id(e.g.,solver-abc123-...) - Stores the complete configuration in Redis
┌─────────────────────┐ ┌─────────────────────┐ ┌─────────────────┐
│ Optional Seeds │ │ Bootstrap Config │ │ Final Config │
│ (testnet/mainnet) │ + │ (your JSON file) │ = │ (in Redis) │
│ │ │ │ │ │
│ - Contract addrs │ │ - Chain IDs │ │ Complete │
│ - Oracle addrs │ │ - Tokens │ │ solver │
│ - Default RPCs │ │ - RPC URLs (opt) │ │ configuration │
│ - Gas settings │ │ │ │ │
└─────────────────────┘ └─────────────────────┘ └─────────────────┘
On subsequent runs (without bootstrap flags), the solver:
- Reads the
SOLVER_IDfrom environment or uses the last seeded ID - Loads the full configuration from Redis
- Starts the solver with the loaded configuration
Configuration in Redis includes version tracking:
{
"data": { /* full config */ },
"version": 1,
"updated_at": 1705849200
}Updates use optimistic locking - if another process modified the config, your update will fail with a version mismatch error.
{prefix}:config:{solver_id} → Versioned<Config>
Default prefix: oif-solver
Example: oif-solver:config:solver-abc123-def456-...
The solver ID in your environment doesn't have configuration in Redis. Either:
- Run with
--bootstrap-configto create new configuration - Check
SOLVER_IDenvironment variable matches an existing solver
You're trying to seed when configuration already exists. Use --force-seed to overwrite:
cargo run -- --seed testnet --bootstrap-config config/seed-overrides-testnet.json --force-seedEnsure your private key:
- Is exactly 64 hex characters (32 bytes)
- Does NOT include the
0xprefix - Is exported in your shell:
export SOLVER_PRIVATE_KEY=...
Check that Redis is running and accessible:
redis-cli ping
# Should return: PONGWhen running, the solver exposes these API endpoints:
| Endpoint | Method | Description |
|---|---|---|
/api/v1/tokens |
GET | List supported tokens |
/api/v1/quotes |
POST | Request a quote |
/api/v1/orders |
POST | Submit an order |
/api/v1/orders/{id} |
GET | Get order status |
The API server runs on 127.0.0.1:3000 by default.
Run the integration tests (requires Redis running locally):
cargo test --package solver-storage config_store_integration -- --ignored# 1. Start Redis
redis-server
# 2. Set environment variables
export REDIS_URL=redis://localhost:6379
export SOLVER_PRIVATE_KEY=your_private_key_here
# 3. Create bootstrap config
cat > config/my-overrides.json << 'EOF'
{
"networks": [
{
"chain_id": 11155420,
"tokens": [
{"symbol": "USDC", "address": "0x191688B2Ff5Be8F0A5BCAB3E819C900a810FAaf6", "decimals": 6}
]
},
{
"chain_id": 84532,
"tokens": [
{"symbol": "USDC", "address": "0x73c83DAcc74bB8a704717AC09703b959E74b9705", "decimals": 6}
]
}
]
}
EOF
# 4. Seed configuration
cargo run -- --seed testnet --bootstrap-config config/my-overrides.json
# 5. Subsequent runs just load from Redis
cargo run --