# eth_getLogs とトークン送金 API の使い分け：ERC-20 送金履歴

> Source: https://docs.blockvectra.com/ja/guides/logs-vs-transfers/

ウォレット履歴や ERC-20 送金の照合には、[トークン送金 API](https://blockvectra.com/en/data/transfers/) から始めることを推奨します。コントラクトイベントログが必要な場合は `eth_getLogs` を使用してください。開発者と AI エージェントは、同一のブロックチェーンデータ API を介してインデックス済みのアドレス送金を照会できます。[ウォレット資産ガイド](https://docs.blockvectra.com/en/guides/wallet-assets/) ではトークン残高、送金履歴、メタデータを組み合わせて解説しており、[Data API リファレンス](https://docs.blockvectra.com/en/api/data/) ではリクエストパラメータとレスポンススキーマを定義しています。

## このガイドで達成できること

* 監視やログのバックフィルのために、有界なブロック範囲で認証付き RPC を介して[コントラクトイベントログを照会](#querying-logs-with-eth_getlogs)します。
* カーソルページネーションと対応範囲の確認を行いながら、ブロックチェーンデータ API を介してアドレスまたはトークンコントラクトごとに[インデックス済み ERC-20 送金履歴を照会](#querying-transfers-with-the-data-api)します。

## ログと送金を読み取る 2 つの方法

`eth_getLogs` は JSON-RPC メソッドであり、JSON-RPC エンドポイントを介してブロックログを返します。Data API は、チェーンスコープの 2 つのエンドポイントを通じてトークン送金履歴を公開しています：

* `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`（チェーンは[対応チェーン一覧](https://docs.blockvectra.com/en/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` になります。

HTTP 経由で `eth_subscribe` を呼び出すと、`-32601 method not available` が返されます。`/v1/chains` で `ws` が `true` になっているチェーンでは、WebSocket 経由で `eth_subscribe` を利用できます（[対応チェーン一覧](https://docs.blockvectra.com/en/chains/)を参照）。それ以外の場合は、最新のブロックに対して `eth_getLogs` をポーリングしてください。

## Data API 送金エンドポイントが提供するもの

2 つのエンドポイントでは異なるパラメータが必要です：

| エンドポイント                                      | `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` で結果を 1 つのコントラクトに絞り込むことができます。   |
| `GET /{chain}/tokens/{token}/transfers`      | 必須：`erc20`、`erc721`、または `erc1155`                           | `from_block` と `to_block` はオプションです。`to_block` を省略した場合はデフォルトで `as_of_block` になります。明示的に `to_block` または `from_block` をそれより上に設定すると、`clamp` による回避策はなく、厳格に `409 not_indexed_yet` となります。 |

### ページネーション

両方のエンドポイントは keyset ページネーションを採用しています：

* `limit` はデフォルトで 50 です。500 を超える値は 500 に制限され、`0` または非整数の場合は `400 bad_request` が返されます。
* `next_cursor` は次のページが存在する場合にのみ表示されます。最後のページでは、このキー自体が存在せず、`null` になることもありません。
* 返された値をそのまま `cursor` として再送することで、次のページを取得します。カーソルは、それを発行したチェーン、エンドポイント、およびクエリパラメータに対してのみ有効です。

### 対応範囲とファイナリティ

Data API 送金は、各チェーンの `coverage.from_block` から `meta.as_of_block` までの過去のトークン送金をインデックス化しています。どのチェーンがこれを提供しているかは、[対応チェーン一覧](https://docs.blockvectra.com/en/chains/)を参照してください。

各送金項目には、`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` を超えない限り、1 回のリクエストで直近の範囲をカバーできます。                                                     |
| 特定アドレスの過去の送金履歴   | `GET /{chain}/addresses/{address}/transfers`             | `from_block`/`to_block` ウィンドウ、`direction` および `token` フィルタ、カーソルページネーションを備えたアドレススコープのクエリ。結果は `as_of_block` まで提供されます。 |
| 特定トークンのすべての送金    | `GET /{chain}/tokens/{token}/transfers`                  | `erc20`、`erc721`、および `erc1155` をカバーするトークンコントラクトスコープのクエリ。任意のウィンドウと、完全な結果セットのためのカーソルページネーションを備えています。                  |
| 新しいイベントのリアルタイム監視 | `eth_subscribe`（WebSocket 対応チェーン） / `eth_getLogs`（ポーリング） | サポートされている環境では WebSocket 経由で新しいヘッドやログを購読するか、直近のブロック範囲をポーリングします。                                                      |

## eth\_getLogs によるログのクエリ

**cURL**

```bash
export BLOCKVECTRA_API_KEY=rgw_your_api_key

# fromBlock / toBlock default to latest. Set an explicit recent range to follow
# new events, and keep its span within the chain's 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"
    }]
  }'
```


  **TypeScript**

```ts
const res = await fetch("https://api.blockvectra.com/v1/robinhood_mainnet", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "x-api-key": process.env.BLOCKVECTRA_API_KEY!,
  },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: 1,
    method: "eth_getLogs",
    params: [{
      address: "0x1111111111111111111111111111111111111111",
      fromBlock: "latest",
      toBlock: "latest",
    }],
  }),
});

const { result } = await res.json();
console.log(result);

// npx tsx example.mts
```


  **Python**

```python
import os
import requests

res = requests.post(
    "https://api.blockvectra.com/v1/robinhood_mainnet",
    headers={
        "Content-Type": "application/json",
        "x-api-key": os.environ["BLOCKVECTRA_API_KEY"],
    },
    json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "eth_getLogs",
        "params": [{
            "address": "0x1111111111111111111111111111111111111111",
            "fromBlock": "latest",
            "toBlock": "latest",
        }],
    },
)
res.raise_for_status()
print(res.json())
```


## Data API による送金のクエリ

**cURL**

```bash
export BLOCKVECTRA_API_KEY=rgw_your_api_key

# from_block / to_block are optional here; omitting to_block defaults to 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"
```


  **TypeScript**

```ts
let cursor: string | undefined;

do {
  const url = new URL(
    "https://api.blockvectra.com/v1/data/robinhood_mainnet/tokens/0x1111111111111111111111111111111111111111/transfers",
  );
  url.searchParams.set("standard", "erc20");
  if (cursor) url.searchParams.set("cursor", cursor);

  const res = await fetch(url, {
    headers: { "x-api-key": process.env.BLOCKVECTRA_API_KEY! },
  });
  const body = await res.json();
  console.log(body.data);
  cursor = body.next_cursor; // absent on the last page
} while (cursor);

// npx tsx example.mts
```


  **Python**

```python
import os
import requests

url = "https://api.blockvectra.com/v1/data/robinhood_mainnet/tokens/0x1111111111111111111111111111111111111111/transfers"
cursor = None

while True:
    params = {"standard": "erc20"}
    if cursor:
        params["cursor"] = cursor
    res = requests.get(
        url,
        params=params,
        headers={"x-api-key": os.environ["BLOCKVECTRA_API_KEY"]},
    )
    res.raise_for_status()
    body = res.json()
    print(body["data"])
    cursor = body.get("next_cursor")  # absent on the last page
    if not cursor:
        break
```


アドレスを基準に照会する場合は、`from_block` と `to_block` が必須です：

```bash
# clamp=true truncates a too-wide window, or a to_block above as_of_block,
# instead of returning 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"
```

## 1 回の呼び出しあたりの CU

すべてのメソッドは CU 重み付けに基づいて課金されます。以下の重み付けはプラットフォームのプラン API から読み取られます：

**呼び出しあたりの CU 重み付け**

| メソッド | 呼び出しあたりの CU |
| --- | --- |
| `eth_getLogs` | 30 |
| `data.address_transfers` | 25 |
| `data.token_transfers` | 25 |

現在の価格とチャージオプションについては、[料金ページ](https://blockvectra.com/en/pricing/)を参照してください。

## 次のステップ

* [データセット一覧を見る](https://blockvectra.com/en/data/)と、BlockVectra がインデックス化しているすべてのデータセットを確認できます。
* [無料プランと料金を見る](https://blockvectra.com/en/pricing/#free)と、アカウントに含まれる内容を確認できます。
* [コンソールにログイン](https://console.blockvectra.com/login/?next=%2Fkeys%2F)して、API keyを作成します。
