Supported blockchains
The four chain families Ecosystem custodies — built-in EVM, UTXO, licensed non-EVM and operator-defined custom EVM — how to enable one, and the diagnostics console that names the missing variable.
Ecosystem groups chains into four families. Which family a chain belongs to
decides how it is enabled, what it needs in .env, whether it needs a separate
licence, and how deposits reach a customer.
| Family | Chains | Enabled by |
|---|---|---|
| Built-in EVM | ETH, BSC, POLYGON, FTM, OPTIMISM, ARBITRUM, BASE, CELO, RSK, HECO, CRONOS, MO | Setting its .env variables |
| UTXO | BTC, LTC, DOGE, DASH | Setting its .env variables |
| Licensed non-EVM | SOL, TRON, TON, XMR | Buying the blockchain addon, activating its licence, enabling the row |
| Custom EVM | Anything you add | Admin → Ecosystem → Custom EVM Chains |
A chain being "supported" means the addon can derive addresses on it, watch for deposits, and sign withdrawals. It does not mean it is on — every chain is off until you configure it, and the platform ships with none configured.
The naming convention
Built-in chains read their configuration from .env using a mechanical pattern.
Get the pattern right and there is nothing else to learn per chain.
ETH_NETWORK="mainnet"
ETH_MAINNET_RPC="https://ethereum-rpc.publicnode.com"
ETH_MAINNET_RPC_WSS="wss://..."
ETH_EXPLORER_API_KEY="..."<SYMBOL>_NETWORK selects the network. The runtime then reads
<SYMBOL>_<NETWORK>_RPC and <SYMBOL>_<NETWORK>_RPC_WSS — the network name
uppercased — for that network only. <SYMBOL>_EXPLORER_API_KEY is the per-chain
Etherscan key: it is tried before the global ETHERSCAN_API_KEY, not instead
of it, so a stale per-chain key no longer shadows a working global one.
The valid network names are per chain and not guessable:
| Chain | Networks | Chain IDs |
|---|---|---|
| ETH | mainnet, sepolia |
1, 11155111 |
| BSC | mainnet, testnet |
56, 97 |
| POLYGON | matic, amoy |
137, 80002 |
| FTM | mainnet, testnet |
250, 4002 |
| OPTIMISM | mainnet, sepolia |
10, 11155420 |
| ARBITRUM | mainnet, sepolia |
42161, 421614 |
| BASE | mainnet, sepolia |
8453, 84532 |
| CELO | mainnet, sepolia |
42220, 11142220 |
| RSK | mainnet, testnet |
30, 31 |
| HECO | mainnet, testnet |
128, 256 |
| CRONOS | mainnet |
25 |
| MO | mainnet, testnet |
7860, 7862 |
Polygon's mainnet is called matic, not mainnet. Setting
POLYGON_NETWORK="mainnet" means the runtime reads POLYGON_MAINNET_RPC, which
is not a valid network, and provider initialisation fails with "Chain ID not
found".
ARBIRUM_MAINNET_RPC — missing the second T — is still read by the admin
balance endpoint and the legacy health check, but not by the real provider path.
Set only the typo and health reports Arbitrum as Up while every deposit and
withdrawal on it is broken. Always set ARBITRUM_MAINNET_RPC.
alfajores is not a supported CELO network. CELO_ALFAJORES_RPC is read by
nothing.
Enabling a built-in EVM chain
-
Pick the network and add the variables to the project root
.env.BSC_NETWORK="mainnet" BSC_MAINNET_RPC="https://bsc-dataseed.binance.org" BSC_MAINNET_RPC_WSS="wss://bsc-ws-node.nariox.org:443"The WSS endpoint is optional. Without it, token-deposit monitors fall back to HTTP polling rather than realtime events.
-
Add a transaction-history provider key — unless the chain is keyless. Native-deposit detection and the admin token-holders view both go through the explorer providers. Most chains have a free keyless provider behind them and need nothing here; BSC, FTM, CRONOS, HECO and Polygon's Amoy testnet are the ones that do not. An Etherscan V2 key still buys the richest data on the chains its free tier covers:
ETHERSCAN_API_KEY="..."The key may hold several comma-separated keys, and the same is true of every other provider key. See Explorer coverage is not uniform for which chains need what.
-
Restart the backend. Provider instances are constructed at module load, so nothing you just wrote is in effect yet.
pm2 restart backend -
Run the diagnostics. Admin → Ecosystem → Blockchains → Requirements, select the chain, and run its test. Fix what it names before moving on.
-
Create the master wallet for the chain — see Master wallets. Until one exists, withdrawals on the chain cannot be signed.
Explorer coverage is not uniform
One Etherscan V2 key does not cover every chain. Its free tier was cut on 2025-11-22 and is now paid-only for BSC (56 and 97), OP Mainnet (10 and 11155420), Base (8453 and 84532) and Avalanche; Gnosis moves to paid on 2026-09-01. FTM (chain id 250) and CRONOS (25) are not on the V2 chainlist at all — Fantom migrated to Sonic — and HECO is effectively sunset.
That is why the provider order is decided per chain rather than globally. Each chain leads with a provider that is actually free for it, and any keyless provider that can serve the chain is appended to the end of whatever order applies, so the chain still has a last resort:
| Chain | Built-in order | Works with no keys at all |
|---|---|---|
| ETH, POLYGON, ARBITRUM, CELO | Etherscan, Blockscout, then the keyed fallbacks | Yes — except Polygon Amoy |
| BASE, OPTIMISM | Blockscout first, Etherscan behind it | Yes |
| RSK | Blockscout, then Etherscan | Yes |
| MO | Etherscan against MO's own explorer host, then Blockscout if you self-host one | Yes |
| FTM | Ankr, Moralis, Covalent, Etherscan | No |
| BSC | NodeReal, Ankr, Moralis, Covalent, Etherscan | No |
| CRONOS, HECO | The generic order — but no provider indexes either chain | No |
Five chains have no keyless option at all. There is no hosted Blockscout
instance and no Routescan coverage for BSC (56 and 97), FTM (250 and 4002),
CRONOS (25), HECO (128 and 256) or Polygon's Amoy testnet (80002). BSC is the one
of them where a keyed provider is the normal answer for a production install: on
mainnet set NODEREAL_API_KEY, which is free for BSC; on testnet NodeReal and
Ankr do not index chain id 97 at all, so use MORALIS_API_KEY or
COVALENT_API_KEY. A paid Etherscan plan also works, and a self-hosted instance
named in BSC_BLOCKSCOUT_HOST is the only way to make BSC keyless.
RSK is served keylessly on both networks. It goes through the same provider
dispatcher as every other chain, and Blockscout resolves the host from the chain
id — 30 to rootstock.blockscout.com, 31 to rootstock-testnet.blockscout.com —
so RSK_NETWORK="testnet" reads testnet. Earlier releases called a hardcoded
mainnet Blockscout endpoint whose response shape the parser rejected; that is
fixed.
The RPC block scan underneath all of this is a floor, not a substitute. When the explorer path fails, the native-deposit monitor switches to walking blocks over the chain's own RPC — at most 50 blocks per poll, forward only. It catches deposits arriving from then on; it does not recover the 24 hours of lookback the explorer path gives.
Setting keys, and pinning an order
The built-in defaults already lead each chain with a provider that is free for it, so on most installations the answer is set nothing. Reach for the following only when the diagnostics console tells you to.
One key, everywhere. The common case. An Etherscan V2 key covers every chain its free tier still includes, and is ignored on the ones it does not:
ETHERSCAN_API_KEY="your_key"Several keys, rotated. Any provider key may hold a comma-separated list. The dispatcher moves to the next key when one is rejected, out of quota, or on a plan that excludes the chain — so a revoked key costs one attempt rather than the chain:
ETHERSCAN_API_KEY="key_one,key_two,key_three"A key for one chain only. Prefix any provider key with the chain symbol. The chain-scoped keys are tried first and the global key stays behind them as a spare, so a paid key can serve the one chain that needs it without you buying a plan for the rest:
ETHERSCAN_API_KEY="free_key"
BSC_ETHERSCAN_API_KEY="paid_key"
NODEREAL_API_KEY="your_key"
BSC_NODEREAL_API_KEY="a_different_key"Every provider takes both forms — <CHAIN>_ANKR_API_KEY and ANKR_API_KEY,
<CHAIN>_MORALIS_API_KEY and MORALIS_API_KEY, and so on. <CHAIN>_EXPLORER_API_KEY
is the older name for the Etherscan one and still works.
Pinning the order for a chain. Only worth doing when you know something the defaults do not — that your Moralis plan is faster than your Etherscan one, say:
TRANSACTION_PROVIDERS_BSC="nodereal,covalent"TRANSACTION_PROVIDERS sets one order for every chain at once and is the blunter
instrument; a per-chain variable beats it. Whichever applies, any keyless
provider that can serve the chain is still appended to the end as a last resort.
Set TRANSACTION_PROVIDERS_STRICT="true" if you would rather a pinned order be
the whole story and have the chain fail when it is exhausted.
Raising a keyless rate limit. Blockscout and Routescan serve without a credential, but the anonymous tier is throttled per IP — an installation polling many deposit addresses will meet it. Both accept an optional key that lifts the limit, and neither stops working without one:
BLOCKSCOUT_API_KEY="your_key"Giving a keyless-less chain a keyless provider. The only way, and it means running the instance yourself:
BSC_BLOCKSCOUT_HOST="blockscout.example.com"Every one of these needs pm2 restart backend before it takes effect, and the
full variable list — including the per-attempt timeout and record limit — is in
the environment reference.
Checking it worked
Admin → Ecosystem → Blockchains → Requirements, select the chain, run its test. The explorer check lists every provider in the order the runtime will try them, and says which one is actually serving the chain, where that order came from, and how many keys each provider has. A provider marked cooling down is one the circuit breaker is skipping after a recent failure — the tooltip says why. no key on a keyless provider is impossible by construction; if you see a provider skipped for a missing key, that is the one to set.
UTXO chains
Bitcoin, Litecoin, Dogecoin and Dash use a provider abstraction rather than an
RPC URL. <SYMBOL>_NODE selects it.
| Chain | Default provider | What actually works |
|---|---|---|
| BTC | mempool |
mempool, blockcypher, node (self-hosted Bitcoin Core) |
| LTC | mempool |
mempool (litecoinspace.org), blockcypher |
| DOGE | blockcypher |
BlockCypher only |
| DASH | blockcypher |
BlockCypher only |
The factory falls back silently. An unrecognised value uses the chain
default; node on anything but BTC falls back to BlockCypher, because
self-hosted node support is Bitcoin-only; mempool on DOGE or DASH falls back
to BlockCypher too.
Two things to know before you point Bitcoin anywhere but mainnet. BlockCypher
only serves mainnet and testnet3, so BTC_NETWORK=testnet4 with
BTC_NODE=blockcypher cannot work. And deposit addresses are generated for
the network configured at the time — flip BTC_NETWORK after users have
addresses and those addresses are invalid and must be regenerated.
Running a self-hosted Bitcoin Core node unlocks realtime zero-confirmation
detection over ZMQ. The presence of BTC_ZMQ_RAWTX is the on/off switch for the
whole ZMQ service, and it only initialises when BTC_NODE=node. Setting it
under any other provider does nothing.
Licensed non-EVM chains
Solana, Tron, TON and Monero are separate products. Each is gated twice, and both gates must pass.
-
Buy and activate the blockchain addon. Activation writes
lic/<productId>.lic— an encrypted, machine-bound file. Without it the status toggle refuses with a 403. -
Enable the row. Admin → Ecosystem → Blockchains lists the seeded chains with their product IDs. Enabling flips
ecosystem_blockchain.status. -
Add the chain's variables — each family has its own names, listed in the environment reference.
-
Restart, then run the diagnostics.
The seeded product IDs are Solana 54514052, Tron 54577641, Monero 54578959
and TON 55715370. Every one of them ships with status: false.
Beyond the licence, each of these chains needs its service module to be present in the install. If the addon code was never extracted, the diagnostics report "Chain service installed: no" and every flow on that chain is dead regardless of the licence.
A few per-chain facts that cost people days:
- Solana has no custom RPC.
SOL_NETWORKselects the public cluster and anything other thanmainnetortestnet— including unset, and including the plausible-lookingmainnet-beta— falls through to devnet.SOLANA_RPC_URLis read only by an admin cost estimate. - Tron throws at construction on a bad network.
TRON_NETWORKmust bemainnet,shastaornile; anything else is a total outage, not a degradation. On mainnet,TRON_API_KEYis effectively mandatory — the deposit monitor stops itself after ten consecutive errors, and anonymous TronGrid quotas will get you there. - TON's anonymous rate limit is about one request per second, which throttles both deposit polling and the ten-attempt withdrawal confirmation loop. Set the Toncenter API key for the active network.
- Monero's wallet RPC is a hard gate. If
get_versionfails at startup the whole chain is disabled.monerodmust also be fully synchronised — withdrawals fail at fee estimation against an unsynced daemon.
Custom EVM chains
Any EVM-compatible chain can be added from data alone, with no code change: Admin → Ecosystem → Blockchains → Custom EVM Chains.
You supply the symbol, display name, EVM chain ID, native currency, RPC URL and optionally a WebSocket URL, explorer URL and explorer API key. Creating the row hydrates the chain into the live registry immediately and backfills its native coin as an Ecosystem token — a native currency has no smart contract, so it cannot be added through the token import flow and is created here instead.
Three guards apply. You cannot shadow a built-in symbol (ETH, BSC, SOL,
BTC and the rest are reserved), symbols must be unique, and two chains may not
claim the same EVM chain ID — providers pin the ID at construction, so a
duplicate means one of them is misconfigured.
The chain's .env keys are then managed automatically: <SYMBOL>_NETWORK,
<SYMBOL>_<NETWORK>_RPC, <SYMBOL>_<NETWORK>_RPC_WSS and
<SYMBOL>_EXPLORER_API_KEY are written into process.env from the database at
boot. Editing them by hand in .env is pointless — they are rewritten on every
reload.
Custom chains do not inherit any global provider key — not
ETHERSCAN_API_KEY, not ANKR_API_KEY, none of them. A first-party key sent to
a third-party explorer turns a working keyless request into an "Invalid API Key"
rejection. What they do get is the chain's own explorer URL, used keylessly,
plus a hosted Blockscout or Routescan instance if one exists for their chain id.
With no explorer configured and no keyless instance, native deposits are found by
RPC block scanning only.
The requirements and diagnostics console
Admin → Ecosystem → Blockchains → Requirements is the page that answers "why is this chain not working". For every chain it lists:
- every
.envkey the runtime actually reads, marked required or optional, with the condition under which an optional key becomes required, and whether it is currently set (secrets are never displayed, only their presence); - the non-environment prerequisites — vault unlocked, master wallet present and enabled, active tokens on the current network, licence valid;
- chain-specific warnings, including the name traps above and every silent provider fallback;
- keys that are dead — read by no code path and safe to remove.
The test result is deliberately strict: it passes only when every check passed or was skipped and no platform flow is reported broken. An RPC that answers is not a pass if the vault is locked or the master wallet is missing, because a customer still cannot withdraw.