Configuration Reference

Configuration values prefixed YOUR_ are placeholders for your own deployment. For the public testnet use the contract reference; never mix networks or environments.

Complete reference for all bridge configuration options.

Environment Variables

Multi-Chain EVM Configuration

The bridge supports multiple EVM chains. Environment variables follow the format {CHAIN_NAME}_RPC_URL and {CHAIN_NAME}_LOCKER.

Variable Required Default Description
SEPOLIA_RPC_URL Yes - Sepolia RPC endpoint
SEPOLIA_BEACON_URL Yes - Sepolia beacon API
SEPOLIA_LOCKER Yes - Sepolia locker contract address
BASE_SEPOLIA_RPC_URL No - Base Sepolia RPC
BASE_SEPOLIA_LOCKER No - Base Sepolia locker address
# Sepolia (Primary)
SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/YOUR_KEY
SEPOLIA_BEACON_URL=https://ethereum-sepolia-beacon-api.publicnode.com
SEPOLIA_LOCKER=YOUR_SEPOLIA_LOCKER

# Base Sepolia (Optional)
BASE_SEPOLIA_RPC_URL=https://base-sepolia.infura.io/v3/YOUR_KEY
BASE_SEPOLIA_LOCKER=YOUR_CHAIN_LOCKER

Casper Network

Variable Required Default Description
CASPER_NODE_URL Yes - Casper RPC endpoint
CASPER_PUBLIC_NODE_URLS No - Comma-separated additional public/community Casper RPC endpoints. These count as the public source class for the verification diversity gate - a terminal verification verdict requires a public-class source (CSPR.cloud alone can never verify or reject an event). Configure at least one besides CASPER_NODE_URL for resilience.
CASPER_CHAIN_NAME Yes - Chain name (casper-test)
CSPR_CLOUD_RPC_URL No CSPR.cloud host CSPR.cloud RPC endpoint. Classified as the cloud source class - it can never satisfy the verification diversity gate on its own.
CASPER_ETH_CLIENT Yes - EthClient contract hash
CASPER_TOKEN_FACTORY Yes - TokenFactory contract hash
CASPER_ERC7786_GATEWAY For exposure-control contracts - Casper ERC-7786 gateway package hash. Transfers to a V18+ locker, and to an exposure-control TokenFactory, travel only through the gateways; without it the relayer signs nothing for them
CASPER_NODE_URL=https://node.testnet.casper.network
CASPER_CHAIN_NAME=casper-test
CASPER_ETH_CLIENT=YOUR_ETH_CLIENT_PACKAGE_HASH
CASPER_TOKEN_FACTORY=YOUR_TOKEN_FACTORY_PACKAGE_HASH

Relayer Keys

Variable Required Default Description
RELAYER_PRIVATE_KEY Yes - Ethereum private key (0x...)
CASPER_SECRET_KEY Yes - Path to Casper secret_key.pem
RELAYER_PRIVATE_KEY=0x1234567890abcdef...
CASPER_SECRET_KEY=/path/to/secret_key.pem

P2P Network

Variable Required Default Description
P2P_ENABLED No true Enable P2P networking
P2P_PORT_EVM2CASPER No 8080 EVM→Casper P2P port
P2P_PORT_CASPER2EVM No 8180 Casper→EVM P2P port
P2P_PEERS No - Comma-separated peer addresses
P2P_TLS_ENABLED No true Enable TLS for P2P
P2P_ALLOW_PRIVATE_PEER_ENDPOINTS No false Allow peer endpoints resolving to private/loopback addresses (otherwise rejected by the SSRF guard). Enable only for local test meshes or VPC-internal fleets - peers remain gated by mTLS + on-chain authorization.
P2P_TLS_CERT No - TLS certificate path
P2P_TLS_KEY No - TLS private key path
P2P_ENABLED=true
P2P_PORT_EVM2CASPER=8080
P2P_PORT_CASPER2EVM=8180
P2P_PEERS=10.0.1.10:8080,10.0.1.11:8080,10.0.1.12:8080
P2P_TLS_ENABLED=true
P2P_TLS_CERT=/path/to/cert.pem
P2P_TLS_KEY=/path/to/key.pem

Relayer Identity

Variable Required Default Description
RELAYER_INDEX Yes - Relayer index (0-4)
RELAYER_COUNT No 5 Total relayers
RELAYER_THRESHOLD No 3 Required signatures. Must be ≥ 2 and a strict majority of the relayer set (threshold × 2 > count) - enforced on-chain (EVM V14+ / Casper EthClient); relayers log a SECURITY warning if an on-chain threshold is a minority.
RELAYER_INDEX=0
RELAYER_COUNT=5
RELAYER_THRESHOLD=3

Fee & Minimum-Amount Safety Rails

The bridge fee is the economic brake on dust-lock relayer griefing: every lock forces all relayers to sign and pay destination-chain gas, so an unmetered lock path drains relayer gas wallets. Configuration interplay to keep in mind:

  • Every EVM route needs a positive minimumCommitmentAmount. The route policy enforces it (zero is refused when a route is configured), together with the route maximum and the domain's custody and representation ceilings. Size the minimum so that a dust commitment still pays for the relayers' work; with a zero bridge fee it is the only economic brake on lock spam.
  • Size the fee against destination gas, not just source-chain UX. The fee is flat; destination gas is variable. A 50 CSPR fee (~$0.25) against a several-dollar mainnet-Ethereum mint leaves a 10-20x asymmetry in an attacker's favor. Revisit fee levels when destination gas regimes change.
  • Zero-fee mode rejects attached value: with fee 0, lock/ burnWrapped revert on any msg.value, and Casper burn/lock_native revert on any attached CSPR. Wallet integrations must not attach value when the fee reads 0.
  • Casper fee ceiling: fee setters reject values above 10,000 CSPR (FeeExceedsMaximum) so a fat-fingered fee can't brick the bridge.
  • Token remapping caveat (update_native_token_mapping): re-pointing a CEP-18 mapping does not migrate the locked-total accounting recorded under the old token key. Reconcile totals manually after any remap (tooling tracked as a known limitation).

Submission Claims (Duplicate-Submission Prevention)

Relayers claim in-flight submissions over P2P so backup relayers don't duplicate a transaction that is dispatched but not yet final. Holds are bounded: a claim extends (never resets) the backup failover deadline, hard-capped at CLAIMS_MAX_ATTEMPTS × CLAIMS_GRACE_SECONDS from the first claim.

Variable Required Default Description
CLAIMS_ENABLED No true Disables transfer claim holds/advisories/parking; for proactive headers disables pending-transaction holds only, not cadence or election
CLAIMS_GRACE_SECONDS No 90 Hold granted per claim, from its last renewal
CLAIMS_RENEWAL_SECONDS No 30 Interval between claim renewals for our own in-flight txs
CLAIMS_MAX_ATTEMPTS No 2 Distinct tx-hash attempts honored per event (caps total hold)
CLAIMS_HASH_DEADLINE_SECONDS No 15 A hash-less claim lapses unless a tx hash arrives within this window

Deterministic on-chain rejections (e.g. unregistered token) park the affected event fleet-wide after independent on-chain verification, logged as SUBMISSION_PERMANENT_FAILURE. Parked state is in-memory: after fixing the root cause (e.g. registering the token), restart the relayers to resume.

CLAIMS_ENABLED=true
CLAIMS_GRACE_SECONDS=90
CLAIMS_MAX_ATTEMPTS=2

Proactive header freshness

Variable Required Default Description
PROACTIVE_HEADER_INTERVAL_SECONDS No 600 Restart-applied interval shared by all enabled EVM chains and relayers

Use positive whole decimal seconds only (no spaces, signs, fractions, exponent notation or leading zeroes). Unsafe integer conversions fail startup. Match the value across the fleet; mismatched coordination contexts are not adopted. Ansible uses proactive_header_interval_seconds; Helm relayer environment maps carry the same default. This setting does not change stranded-lock reconciliation.

A verified increase in EthClient latest height starts a local monotonic interval. Transfers are not rate-limited and still require their own exact header. Backups inherit a valid retained candidate, with 30-second selection and quorum rank waits. Signature-request backoff does not delay an available quorum. Failed paid attempts remain paced, and verified pending transactions can suppress dispatch after final checks. Verified success for the exact active header stops further payment and persists domain-bound occupied-height proof across restart, including interval, authorized-set and threshold changes, even while the latest-height snapshot lags. Successful outstanding local transactions retain proof before candidate selection. If old signatures no longer satisfy the current quorum, or the current quorum cannot be read during recovery, an unfolded local success additionally requires exact destination-storage confirmation. While storage is missing, mismatched or unavailable, that network's proactive publication pauses across restarts rather than risking another payment. This wait is not capped by the pending hold budget and is not disabled by CLAIMS_ENABLED=false. It ends on exact storage confirmation or coherent destination progress reaching the height, never on a lookup timeout. Peer hints cannot create this historical-recovery wait. An occupied height is not paid for again, but an old header's proof never completes a different same-height header. Signatures and old scheduling authority are not restored after configuration changes; without terminal proof, a full new interval and current quorum are required. Destination chain/package and source-chain changes isolate old proof. Suppression retires only when a coherent watermark reaches its height; later heights retain normal pacing. Missing/stale state, failed saves and rollback to older software do not guarantee durable suppression. Only a coherent higher watermark starts the next interval. Local rank clocks can differ, so duplicate fees remain possible under network delay or partitions. CLAIMS_ENABLED=false disables only proactive pending-transaction holds, not this interval or election. Proactive holds are fixed at 90 seconds with a durable 180-second cycle budget, not renewable leases. Changing authorized membership requires an operator-coordinated restart; a differing on-chain view pauses new proactive signing and dispatch without changing transfer authorization behavior.

Proactive lifecycle logs distinguish scheduling from completed work. A null candidateHeight means no candidate is currently selected, not a malformed header. phase describes the local scheduling state, and activeCycleId is null when no cycle is open. For retired work, read supersededHeight and supersededCycleId; for verified completion, read completedHeight, completedHeader, and transactionHash. completedCycleId may be null during recovery when no matching active cycle remains. Repeated completion observations for one transaction do not mean repeated payments.

Gas and Payments

Variable Required Default Description
CASPER_STANDARD_PAYMENT_AMOUNT No 45000000000 Block header submission payment (motes); sized to measured max cost +5%
CASPER_MINT_PAYMENT No 46000000000 Mint payment (motes); sized to measured max cost +5% (unused Casper 2.0 gas is refunded)
CASPER_BURN_PAYMENT No 2500000000 Burn payment (motes)
CASPER_STANDARD_PAYMENT_AMOUNT=45000000000   # 45 CSPR
CASPER_MINT_PAYMENT=46000000000       # 46 CSPR
CASPER_BURN_PAYMENT=2500000000        # 2.5 CSPR

Logging

Variable Required Default Description
LOG_LEVEL No info Log level (debug, info, warn, error)
LOG_FORMAT No json Log format (json, pretty)
LOG_LEVEL=debug
LOG_FORMAT=json

Persisted-State Retention

Variable Required Default Description
CASPER2EVM_PROCESSED_EVENTS_LIMIT No 10000 Max processed-event keys retained in Casper2Evm persisted state
EVM2CASPER_PROCESSED_EVENTS_LIMIT No 10000 Max processed-event keys retained per chain in Evm2Casper persisted state

Retention caps bound persisted-state growth. Events trimmed from local state remain protected by the on-chain processed-event guards, which are the authoritative replay defense; raise these limits if your deployment restarts frequently and you want a larger local dedup window.

CASPER2EVM_PROCESSED_EVENTS_LIMIT=10000
EVM2CASPER_PROCESSED_EVENTS_LIMIT=10000

Monitoring

Variable Required Default Description
METRICS_ENABLED No true Enable Prometheus metrics
METRICS_PORT No 9080 Metrics endpoint port
METRICS_ENABLED=true
METRICS_PORT=9080

API Server

Variable Required Default Description
API_ENABLED No false Enable API server
API_PORT No 3001 API server port
API_HOST No 0.0.0.0 API bind address
API_ENABLED=true
API_PORT=3001
API_HOST=0.0.0.0

Chain Configuration

Multi-Chain Setup

For multi-chain deployments, configure each chain:

# Sepolia (Chain ID: 11155111)
CHAIN_SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/KEY
CHAIN_SEPOLIA_LOCKER=0x...
# Exposure-control contracts only: the chain's ERC-7786 gateway proxy (both directions)
CHAIN_SEPOLIA_GATEWAY=0x...
CHAIN_SEPOLIA_CONFIRMATIONS=64
CHAIN_SEPOLIA_FINALITY_MODE=finalized

# Base Sepolia (Chain ID: 84532)
CHAIN_BASE_SEPOLIA_RPC_URL=https://sepolia.base.org
CHAIN_BASE_SEPOLIA_LOCKER=0x...
CHAIN_BASE_SEPOLIA_CONFIRMATIONS=64
CHAIN_BASE_SEPOLIA_FINALITY_MODE=finalized

Finality Settings

EVM source blocks must pass both the configured protocol-native block tag and the confirmation-depth floor. RPC errors or unsupported tags fail closed; the worker does not automatically fall back to depth-only processing.

Variable Default Description
FINALITY_CONFIRMATIONS 64 Global confirmation floor; each chain enforces the stricter of this value and its per-chain setting
CHAIN_<CHAIN_NAME>_CONFIRMATIONS Chain default Per-chain depth floor, for example CHAIN_SEPOLIA_CONFIRMATIONS
CHAIN_<CHAIN_NAME>_FINALITY_MODE finalized Protocol tag to query: finalized or safe; depth-only is an explicit emergency compatibility mode
FINALIZED_TAG_TTL_MS 12000 Per-chain cache lifetime for protocol-finality tag lookups, in milliseconds
CHAIN_<CHAIN_NAME>_FINALITY_MAX_REGRESSION 30 min of blocks (ceil(1800 / blockTime), e.g. 900 on Base, 150 on Ethereum) Deepest drop, in blocks, a fresh tag reading may show below the per-process high-water mark before the chain fails closed

Concurrent lookups share one refresh per chain. Lookup failures remain fail-closed, without using expired cache data.

In finalized mode the worker keeps a per-chain, per-process high-water mark of the tag height. On OP Stack chains the finalized tag is per-node derived state, so a load-balanced RPC pool routinely answers a few hundred blocks below the previous reading even though nothing was reorged. A finalized block cannot un-finalize, so a lower reading within CHAIN_<CHAIN_NAME>_FINALITY_MAX_REGRESSION is logged at warn (Finality tag reading below high-water mark - keeping mark) and the ceiling stays at the mark. A drop deeper than the bound cannot be explained by derivation lag: the worker logs at error, discards the mark, and treats the chain as not-final until a later, distinct successful reading re-bootstraps it. Concurrent lookups that share one RPC response all receive the same decision. The mark lives only in process memory and resets on restart. The confirmation-depth floor is applied on top and is unaffected.

safe mode keeps no high-water mark. The OP Stack safe head can be reorged by an L1 reorg, so a lower safe reading is authoritative and lowers the ceiling.

Finality tag observation regressed warns when a valid block hash changes at the same height. Finality tag reading below high-water mark - keeping mark warns when the returned height decreases within the bound. Both are evidence of an inconsistent RPC view, not proof of a reorg. The logs include both observations and a credential-free provider vendor label; other means the vendor is not recognized. Existing confirmation-depth requirements remain unchanged.

Chain Chain Default (global floor applies) Block Time
Ethereum Sepolia 6 ~12s
Base Sepolia 64 ~2s
Polygon Amoy 15 ~2s

Use depth-only only when an RPC serves neither finalized nor safe. The worker logs a warning at startup whenever this emergency mode is configured.

Configuration File

Alternatively, use a config.json file:

{
  "chains": {
    "sepolia": {
      "chainId": 11155111,
      "rpcUrl": "https://sepolia.infura.io/v3/KEY",
      "lockerAddress": "0x...",
      "confirmations": 64
    },
    "base-sepolia": {
      "chainId": 84532,
      "rpcUrl": "https://sepolia.base.org",
      "lockerAddress": "0x...",
      "confirmations": 64
    }
  },
  "casper": {
    "nodeUrl": "https://node.testnet.casper.network",
    "chainName": "casper-test",
    "ethClient": "hash-...",
    "tokenFactory": "hash-..."
  },
  "relayer": {
    "index": 0,
    "count": 5,
    "threshold": 3
  },
  "p2p": {
    "enabled": true,
    "ports": {
      "eth2casper": 8080,
      "casper2eth": 8180
    },
    "tls": {
      "enabled": true,
      "cert": "/path/to/cert.pem",
      "key": "/path/to/key.pem"
    }
  }
}

Load with:

bridge-cli --config /path/to/config.json start

Validation

Validate configuration before starting:

bridge-cli config validate

Output:

Configuration validation:
✓ Ethereum RPC responsive
✓ Base RPC responsive
✓ Casper RPC responsive
✓ Relayer key valid
✓ Casper key valid
✓ Contract addresses verified
✓ P2P configuration valid
✓ Data directory writable

Configuration is valid!

Example Configurations

Single Relayer (Development)

SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/KEY
SEPOLIA_LOCKER=YOUR_SEPOLIA_LOCKER
CASPER_NODE_URL=https://node.testnet.casper.network
RELAYER_PRIVATE_KEY=0x...
CASPER_SECRET_KEY=./keys/secret_key.pem
P2P_ENABLED=false
LOG_LEVEL=debug

Multi-Relayer (Production)

SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/KEY
SEPOLIA_LOCKER=YOUR_SEPOLIA_LOCKER
CASPER_NODE_URL=https://node.testnet.casper.network
RELAYER_PRIVATE_KEY=aws:secretsmanager:bridge/relayer/0/eth_key
CASPER_SECRET_KEY=/opt/bridge/keys/secret_key.pem
RELAYER_INDEX=0
RELAYER_COUNT=5
RELAYER_THRESHOLD=3
P2P_ENABLED=true
P2P_PEERS=10.0.1.11:8080,10.0.1.12:8080,10.0.1.13:8080,10.0.1.14:8080
P2P_TLS_ENABLED=true
LOG_LEVEL=info
METRICS_ENABLED=true

Note: Relayers use file-based JSON persistence in the data/ directory. No database configuration is required for relayer operation.

results matching ""

    No results matching ""