Metadata
The fields
| Field | Type | Description |
|---|---|---|
key | ChainKey | Canonical class key |
name | string | Display name |
symbol | string | Native token symbol |
decimals | number? | Native currency decimal places |
type | ChainType | Blockchain family |
bip44 | number? | BIP-44 / SLIP-0044 coin type |
chainId | string? | EVM chain ID in hexadecimal |
caip2 | string? | CAIP-2 identifier |
magic | string? | P2P magic bytes, wire order |
pow | PowAlgorithm? | Proof-of-work algorithm |
explorer | string | Block explorer base URL |
rpcDefault | string? | Default public RPC endpoint |
key is read off the class, chain.key and Bitcoin.key are the same string. type is the family the class belongs to: evm, utxo, solana, stellar, xrpl, move, ton, tron, octra, arweave or monero. EVM and Move set it for their subclasses, every other chain declares it itself.
Optional fields stay empty when the chain has no registered value. Octra has no BIP-44 coin type and no CAIP-2 namespace, so both are undefined rather than invented. eCash and Decred have a coin type but no CAIP-2 identifier. Only EVM chains carry a chainId, and only some chains ship a public RPC worth defaulting to. The tools print an absent coin type or CAIP-2 as none, because a value that simply vanishes reads as "not shown" and invites the caller to supply one from memory.
chainId and the reference in caip2 encode the same number twice, so a test checks them against each other. Linea shipped a testnet id against a mainnet CAIP-2 until that test existed.
Decimals
decimals is the exponent in 1 whole native unit = 10^decimals base units. It belongs to the currency, not the address family. eCash is the useful counterexample: XEC has two decimal places despite sharing Bitcoin's UTXO ancestry, and assuming eight for every UTXO chain would get XEC amounts badly wrong. Avalanche here means AVAX on the C-Chain; this metadata doesn't describe its X and P chains.
create("bitcoin").decimals; // 8
getChain("xec").decimals; // 2
This isn't a token's precision or a UI rounding preference, and an RPC may already return amounts in whole units. Every built-in chain declares decimals. Custom classes may leave it undefined, which means unknown, never a default of 18. 0 is a valid value for an indivisible currency. chains info and chains_lookup print unknown when the field is absent, --json omits it.
These references were checked on 2026-09-05, Arc on 2026-09-18, Dogecoin on 2026-09-23, Bitcoin Cash, Bitcoin SV, Bitcoin Gold, Dash and Zcash on 2026-09-24. Tests pin the values independently of the classes, and no network request is needed at runtime or during tests.
| Chain | Decimals | Reference |
|---|---|---|
| Ethereum, Base, Arbitrum, Optimism, Polygon, BNB Chain, Avalanche C-Chain, Fantom, Gnosis, Linea, zkSync, Scroll, Berachain, Arc | 18 | ethereum-lists/chains, nativeCurrency.decimals in eip155-{1,8453,42161,10,137,56,43114,250,100,59144,324,534352,80094,5042}.json; on Arc that is native USDC, the ERC-20 view of the same balance has 6 |
| Bitcoin | 8 | Bitcoin Core COIN, 100,000,000 satoshis |
| Litecoin | 8 | Litecoin COIN, 100,000,000 |
| Pepecoin | 8 | Pepecoin COIN, 100,000,000; native PEP, not an ERC-20 token |
| eCash | 2 | eCash build documentation, 100 satoshis per XEC |
| Cardano | 6 | Cardano denominations, 1,000,000 lovelace per ADA |
| Solana | 9 | Solana account structure, 1,000,000,000 lamports per SOL |
| Stellar | 7 | Stellar asset precision, 10,000,000 stroops per XLM |
| XRP Ledger | 6 | XRP currency format, 1,000,000 drops per XRP |
| Aptos | 8 | AptosCoin initialization, decimals = 8 |
| Sui | 9 | SUI module, 1,000,000,000 mist per SUI |
| TON | 9 | TON Core conversion, 1,000,000,000 nano units per TON |
| TRON | 6 | TRX denominations, 1,000,000 sun per TRX |
| Octra | 6 | Octranomics, 1,000,000 operational units per OCT |
| Arweave | 12 | Arweave debugging guide, 1,000,000,000,000 Winston per AR |
| Monero | 12 | Monero configuration, CRYPTONOTE_DISPLAY_DECIMAL_POINT = 12 |
| Decred | 8 | Decred AtomsPerCoin, 100,000,000 atoms |
| Dogecoin | 8 | Dogecoin COIN, 100,000,000 |
| Bitcoin Cash | 8 | Bitcoin Cash Node COIN, 100,000,000 satoshis |
| Bitcoin SV | 8 | SV Node COIN, 100,000,000 satoshis |
| Bitcoin Gold | 8 | Bitcoin Gold COIN, 100,000,000 satoshis |
| Dash | 8 | Dash Core COIN, 100,000,000 duffs |
| Zcash | 8 | zcashd COIN, 100,000,000 zatoshis |
Coin types
bip44 is the SLIP-0044 coin type, the number that goes into m/44'/coin'/…. All fourteen EVM chains repeat 60, Ethereum's, which is what wallets actually derive with. Decred is 42, not its legacy 20. Octra has none registered and the field says so instead of borrowing one. Deriving keys from it belongs in @agntn/keys, not here.
Magic bytes
magic is the four bytes every P2P message opens with, written as lowercase hex in the order they cross the wire. Every message a Bitcoin node sends you starts with f9beb4d9. Send one under other bytes and the node disconnects. learn me a bitcoin has the long version.
Only chains that kept Bitcoin's wire protocol have one. That's eleven of them. Cardano, Monero and the account chains frame their messages differently, so the field stays undefined there. Cardano's "network magic" is a different thing too, a number checked during the handshake, not a prefix on every message.
The value is mainnet's. A chain class here describes mainnet, and testnet and regtest move the bytes anyway.
create("bitcoin").magic; // "f9beb4d9"
getChain("doge").magic; // "c0c0c0c0"
create("ethereum").magic; // undefined
Two traps. Bitcoin Cash picked e3e1f3e8 in 2017, and eCash and Bitcoin SV kept it when they split off. So the bytes alone won't tell you which of the three you're talking to. The same nodes still write Bitcoin's f9beb4d9 at the start of every block in blk*.dat. That's diskMagic, the field here is netMagic. Decred declares 0xd9b400f9 as a number and writes it little-endian, so the wire reads f900b4d9, and that's what the field holds.
Each value was read on 2026-09-24 from the mainnet params in the node's own source. Tests pin all eleven.
| Chain | Magic | Reference |
|---|---|---|
| Bitcoin | f9beb4d9 | Bitcoin Core chainparams.cpp, pchMessageStart |
| Litecoin | fbc0b6db | Litecoin chainparams.cpp, pchMessageStart |
| Pepecoin | c0a0f0e0 | Pepecoin chainparams.cpp, pchMessageStart |
| Dogecoin | c0c0c0c0 | Dogecoin chainparams.cpp, pchMessageStart |
| Bitcoin Cash | e3e1f3e8 | Bitcoin Cash Node chainparams.cpp, netMagic |
| eCash | e3e1f3e8 | Bitcoin ABC chainparams.cpp, netMagic |
| Bitcoin SV | e3e1f3e8 | SV Node chainparams.cpp, netMagic |
| Bitcoin Gold | e1476d44 | Bitcoin Gold chainparams.cpp, pchMessageStart |
| Dash | bf0c6bbd | Dash Core chainparams.cpp, pchMessageStart |
| Zcash | 24e92764 | zcashd chainparams.cpp, pchMessageStart; Zebra agrees |
| Decred | f900b4d9 | dcrd wire/protocol.go, MainNet CurrencyNet = 0xd9b400f9, read little-endian by wire/common.go |
Proof of work
pow names what a miner grinds. Mostly that's a hash of the block header, and the block counts once it lands under the target. Equihash is a puzzle instead: the header carries a solution, and only then does its SHA-256d face the target. Either way it's the one algorithm the whole chain agrees on. Pool software and mining hardware are sorted by it: an ASIC built for sha256d can't mine Litecoin.
create("zcash").pow; // "equihash-200-9"
getChain("xmr").pow; // "randomx"
create("ethereum").pow; // undefined
Twelve chains here mine. Ethereum left proof of work in 2022, and Cardano and most account chains never had it. Two are harder. Arweave does mine, but each round is one RandomX hash and then SHA-256 over chunks the miner actually stores. Octra's proof of useful work is encrypted computation, not a hash to grind. Neither fits in one string, so both stay undefined.
Equihash has one more catch. It's a family, not a function, and (n, k) decide how much memory a solution costs. Zcash runs 200,9. Bitcoin Gold started there and moved to 144,5 in 2018 to shake off the Zcash ASICs. A bare "equihash" would put both under one name, so the parameters are part of the value.
The value is today's mainnet algorithm. Decred switched from BLAKE-256 to BLAKE3 with DCP-0011, Monero went from CryptoNight to RandomX in 2019. Old blocks still verify under the old hash, the field only says what the next one needs.
Each value was read on 2026-09-24 from the node's own header check. Tests pin all twelve.
| Chain | pow | Reference |
|---|---|---|
| Bitcoin | sha256d | Bitcoin Core primitives/block.cpp, GetHash |
| Bitcoin Cash | sha256d | Bitcoin Cash Node primitives/block.cpp, GetHash |
| eCash | sha256d | Bitcoin ABC primitives/block.cpp, GetHash |
| Bitcoin SV | sha256d | SV Node primitives/block.cpp, GetHash |
| Litecoin | scrypt | Litecoin primitives/block.cpp, GetPoWHash |
| Dogecoin | scrypt | Dogecoin primitives/pureheader.cpp, GetPoWHash |
| Pepecoin | scrypt | Pepecoin primitives/pureheader.cpp, GetPoWHash |
| Dash | x11 | Dash Core primitives/block.cpp, HashX11 |
| Zcash | equihash-200-9 | zcashd chainparams.cpp, nEquihashN, nEquihashK |
| Bitcoin Gold | equihash-144-5 | Bitcoin Gold chainparams.cpp, nEquihashNnew, nEquihashKnew |
| Decred | blake3 | dcrd wire/blockheader.go, PowHashV2 |
| Monero | randomx | Monero cryptonote_tx_utils.cpp, rx_slow_hash |