Chainscan — Etherscan V2 unified explorer skill
Query any major EVM chain's block explorer via the Etherscan V2 unified API, with Foundry cast as a fallback for paid-tier endpoints. One Etherscan.io API key works across every supported chain through V2 — BscScan/PolygonScan/etc. keys do not work and are no longer needed.
Etherscan V1 was deprecated 2025-08-15. V2 is the only API path going forward.
Configuration
Base URL: https://api.etherscan.io/v2/api API key: {{vault:ETHERSCAN_API_KEY}} Auth pattern: &apikey={{vault:ETHERSCAN_API_KEY}} Chain selector: &chainid=<id> (REQUIRED on every call — no default) Free tier: 3 req/sec, 100k req/day
Chain ID quick reference
Most-used chains:
| Chain | chainid | Native | Default RPC |
|---|---|---|---|
| Ethereum mainnet | 1 | ETH | https://eth.llamarpc.com |
| BSC | 56 | BNB | https://bsc-dataseed.binance.org |
| Polygon | 137 | MATIC | https://polygon-rpc.com |
| Arbitrum One | 42161 | ETH | https://arb1.arbitrum.io/rpc |
| Optimism | 10 | ETH | https://mainnet.optimism.io |
| Base | 8453 | ETH | https://mainnet.base.org |
| Avalanche C-chain | 43114 | AVAX | https://api.avax.network/ext/bc/C/rpc |
| Sepolia | 11155111 | ETH | https://ethereum-sepolia-rpc.publicnode.com |
| Base Sepolia | 84532 | ETH | https://sepolia.base.org |
| Arbitrum Sepolia | 421614 | ETH | https://sepolia-rollup.arbitrum.io/rpc |
Full list: see references/chains.md.
Free-tier endpoint availability
This is the most important table to internalize. Many endpoints are gated behind paid plans on non-Ethereum chains.
| Endpoint | ETH (1) | Polygon (137) | Arbitrum (42161) | BSC (56) | Base (8453) | OP (10) | Avalanche (43114) |
|---|---|---|---|---|---|---|---|
getabi | YES | YES | YES | YES | YES | YES | YES |
getsourcecode | YES | YES | YES | YES | YES | YES | YES |
verifysourcecode | YES | YES | YES | YES | YES | YES | YES |
checkverifystatus | YES | YES | YES | YES | YES | YES | YES |
getcontractcreation | YES | YES | YES | NO | NO | NO | NO |
balance, txlist, tokentx, getLogs, gas, prices | YES | YES | YES | NO | NO | NO | NO |
Bolded YES = available on all plans including free for that chain. So contract ABI/source and verification work everywhere; everything else needs cast on paid chains.
Etherscan V2 endpoints
Every URL adds &chainid=<CHAIN>&apikey={{vault:ETHERSCAN_API_KEY}}. Replace <CHAIN> with the chain ID from the table above.
Contract ABI
bashcurl -s "https://api.etherscan.io/v2/api?chainid=<CHAIN>&module=contract&action=getabi&address=<ADDR>&apikey={{vault:ETHERSCAN_API_KEY}}" | python3 -m json.tool
Returns result as a JSON-stringified ABI array. Pipe through python3 -c 'import sys,json; print(json.dumps(json.loads(json.load(sys.stdin)["result"]), indent=2))' to fully decode.
Verified source code
bashcurl -s "https://api.etherscan.io/v2/api?chainid=<CHAIN>&module=contract&action=getsourcecode&address=<ADDR>&apikey={{vault:ETHERSCAN_API_KEY}}" | python3 -m json.tool
Returns: SourceCode, ABI, ContractName, CompilerVersion, OptimizationUsed, Runs, ConstructorArguments, LicenseType, Proxy, Implementation. For proxies, the returned ABI is the proxy's; fetch Implementation separately for the impl ABI.
Contract creation tx (creator + creation hash)
Free on Ethereum/Polygon/Arbitrum, paid elsewhere. Max 5 addresses per call (comma-separated).
bashcurl -s "https://api.etherscan.io/v2/api?chainid=<CHAIN>&module=contract&action=getcontractcreation&contractaddresses=<ADDR1>,<ADDR2>&apikey={{vault:ETHERSCAN_API_KEY}}" | python3 -m json.tool
For paid chains, fall back to a binary-search using cast code. See "Find deployment block" below.
Transaction by hash
bashcurl -s "https://api.etherscan.io/v2/api?chainid=<CHAIN>&module=proxy&action=eth_getTransactionByHash&txhash=<TXHASH>&apikey={{vault:ETHERSCAN_API_KEY}}" | python3 -m json.tool
The
proxymodule returns raw JSON-RPC shape{jsonrpc, id, result}, not the standard{status, message, result}wrapper. Handle both shapes when parsing.
Transaction receipt (logs, status)
bashcurl -s "https://api.etherscan.io/v2/api?chainid=<CHAIN>&module=proxy&action=eth_getTransactionReceipt&txhash=<TXHASH>&apikey={{vault:ETHERSCAN_API_KEY}}" | python3 -m json.tool
Event logs
Free on Ethereum/Polygon/Arbitrum, paid elsewhere.
bashcurl -s "https://api.etherscan.io/v2/api?chainid=<CHAIN>&module=logs&action=getLogs&address=<ADDR>&fromBlock=<FROM>&toBlock=<TO>&topic0=<HASH>&apikey={{vault:ETHERSCAN_API_KEY}}" | python3 -m json.tool
Pagination: &page=1&offset=1000. Multiple topics: topic1, topic2, topic3, with topic0_1_opr=and|or for combinators.
Effective 2026-07-01, free-tier
getLogsandtxlistmax records drop from 10,000 to 1,000 per request. Paginate.
Native balance
bashcurl -s "https://api.etherscan.io/v2/api?chainid=<CHAIN>&module=account&action=balance&address=<ADDR>&tag=latest&apikey={{vault:ETHERSCAN_API_KEY}}"
Returns wei as a string. Multi-address: action=balancemulti&address=<ADDR1>,<ADDR2> (max 20).
ERC-20 token balance
bashcurl -s "https://api.etherscan.io/v2/api?chainid=<CHAIN>&module=account&action=tokenbalance&contractaddress=<TOKEN>&address=<HOLDER>&tag=latest&apikey={{vault:ETHERSCAN_API_KEY}}"
Returns raw integer (no decimals applied). Fetch decimals() separately to format.
Normal txs for an address
bashcurl -s "https://api.etherscan.io/v2/api?chainid=<CHAIN>&module=account&action=txlist&address=<ADDR>&startblock=0&endblock=99999999&page=1&offset=100&sort=desc&apikey={{vault:ETHERSCAN_API_KEY}}" | python3 -m json.tool
Use action=tokentx for ERC-20 transfers, action=tokennfttx for NFTs.
Verify contract source (POST)
bashcurl -s -X POST "https://api.etherscan.io/v2/api" \ -d "chainid=<CHAIN>" \ -d "module=contract" \ -d "action=verifysourcecode" \ -d "apikey={{vault:ETHERSCAN_API_KEY}}" \ -d "contractaddress=<ADDR>" \ -d "sourceCode=<STANDARD_JSON_INPUT>" \ -d "codeformat=solidity-standard-json-input" \ -d "contractname=<File.sol>:<ContractName>" \ -d "compilerversion=v0.8.26+commit.8a97fa7a" \ -d "optimizationUsed=1" \ -d "runs=200" \ -d "constructorArguements=<ABI_ENCODED_ARGS>" \ -d "licenseType=3"
License IDs: 1=No License, 2=Unlicense, 3=MIT, 4=GPL-2.0, 5=GPL-3.0, 6=LGPL-2.1, 7=LGPL-3.0, 8=BSD-2-Clause, 9=BSD-3-Clause, 10=MPL-2.0, 11=OSL-3.0, 12=Apache-2.0, 13=AGPL-3.0, 14=BUSL-1.1.
Check verification status
bashcurl -s "https://api.etherscan.io/v2/api?chainid=<CHAIN>&module=contract&action=checkverifystatus&guid=<GUID>&apikey={{vault:ETHERSCAN_API_KEY}}"
Verify with Forge (preferred)
bashforge verify-contract <ADDR> <ContractName> \ --chain-id <CHAIN> \ --etherscan-api-key {{vault:ETHERSCAN_API_KEY}} \ --watch
Forge handles the V2 endpoint URL automatically.
Foundry cast fallbacks (for paid endpoints)
Use these when the chain isn't on the free tier (BSC, Base, OP, Avalanche, etc.). Pass --rpc-url <RPC> from the chain table.
bash# Native balance cast balance <ADDR> --rpc-url <RPC> --ether # Contract code (existence check) cast code <ADDR> --rpc-url <RPC> | head -c 80 # "0x" if no contract # Tx + receipt cast tx <TXHASH> --rpc-url <RPC> cast receipt <TXHASH> --rpc-url <RPC> # Block / chain state cast block-number --rpc-url <RPC> cast block <BLOCK> --rpc-url <RPC> cast gas-price --rpc-url <RPC> cast nonce <ADDR> --rpc-url <RPC> # Storage slot cast storage <ADDR> <SLOT> --rpc-url <RPC> # Read calls cast call <ADDR> "name()(string)" --rpc-url <RPC> cast call <ADDR> "balanceOf(address)(uint256)" <HOLDER> --rpc-url <RPC> # Event logs (raw) cast logs --from-block <FROM> --to-block <TO> \ --address <ADDR> "Transfer(address,address,uint256)" \ --rpc-url <RPC> # By topic hash cast logs --from-block <FROM> --to-block <TO> \ --address <ADDR> --topic0 <HASH> --rpc-url <RPC> # Decoders / encoders cast 4byte-decode 0x<METHOD_ID> # selector → signature cast calldata-decode "fn(types)" 0x<DATA> cast sig "transfer(address,uint256)" # signature → selector cast keccak "Transfer(address,address,uint256)" # event topic # Unit conversions cast to-wei 1.5 ether cast from-wei <WEI> cast to-hex <DEC> cast to-dec 0x<HEX>
Find contract deployment block (binary search)
When getcontractcreation is paid on the chain, binary-search with cast code:
bash# Returns "0x" if not deployed at <BLOCK>, else has bytecode cast code <ADDR> --block <BLOCK> --rpc-url <RPC> | head -c 10
Algorithm: midpoint check, halve range based on whether code exists, until you converge to the exact deployment block. ~25 calls for any block range up to current head.
Critical gotchas
status === "1"(string) — V2 returns success as"1"not1and nottrue. Bad calls return HTTP 200 with{"status":"0","message":"NOTOK","result":"..."}. Always checkstatus === "1", never truthyresult.chainidis required. Missing it returns an error, not a default-to-Ethereum.- Old chain-specific keys (BscScan, PolygonScan) don't work on V2. Must be an Etherscan.io key.
proxymodule returns raw JSON-RPC shape{jsonrpc, id, result}, not the standard wrapper. Other modules return{status, message, result}.getsourcecodeproxies: check theProxy("1"/"0") andImplementationfields. For proxies the returned ABI is the proxy's, not the impl's.getcontractcreationcaps at 5 addresses per call. Batch larger lookups.tokenbalancereturns raw integer. Always fetchdecimals()to format.- Rate limits: 3 req/sec, 100k/day on free. Space rapid-fire calls or you'll start getting
Max calls per sec rate limit reachedstrings inresult. getLogs/txlist10k → 1k pagination cap effective 2026-07-01. Paginate now, future-self thanks you.- Native-currency price endpoints (
bnbprice,ethprice, etc.) are paid on most chains. Use CoinGecko (api.coingecko.com/api/v3/simple/price) for free.
Decision flow
When the user asks for chain data:
- Need ABI or source? → Etherscan V2 (free on every chain).
- Need a tx, receipt, balance, log, or read call? → if chain ∈ {ETH, Polygon, Arbitrum}, use V2; else use
castwith the RPC. - Verifying a contract? →
forge verify-contractis the easiest path, V2 POST is the manual fallback. - Paid endpoint on a paid chain? → use
cast(free, fast, no rate limit beyond RPC). - Native price? → CoinGecko, not the explorer.
References
references/chains.md— complete chain ID + RPC inventory (60+ chains).references/endpoints.md— every V2 endpoint with full parameter list.
Notes
- The same Etherscan.io key in this skill is also referenced by
~/.claude/skills/bscscan/SKILL.md. They share the key intentionally — V2 unified everything, so one key serves both skills. Thebscscanskill is BSC-specific; thischainscanskill is the general multi-chain version.


