Environment reference
Every environment variable the Ecosystem addon reads — vault, ScyllaDB, transaction providers, deposit monitoring and each chain family — with what breaks without it and which keys are dead.
Only the explorer and transaction-provider block below is declared in
.env.example. Every other variable on this page is added by hand to the project
root .env, and every one requires a backend restart to take effect — provider
instances and the ScyllaDB client are constructed at module load.
Admin → Ecosystem → Blockchains → Requirements shows which of these keys are currently set on your install, and its per-chain Tx history & explorer providers row is built from the runtime dispatcher itself, so it cannot disagree with what a real request does.
Vault
ScyllaDB
Ecosystem spot and futures order placement, order book and candles live here. Wallets, deposits and withdrawals do not depend on it.
Redis
Load-bearing for this addon specifically: pending deposits, balance caches, address locks and the engine lease all live in Redis. The core already requires it, so these are listed for completeness.
The built-in EVM chain pattern
For each of ETH, BSC, POLYGON, FTM, OPTIMISM, ARBITRUM, BASE,
CELO, RSK, HECO, CRONOS and MO:
| Key | Required | Purpose |
|---|---|---|
<CHAIN>_NETWORK |
Yes | Selects the network. Decides which <CHAIN>_<NETWORK>_* keys are read. Must be one of the chain's own valid names. |
<CHAIN>_<NETWORK>_RPC |
Yes | HTTP(S) JSON-RPC endpoint. Provider initialisation throws without it. |
<CHAIN>_<NETWORK>_RPC_WSS |
No | WebSocket JSON-RPC. Without it, token-deposit monitors fall back to HTTP polling. |
<CHAIN>_EXPLORER_API_KEY |
No | Per-chain Etherscan key, tried before ETHERSCAN_API_KEY rather than instead of it. <CHAIN>_ETHERSCAN_API_KEY is read after it and before the global key. |
The network segment is the network name uppercased — POLYGON_NETWORK=matic
means the runtime reads POLYGON_MATIC_RPC.
Valid network names per chain, and the chain IDs the RPC must serve, are listed in Supported blockchains.
The misspelled key — one T — is still read as a fallback by the admin balance
endpoint and the legacy health check, but never by the real provider path. Set
it alone and health reports Arbitrum as Up while deposits and withdrawals are
broken. Always set ARBITRUM_MAINNET_RPC.
Explorer and transaction-history providers
Seven providers serve EVM transaction history, native-deposit detection, token transfer lists and contract ABI lookups. They are tried in a per-chain order with automatic failover, and every configured key for a provider is rotated through before the next provider is reached.
Two of them — Blockscout and Routescan — need no credential at all, so a chain with a hosted instance keeps working with nothing set here. Across the built-in chains that covers ETH, ARBITRUM, OPTIMISM, BASE, CELO and RSK on both of their networks plus POLYGON mainnet, and MO through its own explorer host. It does not cover Polygon Amoy, BSC, FTM, CRONOS or HECO — the per-chain picture is in Explorer coverage is not uniform.
Where the order comes from
Most specific wins, and exactly one of the three applies:
| Source | When it is used |
|---|---|
TRANSACTION_PROVIDERS_<CHAIN> |
Set for that chain |
TRANSACTION_PROVIDERS |
Set, and no per-chain variable exists for this chain |
| Built-in per-chain default | Neither is set — the normal case |
Whichever wins, every keyless provider that can serve the chain and is not
already listed is appended to the end, so even a short pinned order keeps a last
resort. TRANSACTION_PROVIDERS_STRICT=true turns that off.
Unknown names are dropped with a warning naming the seven that exist:
etherscan, blockscout, routescan, ankr, moralis, covalent,
nodereal.
Keys are lists, and can be scoped to one chain
Every key variable below may hold several comma-separated keys. The dispatcher walks the list on auth, plan and rate-limit failures before giving up on the provider, so one revoked or exhausted key does not take a chain's explorer down.
Each provider also reads a chain-scoped name, and the chain-scoped list and the global list are concatenated rather than "first wins" — a per-chain paid key is preferred and the shared free key still stands behind it as a spare.
| Provider | Chain-scoped names, in order | Global |
|---|---|---|
| Etherscan | <CHAIN>_EXPLORER_API_KEY, <CHAIN>_ETHERSCAN_API_KEY |
ETHERSCAN_API_KEY |
| Ankr | <CHAIN>_ANKR_API_KEY |
ANKR_API_KEY |
| Moralis | <CHAIN>_MORALIS_API_KEY |
MORALIS_API_KEY |
| Covalent | <CHAIN>_COVALENT_API_KEY |
COVALENT_API_KEY |
| NodeReal | <CHAIN>_NODEREAL_API_KEY |
NODEREAL_API_KEY |
| Blockscout | <CHAIN>_BLOCKSCOUT_API_KEY |
BLOCKSCOUT_API_KEY |
| Routescan | <CHAIN>_ROUTESCAN_API_KEY |
ROUTESCAN_API_KEY |
A value that looks like a URL is ignored with a warning, and placeholder strings
— changeme, or anything starting your_ or < — count as not set. That is
what makes an unfilled .env.example line harmless, and it is also why a pasted
<your-key-here> reads as no key on the diagnostics page rather than as a
broken one.
A failed provider is remembered
Failures are classified, and the failing provider is then skipped for a cooldown on that chain and network: 10 minutes for a rejected key, 30 minutes for a plan rejection, 60 seconds for a rate limit, an hour for "does not index this chain", 30 seconds for a network error. The transient classes — rate limit, network error and an unclassified failure — double their cooldown on each consecutive failure, capped at 5 minutes; the deterministic ones do not grow. A key that comes back invalid or rate limited is quarantined across every chain at once, because that is a property of the key rather than of the chain it was used on.
That state is in memory, per process, and nothing in the admin panel clears it —
the only reliable reset is restarting backend and cron, which hold
separate breakers. If every provider for a chain is cooling down the dispatcher
ignores the breaker and tries them anyway, so it can never be the sole cause of
an outage.
The variables
Deposit monitoring
Per-user WebSocket monitors always run. These keys control the optional background sweep and its tuning.
UTXO chains
For BTC, LTC, DOGE and DASH:
Self-hosted Bitcoin Core, used only when BTC_NODE=node:
Solana
Tron
TON
Monero
Keys that are read by nothing
These appear in shipped .env files and get copied between installs. Removing
them changes no behaviour; keeping them wastes your time when you are debugging.
| Key | Reality |
|---|---|
XMR_WALLET_USER |
Read by no code |
XMR_WALLET_PASSWORD |
Read by no code. Wallet files are created and opened with an empty password regardless — if external tooling created them with a password, the backend cannot open them |
BTC_ZMQ_HASHBLOCK |
Parsed into config, but its socket is never connected |
LTC_NODE_HOST and siblings |
Dormant. Self-hosted node support is Bitcoin-only; the provider factory never routes to them |
LTC_ZMQ_RAWTX and siblings |
ZMQ realtime is Bitcoin-only |
CELO_ALFAJORES_RPC |
alfajores is not a supported CELO network |
SOL_<NETWORK>_RPC, XMR_<NETWORK>_RPC |
Display only — the overview badge checks their presence; the chain services never read them |
Custom EVM chains
Do not set these by hand. <CHAIN>_NETWORK, <CHAIN>_<NETWORK>_RPC,
<CHAIN>_<NETWORK>_RPC_WSS and <CHAIN>_EXPLORER_API_KEY for an
operator-defined chain are written into process.env from the
ecosystem_custom_chain table at boot and rewritten on every registry reload.
Edit the chain in Admin → Ecosystem → Custom EVM Chains instead.
Custom chains never inherit any global provider key — not ETHERSCAN_API_KEY,
not ANKR_API_KEY, none of them. A first-party key on a third-party explorer
turns a working keyless request into an "Invalid API Key" rejection, so only the
chain's own <SYMBOL>_* keys and the keyless providers apply.
Related
- Blockchains — what to do with these values
- Core environment reference — everything the platform reads outside this addon
- Troubleshooting