Providers
Etherscan
The v2 API with one key for ten EVM chains and every operation. Five requests a second on the free tier. First choice whenever ETHERSCAN_API_KEY is set.
Provider
Etherscan
- ethereum
- base
- arbitrum
- optimism
- polygon
- bsc
- avalanche
- gnosis
- linea
- berachain
- Chains
- 10
- Auth
- key
- Operations
- 8 of 10
served 8 / 10
Operations
- balance
getBalanceserved - history
getTxHistoryserved - tx detail
getTxDetailserved - utxos
getUtxosabsent - pubkey
getPubkeyabsent - contract
getContractInfoserved - tokens
getTokenBalancesserved - transfers
getTokenTransfersserved - gas
getGasDataserved - block
getBlockInfoserved
Access
- Create
create("etherscan") - Import
@agntn/explorers/providers/etherscan - Host
api.etherscan.io/v2/api - Statusproviders on the docs worker
Address it
import { create } from "@agntn/explorers";
const etherscan = await create("etherscan"); // ETHERSCAN_API_KEY from the environment
await etherscan.getBalance("0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045", "base");
One key, ten chains. The provider sends the chain id with every request to api.etherscan.io/v2/api, so Base, Arbitrum, Optimism, Polygon, BSC, Avalanche, Gnosis, Linea and Berachain go through the same endpoint as Ethereum. Without the key the constructor throws AuthError before any request goes out.
What it reads
| Operation | Action |
|---|---|
| balance | account.balance |
| history | account.txlist, with startblock, endblock, sort, page, offset |
| one transaction | proxy.eth_getTransactionByHash plus the receipt for status and fee |
| contract | contract.getsourcecode, with proxy and implementation |
| token holdings | account.addresstokenbalance |
| token transfers | account.tokentx, optionally one contractaddress |
| gas | gastracker.gasoracle, in gwei |
| block | proxy.eth_getBlockByNumber |
Gotchas
- Five requests a second on the free tier, and Etherscan counts them. Past that you get a rate limit message dressed up as a normal answer; the provider waits and retries that same backend, then an automatic selection moves the read to Blockscout, once.
- On BNB Chain, Base, OP Mainnet, Avalanche and Gnosis the free plan refuses every read except contract source, and you find out at runtime. Token holdings need API Pro even on Ethereum. That's a
PlanRestrictedError, and the fallback pass tries Blockscout if it serves the chain, which for BNB Chain it doesn't. Automatic selection remembers the refusal for an hour, so on the chains Blockscout serves the next read of that kind goes there first instead of paying for the same no again. - "No transactions found" is an empty list, not an error. Etherscan phrases an empty page as a failure, which is silly, and the provider knows the phrasing.
- Amounts arrive as decimal strings and stay strings. Token decimals come with each transfer row.
Where it lives
src/providers/etherscan.ts.