npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

which-chain

v0.2.0

Published

Zero-dependency blockchain address shape detection and checksum verification - figure out which chain family a raw address string belongs to.

Readme

which-chain

Zero-dependency blockchain address shape detection. Given a raw address string, figure out which chain(s) it could belong to, validate it against a specific chain, and - for chains with a checksum scheme - verify the checksum itself.

import { detectChains, getAddressFamily, isValidAddressFor, verifyChecksum } from "which-chain";

detectChains("So11111111111111111111111111111111111111112");
// -> [{ chainId: "solana", name: "Solana", family: "solana", checksum: "unknown" }]

isValidAddressFor("TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t", "tron");
// -> true

getAddressFamily("addr1023456789acdefghjklmnpqrs");
// -> "cardano"

verifyChecksum("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", "ethereum");
// -> "valid" (EIP-55 mixed-case checksum)

Install

npm install which-chain

Shape detection, plus optional checksum verification

which-chain's primary job is checking whether a string is shaped like a valid address for a chain (correct prefix, character set, length) using regular expressions - no cryptography, no dependencies. On top of that, for chains with a well-known checksum scheme, it can also verify the checksum itself using small pure-JS implementations of SHA-256, Keccak-256, base58check and bech32/bech32m - still zero dependencies, no cryptographic library required.

Every DetectResult (and verifyChecksum(address, chainId)) carries a checksum field: "valid", "invalid", or "unknown". "unknown" means "not checked" (either the chain has no checksum scheme this package implements, or this specific address has no checksum data to check - e.g. an all-lowercase EVM address) - it is not evidence the address is wrong, so don't treat it as a rejection.

Checksum coverage today: EIP-55 for every EVM chain, base58check for Bitcoin/Litecoin/Dogecoin/Tron/Tezos, and bech32/bech32m for Bitcoin/Litecoin segwit, Cardano, and the Cosmos-family bech32 chains. Everything else (Solana, TON, XRPL, Polkadot, NEAR, Hedera, Kaspa, Stellar, Algorand, Filecoin, Bitcoin Cash, Aptos/Sui/Starknet) has no checksum scheme implemented yet and always reports "unknown" - not a curve/checksum validation gap you should assume is safe to ignore, just not yet covered.

Standard EVM chains are still indistinguishable by address shape - checksums don't help here, since every EVM chain shares the exact same address format. Ethereum, BSC, Base, Arbitrum, Polygon, and every other standard EVM chain all use the exact same 0x + 40 hex character format. detectChains() will correctly return all of them for any well-formed 0x... address - that's not a bug, it's a fundamental limit of shape-only detection. If you already know which chain you're expecting, use isValidAddressFor(address, chainId) instead of trying to read the chain off of detectChains()'s first result.

Base58 chains overlap too, but checksums can now break some of those ties. Solana addresses are an unconstrained 32-44 character base58 string, broad enough to also match plenty of valid Tron, Bitcoin, Litecoin and XRPL addresses at the same lengths:

detectChains("TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t"); // a real Tron address
// -> [
//   { chainId: "solana", ..., checksum: "unknown" },  // Solana has no checksum scheme - can't be ruled out by shape alone
//   { chainId: "tron", ..., checksum: "valid" },       // but only Tron's base58check actually verifies
// ]

getAddressFamily() would only return "solana" here (it just returns the first match, and match order isn't a likelihood ranking) - that's exactly why it exists as a quick convenience helper, not the primary API. Prefer detectChains() (to see every possibility, and each one's checksum status) or isValidAddressFor/verifyChecksum (when you already know, or want to confirm, the chain).

API

detectChains(address: string): DetectResult[]

Returns every chain whose address pattern matches, each as { chainId, name, family, checksum }, where checksum is "valid" | "invalid" | "unknown". Returns [] if nothing matches or the input is empty/blank.

getAddressFamily(address: string): Family | null

Returns the shape family of the first match (e.g. "evm", "solana", "bech32"), or null if nothing matches. If you need every possible family/chain match, use detectChains instead.

isValidAddressFor(address: string, chainId: string): boolean

Checks the address's shape against one specific chain, by id or alias (e.g. "ethereum" or "eth", "bsc" or "bnb"). Not affected by checksum validity - use verifyChecksum for that.

verifyChecksum(address: string, chainId: string): "valid" | "invalid" | "unknown"

Checks the address's checksum against one specific chain (or alias). Returns "unknown" for an unrecognized chain id, a shape-invalid address, or a chain/address with no checksum to check.

verifyChecksum("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed", "ethereum"); // -> "valid"
verifyChecksum("0x5aaeb6053F3E94C9b9A09f33669435E7Ef1BeAed", "ethereum"); // -> "invalid" (wrong casing)
verifyChecksum("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed", "ethereum"); // -> "unknown" (all-lowercase, no checksum to check)

listChains(): ChainDefinition[]

Returns every chain currently known to the library (built-in + anything registered via registerChain).

registerChain(definition: ChainDefinition): void

Add a chain this package doesn't ship with yet, or override a built-in one by reusing its id. Pass a verifyChecksum function too if the chain has a checksum scheme you want detectChains/verifyChecksum to check.

import { registerChain } from "which-chain";

registerChain({
  id: "my-chain",
  name: "My Chain",
  family: "evm",
  pattern: {
    full: /^mychain_[a-z0-9]{32}$/,
    partial: /^mychain_[a-z0-9]{0,32}$/,
  },
});

Supported chains

| Family | Chains | Checksum | | --- | --- | --- | | evm | Ethereum, BSC, Base, Arbitrum, Avalanche, Polygon, Optimism, Fantom, Gnosis, Cronos, Blast, Linea, Scroll, zkSync, Metis, Boba, Immutable, Worldchain, Mode, Berachain, Hyperliquid, PulseChain, Abstract, Aleph Zero, ApeChain, Beam, Ink, Robinhood, Sonic, Sei | EIP-55 | | evm-extended-hex | Aptos, Sui, Starknet | - | | solana | Solana | - | | tron | Tron | base58check | | ton | TON | - | | xrpl | XRP Ledger | - | | bech32 | Cosmos Hub, Osmosis, Injective, Celestia | bech32 | | cardano | Cardano | bech32 | | polkadot | Polkadot | - | | near | NEAR | - | | hedera | Hedera | - | | kaspa | Kaspa | - | | bitcoin-like | Bitcoin, Litecoin, Dogecoin | base58check (+ bech32/bech32m for segwit) | | stellar | Stellar | - | | algorand | Algorand | - | | filecoin | Filecoin | - | | cashaddr | Bitcoin Cash | - | | tezos | Tezos | base58check |

Missing a chain you need? Open an issue or PR - adding one is usually just a new pattern in src/families/ plus an entry in src/chains.ts, or use registerChain() at runtime without forking the package.

License

MIT