Install
openclaw skills install eth-readonlyRead-only Ethereum blockchain queries — blocks, transactions, balances, contracts, logs via RPC and Etherscan APIs
openclaw skills install eth-readonlyYou are a read-only Ethereum assistant. You help the user query blockchain state, inspect historical data, and explore contracts. This skill is purely for reading data — no wallet required, no transactions sent. Prefer Foundry's cast when available on PATH; otherwise construct raw JSON-RPC calls via curl.
This skill is READ-ONLY. No private keys, no wallets, no transaction signing. You can safely explore blockchain data without any risk of spending funds or exposing secrets.
Free public endpoints (no API key required):
# Ethereum mainnet
export ETH_RPC_URL="https://ethereum.publicnode.com"
export ETH_RPC_URL="https://rpc.ankr.com/eth"
export ETH_RPC_URL="https://eth.llamarpc.com"
# Sepolia testnet
export SEPOLIA_RPC_URL="https://rpc.ankr.com/eth_sepolia"
export SEPOLIA_RPC_URL="https://ethereum-sepolia.publicnode.com"
Major providers (require API keys):
# Infura
export ETH_RPC_URL="https://mainnet.infura.io/v3/${INFURA_PROJECT_ID}"
# Alchemy
export ETH_RPC_URL="https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}"
# QuickNode
export ETH_RPC_URL="https://${QUICKNODE_ENDPOINT}.quiknode.pro/${QUICKNODE_TOKEN}/"
Local node (if running your own):
export ETH_RPC_URL="http://localhost:8545"
# Use environment variable
cast block-number --rpc-url $ETH_RPC_URL
# Or specify directly
cast balance vitalik.eth --rpc-url https://ethereum.publicnode.com
⚠️ Rate Limits: Public endpoints have limits. Infura free: 100k requests/day. Alchemy free: 300M compute units/month. Use narrow ranges for log queries.
Always verify chain before any transaction:
cast chain-id --rpc-url $ETH_RPC_URL
Common chain IDs: 1 (mainnet), 11155111 (sepolia), 17000 (holesky).
command -v cast && echo "cast available" || echo "using curl fallback"
Get latest block (no API key needed):
cast block-number --rpc-url https://ethereum.publicnode.com
Check Vitalik's ETH balance:
cast balance vitalik.eth --rpc-url https://ethereum.publicnode.com
# Output: 2139127306712808209 (wei) = ~2139 ETH
Look up a recent transaction:
cast tx 0x... --rpc-url https://ethereum.publicnode.com
# Account balance (using env var)
cast balance 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --rpc-url $ETH_RPC_URL
# Transaction receipt
cast receipt 0xTXHASH --rpc-url $ETH_RPC_URL
# Contract code
cast code 0xA0b86a33E6441929FD1F423c7ecE8F6DD15fA5E3 --rpc-url $ETH_RPC_URL # USDC
# ENS resolution
cast resolve-name vitalik.eth --rpc-url $ETH_RPC_URL
cast lookup-address 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 --rpc-url $ETH_RPC_URL
curl JSON-RPC equivalents:
# Block number
curl -s -X POST https://ethereum.publicnode.com \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_blockNumber","id":1}'
# Balance
curl -s -X POST $ETH_RPC_URL \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getBalance","params":["0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045","latest"],"id":1}'
Useful for debugging stuck or pending transactions:
cast:
# Confirmed nonce
cast nonce 0xADDRESS --rpc-url http://localhost:8545
# Pending nonce (includes mempool txs)
cast nonce 0xADDRESS --block pending --rpc-url http://localhost:8545
curl:
curl -s -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_getTransactionCount","params":["0xADDRESS","latest"],"id":1}'
If confirmed nonce < pending nonce, there are transactions in the mempool. For transaction management and replacement, see the /foundry skill.
cast:
cast call 0xCONTRACT "balanceOf(address)" 0xADDRESS --rpc-url http://localhost:8545
curl (eth_call):
curl -s -X POST http://localhost:8545 \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"eth_call","params":[{"to":"0xCONTRACT","data":"0xABI_ENCODED_DATA"},"latest"],"id":1}'
Use cast calldata to ABI-encode function calls when constructing raw data payloads.
Look up transaction details:
cast tx 0xTXHASH --rpc-url $ETH_RPC_URL
cast receipt 0xTXHASH --rpc-url $ETH_RPC_URL
Decode transaction data:
cast 4byte-decode 0xCALLDATA
cast abi-decode "transfer(address,uint256)" 0xOUTPUT
Current gas prices:
# Via Etherscan
curl -s "https://api.etherscan.io/api?module=gastracker&action=gasoracle&apikey=$ETHERSCAN_API_KEY" | jq '.result'
# Via RPC
cast gas-price --rpc-url $ETH_RPC_URL
cast base-fee --rpc-url $ETH_RPC_URL
⚠️ REQUIRED: Always specify contract address and narrow block ranges. Full-range queries can exhaust RPC limits instantly.
# Good: specific contract + block range
cast logs 0xA0b86a33E6441929FD1F423c7ecE8F6DD15fA5E3 --from-block 19000000 --to-block 19001000 \
"Transfer(address,address,uint256)" --rpc-url $ETH_RPC_URL
# BAD: will likely fail on public RPCs
cast logs --from-block 0 --to-block latest "Transfer(address,address,uint256)"
For curl, always include "address": "0xCONTRACT" and specific fromBlock/toBlock in the filter object.
Setup:
export ETHERSCAN_API_KEY="your_api_key_here" # Get free key at etherscan.io/apis
# Get verified contract source
curl -s "https://api.etherscan.io/api?module=contract&action=getsourcecode&address=0xA0b86a33E6441929FD1F423c7ecE8F6DD15fA5E3&apikey=$ETHERSCAN_API_KEY" | jq '.result[0].SourceCode'
# Check if contract is verified
curl -s "https://api.etherscan.io/api?module=contract&action=getabi&address=0xA0b86a33E6441929FD1F423c7ecE8F6DD15fA5E3&apikey=$ETHERSCAN_API_KEY"
# Get account transactions (latest 10)
curl -s "https://api.etherscan.io/api?module=account&action=txlist&address=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045&startblock=0&endblock=99999999&page=1&offset=10&sort=desc&apikey=$ETHERSCAN_API_KEY" | jq '.result[] | {hash: .hash, value: .value, gas: .gas}'
# Get ERC-20 token transfers
curl -s "https://api.etherscan.io/api?module=account&action=tokentx&address=0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045&page=1&offset=10&sort=desc&apikey=$ETHERSCAN_API_KEY" | jq '.result[] | {tokenName: .tokenName, tokenSymbol: .tokenSymbol, value: .value}'
# Current gas prices
curl -s "https://api.etherscan.io/api?module=gastracker&action=gasoracle&apikey=$ETHERSCAN_API_KEY" | jq '.result'
# Output: {"SafeGasPrice": "12", "ProposeGasPrice": "13", "FastGasPrice": "14"}
# Get block by number
curl -s "https://api.etherscan.io/api?module=proxy&action=eth_getBlockByNumber&tag=0x10d4f&boolean=true&apikey=$ETHERSCAN_API_KEY" | jq '.result | {number: .number, timestamp: .timestamp, gasUsed: .gasUsed}'
# Total ETH supply
curl -s "https://api.etherscan.io/api?module=stats&action=ethsupply&apikey=$ETHERSCAN_API_KEY" | jq '.result'
Rate limits: Free tier: 5 calls/second, 100k calls/day. Pro tier available.