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.

11 min readUpdated 8 August 2026blockchains, evm, utxo, rpc, custom-chain

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

  1. 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.

  2. 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.

  3. Restart the backend. Provider instances are constructed at module load, so nothing you just wrote is in effect yet.

    pm2 restart backend
  4. Run the diagnostics. Admin → Ecosystem → Blockchains → Requirements, select the chain, and run its test. Fix what it names before moving on.

  5. 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.

Shared BlockCypher token for every UTXO chain. Effectively required for DOGE and DASH — anonymous limits are roughly 3 requests/second and 100/hour, which cannot sustain deposit polling.
Bitcoin network. mainnet, testnet, testnet4, testnet3 or signet. "testnet" is an alias of testnet4.
Comma-separated esplora API roots that replace the built-in public mirror list entirely. Only set this for a self-hosted mempool/esplora deployment — the provider already fails over across the public mirrors.

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.

  1. 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.

  2. Enable the row. Admin → Ecosystem → Blockchains lists the seeded chains with their product IDs. Enabling flips ecosystem_blockchain.status.

  3. Add the chain's variables — each family has its own names, listed in the environment reference.

  4. 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_NETWORK selects the public cluster and anything other than mainnet or testnet — including unset, and including the plausible-looking mainnet-beta — falls through to devnet. SOLANA_RPC_URL is read only by an admin cost estimate.
  • Tron throws at construction on a bad network. TRON_NETWORK must be mainnet, shasta or nile; anything else is a total outage, not a degradation. On mainnet, TRON_API_KEY is 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_version fails at startup the whole chain is disabled. monerod must 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.

Registers a new EVM chain and activates it in the live registry
Probes RPC, WebSocket, chain ID and explorer for a candidate chain before you save it

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 .env key 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.
Full per-chain requirements report plus the global configuration groups
Runs live read-only probes against a chain's endpoints and returns per-flow readiness

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.