Walletless On-Chain State Reads Using Foundry Cast
Ethereum読み取り専用アクセス是一项面向实际任务的技能,主要用于Foundryの cast コマンドを使用してウォレットなしでEthereumブロックチェーンの状態を読み取る方法;ブロック情報、コントラクト状態、イベントログ、ENS解決の実装ガイドです;
ブロック情報取得;基本的なブロック検査;ブロック範囲分析;コントラクト状態読み取り;基本的なコントラクト呼び出し。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。
从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。该技能适合用于一次性任务,也可以接入自动化工作流,与其他技能或上层代理配合完成更完整的业务链路;在组合使用时,应明确每一步的输入输出关系,并避免不同步骤之间出现参数冲突。
使用 Foundry 的 cast 命令,在无需钱包的情况下读取 Ethereum 区块链状态。本指南涵盖区块信息查询、合约状态读取、事件日志检索以及 ENS 解析等实用场景。
# 安装 Foundry curl -L https://foundry.paradigm.xyz | bash foundryup # 验证安装 cast --version
# 设置环境变量(写入 ~/.bashrc 或 ~/.zshrc) export ETH_RPC_URL="https://eth-mainnet.alchemyapi.io/v2/YOUR-API-KEY" export POLYGON_RPC_URL="https://polygon-mainnet.g.alchemy.com/v2/YOUR-API-KEY" export ARB_RPC_URL="https://arb-mainnet.g.alchemy.com/v2/YOUR-API-KEY" # 使用免费 RPC(含速率限制) export ETH_RPC_URL="https://rpc.ankr.com/eth" export POLYGON_RPC_URL="https://rpc.ankr.com/polygon" # 验证配置 cast client --rpc-url $ETH_RPC_URL
#!/bin/bash
# block-inspector.sh
# 获取最新区块号
get_latest_block() {
echo "最新区块号:"
cast block-number --rpc-url $ETH_RPC_URL
}
# 查询区块基本信息
inspect_block() {
local block_number="$1"
echo "=== 区块 $block_number 基本信息 ==="
cast block "$block_number" --rpc-url $ETH_RPC_URL
}
# 查询含交易的完整区块详情
inspect_block_full() {
local block_number="$1"
echo "=== 区块 $block_number 详细信息(含交易)==="
cast block "$block_number" --full --rpc-url $ETH_RPC_URL
}
# 区块统计信息
block_stats() {
local block_number="$1"
echo "=== 区块 $block_number 统计信息 ==="
# 交易数量
local tx_count="$(cast block "$block_number" --rpc-url $ETH_RPC_URL | jq -r '.transactions | length')"
echo "交易数量: $tx_count"
# Gas 消耗量
local gas_used="$(cast block "$block_number" --rpc-url $ETH_RPC_URL | jq -r '.gasUsed')"
echo "Gas 消耗量: $gas_used"
# 时间戳
local timestamp="$(cast block "$block_number" --rpc-url $ETH_RPC_URL | jq -r '.timestamp')"
echo "区块时间: $(date -d @$((timestamp)) +'%Y-%m-%d %H:%M:%S')"
}
# 示例用法
get_latest_block
inspect_block "latest"
block_stats "latest"
# block-range-analyzer.sh
analyze_block_range() {
local start_block="$1"
local end_block="$2"
echo "=== 区块范围分析: $start_block - $end_block ==="
local total_tx=0
local total_gas=0
for ((block=$start_block; block<=$end_block; block++)); do
echo "正在处理区块 $block..."
local block_data="$(cast block "$block" --rpc-url $ETH_RPC_URL)"
local tx_count="$(echo "$block_data" | jq -r '.transactions | length')"
local gas_used="$(echo "$block_data" | jq -r '.gasUsed')"
total_tx=$((total_tx + tx_count))
total_gas=$((total_gas + gas_used))
echo " TX: $tx_count, Gas: $gas_used"
done
echo ""
echo "=== 汇总 ==="
echo "总交易数: $total_tx"
echo "总 Gas 消耗量: $total_gas"
echo "平均每区块交易数: $((total_tx / (end_block - start_block + 1)))"
}
# 示例用法
analyze_block_range 19000000 19000010
#!/bin/bash
# contract-reader.sh
# 检查 ERC20 代币余额
check_erc20_balance() {
local token_address="$1"
local wallet_address="$2"
echo "=== ERC20 余额检查 ==="
echo "代币地址: $token_address"
echo "钱包地址: $wallet_address"
# 调用 balanceOf(address) 函数
local balance="$(cast call "$token_address" \
"balanceOf(address)(uint256)" \
"$wallet_address" \
--rpc-url $ETH_RPC_URL)"
echo "余额: $balance"
# 获取代币名称
local name="$(cast call "$token_address" \
"name()(string)" \
--rpc-url $ETH_RPC_URL)"
# 获取代币符号
local symbol="$(cast call "$token_address" \
"symbol()(string)" \
--rpc-url $ETH_RPC_URL)"
# 获取小数位数
local decimals="$(cast call "$token_address" \
"decimals()(uint8)" \
--rpc-url $ETH_RPC_URL)"
echo "代币名称: $name"
echo "符号: $symbol"
echo "小数位数: $decimals"
# 转换为人类可读格式
local human_balance="$(cast to-dec "$balance")"
local scaled_balance="$(echo "scale=6; $human_balance / 10^$decimals" | bc -l)"
echo "显示余额: $scaled_balance $symbol"
}
# 获取 Uniswap V3 流动性池信息
check_uniswap_pool() {
local pool_address="$1"
echo "=== Uniswap V3 流动性池信息 ==="
echo "池地址: $pool_address"
# 获取池基础信息
local token0="$(cast call "$pool_address" "token0()(address)" --rpc-url $ETH_RPC_URL)"
local token1="$(cast call "$pool_address" "token1()(address)" --rpc-url $ETH_RPC_URL)"
local fee="$(cast call "$pool_address" "fee()(uint24)" --rpc-url $ETH_RPC_URL)"
echo "Token0: $token0"
echo "Token1: $token1"
echo "手续费: $(cast to-dec "$fee") (0.01% = 100)"
# 获取当前流动性与价格
local liquidity="$(cast call "$pool_address" "liquidity()(uint128)" --rpc-url $ETH_RPC_URL)"
echo "流动性: $(cast to-dec "$liquidity")"
# 获取 slot0 信息(价格、tick 等)
local slot0="$(cast call "$pool_address" "slot0()(uint160,int24,uint16,uint16,uint16,uint8,bool)" --rpc-url $ETH_RPC_URL)"
echo "Slot0: $slot0"
}
# ENS 反向解析
resolve_ens() {
local address="$1"
echo "=== ENS 解析 ==="
echo "地址: $address"
# 执行 ENS 名称解析
local ens_name="$(cast lookup-address "$address" --rpc-url $ETH_RPC_URL 2>/dev/null || echo "无")"
echo "ENS 名称: $ens_name"
}
# 示例用法
check_erc20_balance "0xA0b86a33E6441b04B9b73f9251e9b49Cd2B3a64" "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" # USDC, Vitalik
check_uniswap_pool "0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8" # USDC/ETH 0.3%
resolve_ens "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
#!/bin/bash
# event-log-searcher.sh
# 搜索 Transfer 事件
search_transfer_events() {
local contract_address="$1"
local from_block="$2"
local to_block="$3"
local sender="${4:-}"
local receiver="${5:-}"
echo "=== Transfer 事件搜索 ==="
echo "合约地址: $contract_address"
echo "区块范围: $from_block - $to_block"
# Transfer(address,address,uint256) 事件签名
local transfer_sig="0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"
# 构建基础搜索命令
local cmd="cast logs --rpc-url $ETH_RPC_URL"
cmd="$cmd --address $contract_address"
cmd="$cmd --from-block $from_block"
cmd="$cmd --to-block $to_block"
cmd="$cmd $transfer_sig"
# 添加过滤器
if [[ -n "$sender" ]]; then
cmd="$cmd $sender"
fi
if [[ -n "$receiver" ]]; then
if [[ -z "$sender" ]]; then
cmd="$cmd '' $receiver" # 若未指定 sender,则传空字符串
else
cmd="$cmd $receiver"
fi
fi
echo "执行命令: $cmd"
# 执行日志查询并解析结果
eval "$cmd" | jq -r '.[] | "区块: (.blockNumber), TX: (.transactionHash), 日志索引: (.logIndex)"'
}
# 通用事件搜索
search_custom_events() {
local contract_address="$1"
local event_signature="$2"
local from_block="$3"
local to_block="$4"
echo "=== 自定义事件搜索 ==="
echo "签名: $event_signature"
cast logs \
--address "$contract_address" \
--from-block "$from_block" \
--to-block "$to_block" \
"$event_signature" \
--rpc-url $ETH_RPC_URL \
| jq '.'
}
# DEX 交易分析
analyze_dex_trades() {
local pool_address="$1"
local from_block="$2"
local to_block="$3"
echo "=== DEX 交易分析 ==="
# Swap 事件 (Uniswap V3: Swap(address,address,int256,int256,uint160,uint128,int24))
local swap_sig="0xc42079f94a6350d7e6235f29174924f928cc2ac818eb64fed8004e115fbcca67"
cast logs \
--address "$pool_address" \
--from-block "$from_block" \
--to-block "$to_block" \
"$swap_sig" \
--rpc-url $ETH_RPC_URL \
| jq -r '.[] | "交易: 区块 (.blockNumber), TX (.transactionHash), Gas 消耗: (.gasUsed)"'
}
# 示例用法
search_transfer_events "0xA0b86a33E6441b04B9b73f9251e9b49Cd2B3a64" "19000000" "19000100" # USDC transfers
search_custom_events "0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984" "0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925" "19000000" "19000050" # UNI Approval
#!/bin/bash
# ens-resolver.sh
# 从 ENS 名称解析地址
resolve_ens_to_address() {
local ens_name="$1"
echo "=== ENS → 地址解析 ==="
echo "ENS 名称: $ens_name"
# 基础地址解析
local address="$(cast resolve-name "$ens_name" --rpc-url $ETH_RPC_URL)"
echo "地址: $address"
# 获取内容哈希(如 IPFS)
local content_hash="$(cast call 0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63 \
"contenthash(bytes32)(bytes)" \
"$(cast namehash "$ens_name")" \
--rpc-url $ETH_RPC_URL 2>/dev/null || echo "无")"
echo "内容哈希: $content_hash"
# 获取文本记录
echo "文本记录:"
for key in "email" "url" "avatar" "description" "notice" "keywords" "com.github" "com.twitter"; do
local value="$(cast call 0x231b0Ee14048e9dCcD1d247744d114a4EB5E8E63 \
"text(bytes32,string)(string)" \
"$(cast namehash "$ens_name")" \
"$key" \
--rpc-url $ETH_RPC_URL 2>/dev/null || echo "")"
if [[ -n "$value" && "$value" != '""' ]]; then
echo " $key: $value"
fi
done
}
# 从地址解析 ENS 名称
resolve_address_to_ens() {
local address="$1"
echo "=== 地址 → ENS 解析 ==="
echo "地址: $address"
local ens_name="$(cast lookup-address "$address" --rpc-url $ETH_RPC_URL 2>/dev/null || echo "无")"
echo "ENS 名称: $ens_name"
# 检查是否为主域名
if [[ "$ens_name" != "无" ]]; then
local reverse_address="$(cast resolve-name "$ens_name" --rpc-url $ETH_RPC_URL)"
if [[ "$reverse_address" == "$address" ]]; then
echo "主域名: 是"
else
echo "主域名: 否($reverse_address)"
fi
fi
}
# ENS 域名详细信息
ens_domain_info() {
local ens_name="$1"
echo "=== ENS 域名详细信息 ==="
# 所有者信息
local owner="$(cast call 0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e \
"owner(bytes32)(address)" \
"$(cast namehash "$ens_name")" \
--rpc-url $ETH_RPC_URL)"
echo "所有者: $owner"
# 注册商信息(仅限 .eth 域名)
if [[ "$ens_name" == *.eth ]]; then
local registrar="0x57f1887a8BF19b14fC0dF6Fd9B2acc9Af147eA85"
local token_id="$(cast keccak "$(echo -n "${ens_name%.eth}")")"
local registrant="$(cast call "$registrar" \
"ownerOf(uint256)(address)" \
"$token_id" \
--rpc-url $ETH_RPC_URL 2>/dev/null || echo "无")"
echo "注册人: $registrant"
# 到期时间
local expires="$(cast call "$registrar" \
"nameExpires(uint256)(uint256)" \
"$token_id" \
--rpc-url $ETH_RPC_URL 2>/dev/null || echo "0")"
if [[ "$expires" != "0" ]]; then
echo "到期时间: $(date -d @$((expires)) +'%Y-%m-%d %H:%M:%S')"
fi
fi
}
# 示例用法
resolve_ens_to_address "vitalik.eth"
resolve_address_to_ens "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
ens_domain_info "uniswap.eth"
#!/bin/bash
# abi-decoder.sh
# 解码函数调用
decode_function_call() {
local tx_hash="$1"
local abi_file="$2" # JSON 文件或 Etherscan 签名
echo "=== 函数调用解码 ==="
echo "TX: $tx_hash"
# 获取交易详情
local tx_data="$(cast tx "$tx_hash" --rpc-url $ETH_RPC_URL)"
local input_data="$(echo "$tx_data" | jq -r '.input')"
local to_address="$(echo "$tx_data" | jq -r '.to')"
echo "目标地址: $to_address"
echo "输入数据: ${input_data:0:50}..."
# 提取 4 字节选择器
local selector="${input_data:2:8}"
echo "函数选择器: 0x$selector"
# 从 4byte.directory 查询函数名
local function_sig="$(curl -s "https://www.4byte.directory/api/v1/signatures/?hex_signature=0x$selector" | jq -r '.results[0].text_signature')"
echo "函数签名: $function_sig"
# 若提供 ABI 文件则进行解码
if [[ -f "$abi_file" ]]; then
cast 4byte-decode "$input_data" --abi-path "$abi_file"
fi
}
# 解码事件日志
decode_event_log() {
local tx_hash="$1"
local log_index="$2"
local abi_file="$3"
echo "=== 事件日志解码 ==="
# 获取日志条目
local logs="$(cast receipt "$tx_hash" --rpc-url $ETH_RPC_URL | jq ".logs[$log_index]")"
local topics="$(echo "$logs" | jq -r '.topics[]')"
local data="$(echo "$logs" | jq -r '.data')"
echo "主题: $topics"
echo "数据: $data"
# 解析事件签名
local event_sig="$(echo "$topics" | head -1 | cut -c3-)"
local event_name="$(curl -s "https://www.4byte.directory/api/v1/event-signatures/?hex_signature=0x$event_sig" | jq -r '.results[0].text_signature')"
echo "事件签名: $event_name"
# ABI 解码(Foundry 对日志解码支持有限,需额外工具辅助)
if [[ -f "$abi_file" ]]; then
echo "详细解码需配合 ABI 文件及额外工具完成"
fi
}
# 常用函数选择器字典
common_selectors() {
echo "=== 常用函数选择器 ==="
cat << 'EOF'
0xa9059cbb: transfer(address,uint256)
0x095ea7b3: approve(address,uint256)
0x23b872dd: transferFrom(address,address,uint256)
0x70a08231: balanceOf(address)
0x18160ddd: totalSupply()
0xdd62ed3e: allowance(address,address)
0x40c10f19: mint(address,uint256)
0x42966c68: burn(uint256)
0x7ff36ab5: swapExactETHForTokens(uint256,address[],address,uint256)
0x38ed1739: swapExactTokensForTokens(uint256,uint256,address[],address,uint256)
EOF
}
# 示例用法
common_selectors
# decode_function_call "0x..." "./erc20.abi.json"
#!/bin/bash
# defi-portfolio-checker.sh
check_defi_portfolio() {
local wallet="$1"
echo "=== DeFi 投资组合: $wallet ==="
# ETH 余额
local eth_balance="$(cast balance "$wallet" --rpc-url $ETH_RPC_URL)"
echo "ETH: $(cast to-ether "$eth_balance") ETH"
# 主流代币余额
local tokens=(
"0xA0b86a33E6441b04B9b73f9251e9b49Cd2B3a64:USDC:6"
"0xdAC17F958D2ee523a2206206994597C13D831ec7:USDT:6"
"0x6B175474E89094C44Da98b954EedeAC495271d0F:DAI:18"
"0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984:UNI:18"
)
for token in "${tokens[@]}"; do
IFS=':' read -r address symbol decimals <<< "$token"
local balance="$(cast call "$address" "balanceOf(address)(uint256)" "$wallet" --rpc-url $ETH_RPC_URL)"
local human_balance="$(echo "scale=4; $(cast to-dec "$balance") / 10^$decimals" | bc -l)"
echo "$symbol: $human_balance"
done
}
# 示例用法
check_defi_portfolio "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
包含钱包管理与交易发送功能的完整 cast CLI 指南,可在 kairyuu.net/exchange/ 交易中获取。
相关专题
热门下载
相关下载
精品课程
共6课时 | 54.7万人学习
共89课时 | 134.1万人学习
共49课时 | 82.6万人学习
最新文章