eth_getLogs 与代币转账 API:ERC-20 转账历史怎么查
查询合约事件日志用 eth_getLogs,已索引的 ERC-20 与 ERC-721 转账历史用代币转账 API,支持按地址或按代币合约读取,使用游标分页,超出覆盖范围时返回 422,已被裁剪的历史返回 4444。
查询钱包历史或核对 ERC-20 转账时,从代币转账 API开始;需要合约事件日志时使用 eth_getLogs。开发者与 AI Agent 可通过同一套链上数据 API 查询已索引的地址转账记录。钱包资产教程组合代币余额、转账历史与元数据,Data API 参考定义请求参数与响应格式。
这篇帮你完成什么任务
- 查询合约事件日志:携带 key 调用 RPC,限定区块跨度,用于监控或日志回填。
- 查询已索引的 ERC-20 转账历史:通过链上数据 API 按地址或代币合约读取转账记录,使用游标分页并核对覆盖范围。
两种读取日志与转账的方式
eth_getLogs 是 JSON-RPC 方法,通过 JSON-RPC 端点返回区块日志。Data API 则通过两个按链划分的端点提供代币转账历史:
GET /{chain}/addresses/{address}/transfers——与某个地址相关的转账。GET /{chain}/tokens/{token}/transfers——某个代币合约的转账。
两者使用同一个 API key,并按方法权重以 CU 计量(见下方权重表)。选哪一种,取决于数据有多新、是否需要指定区块窗口,以及如何翻页。
eth_getLogs 受到的限制
eth_getLogs 受公开的 GET /v1/chains 响应中逐链公布的各项限制约束:
- 区块跨度:
max_logs_block_range是单次eth_getLogs请求允许跨越的最大区块数。该值因链而异——请从GET /v1/chains读取(链列表见支持的链),不要写死在代码里。超过该链上限时返回 JSON-RPC 错误-32602 eth_getLogs block range too large(不计费)。 - 节点同步:当某条链的节点未同步时,
eth_getLogs返回-32010(不计费)。 - 状态窗口:
GET /v1/chains中的state_window_blocks所描述的状态窗口只作用于状态类方法(如eth_call、eth_getBalance),不作用于eth_getLogs。 - 节点历史裁剪:区块与日志查询不受状态窗口限制,但受节点保留历史的限制;已被裁剪的数据返回
4444 pruned history unavailable(不计费)。
过滤字段 fromBlock、toBlock 缺省或为 null 时按 latest 处理。
历史扫描超出单次请求范围时,按 eth_getLogs 分块查询指南 拆分包含两端的区块区间,并在当前分块成功后再推进。
通过 HTTP 调用 eth_subscribe 返回 -32601 method not available。在 /v1/chains 中 ws 为 true 的链上,可以通过 WebSocket 使用 eth_subscribe(见支持的链);其他情况请轮询 eth_getLogs 查询最新区块。
Data API 转账接口提供什么
两个端点的必填参数不同:
| 端点 | standard | 区块窗口 |
|---|---|---|
GET /{chain}/addresses/{address}/transfers | 必填:erc20 或 erc721。erc1155 返回 422 no_coverage | from_block 与 to_block 均必填。结果按 (block_number, log_index) 降序排列。direction(in、out 或 any,默认 any)按方向过滤,token 可选,用于限定单个合约。 |
GET /{chain}/tokens/{token}/transfers | 必填:erc20、erc721 或 erc1155 | from_block 与 to_block 可选。缺省 to_block 时默认取 as_of_block;显式传入高于它的 to_block 或 from_block 会直接返回硬 409 not_indexed_yet,没有 clamp 逃逸。 |
分页
两个端点都使用游标分页(keyset pagination):
limit默认 50;超过 500 会被收敛为 500,0或非整数返回400 bad_request。- 返回
limit条记录的页面可能包含next_cursor,即使已经没有更多记录。继续使用返回的游标,直到该字段缺失;最后一次读取可能返回空的data数组。没有游标时,该字段整个省略,不会返回null。 - 把返回的
next_cursor原样作为cursor传回即可取下一页。游标只对签发它的链、端点和查询参数有效。
覆盖范围与最终性
对 GET /{chain}/tokens/{token}/transfers,覆盖范围按所请求 standard 对应的代币转账数据集计算,而不是只看链的起点。当该数据集有记录的构建覆盖起点更晚时,其下界可能高于链的 coverage.from_block。完全早于该下界的窗口返回 422 no_coverage;起点早于该下界、或未提供 from_block 的窗口,会按数据集实际提供的范围返回,并标记 meta.coverage = "partial"。meta.as_of_block 是已完整写入的最新区块(写入水位),并不证明从下界到它之间的每个区块都已索引。地址端点仍然要求同时提供 from_block 与 to_block;不要把这条代币端点的下界规则套用到所有转账路由。哪些链提供该数据集见支持的链。
在从旧到新的历史回填中,已回填尾部与实时起点之间的缺口不会被检测到:完全落在这个缺口里的窗口仍可能返回 200 和空 data 数组。HTTP 成功、空结果、遍历完所有游标,或单单一个覆盖字段,都不能证明整段范围完整。请对照预期数据或自己的核对结果验证完整性。
每条转账数据包含 token、standard、from、to、block_number、block_timestamp、tx_hash、tx_index、log_index。ERC-20 额外有 amount;ERC-721 额外有 token_id;ERC-1155 额外有 operator、token_id、value、batch_index。
该选哪一个
| 典型任务 | 更适合 | 理由 |
|---|---|---|
| 最近几百个区块的事件 | eth_getLogs | 只要区间不超过该链的 max_logs_block_range,一次请求即可覆盖最近一段区块。 |
| 某地址的历史转账 | GET /{chain}/addresses/{address}/transfers | 按地址维度查询,支持 from_block/to_block 窗口、direction 与 token 过滤,并用游标翻页;结果提供截至 as_of_block 的数据。 |
| 某代币的全部转账 | GET /{chain}/tokens/{token}/transfers | 按代币合约维度查询,standard 覆盖 erc20、erc721、erc1155,窗口可选,用游标分页遍历数据集实际提供的范围。 |
| 实时监听新事件 | eth_subscribe(WebSocket 链)/ eth_getLogs 轮询 | 支持 WebSocket 的链订阅新区块头或日志;其他链对最新区块区间轮询。 |
用 eth_getLogs 查询日志
export BLOCKVECTRA_API_KEY=rgw_your_api_key
# fromBlock / toBlock 缺省时为 latest。跟进新事件时可显式指定最近区间,
# 并让跨度不超过该链的 max_logs_block_range。
curl -s "https://api.blockvectra.com/v1/robinhood_mainnet" \
-H 'Content-Type: application/json' \
-H "x-api-key: $BLOCKVECTRA_API_KEY" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_getLogs",
"params": [{
"address": "0x1111111111111111111111111111111111111111",
"fromBlock": "latest",
"toBlock": "latest"
}]
}'用 Data API 查询转账
export BLOCKVECTRA_API_KEY=rgw_your_api_key
# 这里 from_block / to_block 可选;缺省 to_block 时默认取 as_of_block。
curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/tokens/0x1111111111111111111111111111111111111111/transfers?standard=erc20" \
-H "x-api-key: $BLOCKVECTRA_API_KEY"若要按地址查询,from_block 与 to_block 均为必填:
# clamp=true 会把过宽的窗口、或高于 as_of_block 的 to_block 截断,
# 而不是返回 409。
curl -s "https://api.blockvectra.com/v1/data/robinhood_mainnet/addresses/0x1111111111111111111111111111111111111111/transfers?standard=erc20&from_block=0&to_block=73000000&direction=any&clamp=true" \
-H "x-api-key: $BLOCKVECTRA_API_KEY"单次调用的 CU
每个方法都按其 CU 权重计费。下方权重从平台计划接口读取:
单次调用的 CU 权重
| 方法 | 单次调用 CU |
|---|---|
eth_getLogs | 30 |
data.address_transfers | 25 |
data.token_transfers | 25 |
当前价格与充值方式见定价页。
按区块窗口估算调用次数与 CU
区块窗口包含两端:N = to_block - from_block + 1。如果每次范围请求最多覆盖 S 个区块,一次成功遍历至少需要 ceil(N / S) 次请求。例如 10,000,000 个区块、每次 5 个区块是 2,000,000 次请求;每次 10,000 个区块是 1,000 次。这些只是算术示例,不代表任意链或 provider 的上限承诺。
失败与重试会增加请求,结果大小限制也一样。缩小窗口不自动等于更省:调用次数变多可能抵消窗口变窄,而 CU 按每次调用的权重计费。已索引的转账按结果分页,不按区块数分页,因此一次遍历可能需要更多页,包括最后可能出现的空页;不要用区块数直接推算页数。把上方每次调用的权重乘以预期计费调用次数来估算 CU,当前价格见定价页。
下一步
最后更新: