# eth_getLogs vs Token Transfers API: riwayat transfer ERC-20

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

Untuk riwayat dompet atau rekonsiliasi transfer ERC-20, mulailah dengan [Token Transfers API](https://blockvectra.com/en/data/transfers/). Gunakan `eth_getLogs` saat Anda membutuhkan log peristiwa kontrak. Pengembang dan agen AI dapat mengueri transfer alamat terindeks melalui API data blockchain yang sama. [Panduan aset dompet](https://docs.blockvectra.com/en/guides/wallet-assets/) menggabungkan saldo token, riwayat transfer, dan metadata; [referensi Data API](https://docs.blockvectra.com/en/api/data/) mendefinisikan parameter permintaan dan skema respons.

## Tugas yang dibantu panduan ini

* [Kueri log peristiwa kontrak](#querying-logs-with-eth_getlogs) melalui RPC terautentikasi dalam rentang blok terbatas untuk pemantauan atau backfill log.
* [Kueri riwayat transfer ERC-20 terindeks](#querying-transfers-with-the-data-api) melalui API data blockchain berdasarkan alamat atau kontrak token, dengan paginasi kursor dan pemeriksaan cakupan.

## Dua cara membaca log dan transfer

`eth_getLogs` adalah metode JSON-RPC: metode ini mengembalikan log blok melalui endpoint JSON-RPC. Data API mengekspos riwayat transfer token melalui dua endpoint dengan cakupan rantai:

* `GET /{chain}/addresses/{address}/transfers` — transfer yang melibatkan suatu alamat.
* `GET /{chain}/tokens/{token}/transfers` — transfer untuk satu kontrak token.

Keduanya menggunakan API key yang sama dan diukur dalam CU berdasarkan bobot metode (lihat bobot di bawah). Mana yang sesuai bergantung pada seberapa baru datanya, apakah Anda memerlukan jendela blok, dan bagaimana Anda melakukan paginasi.

## Batas yang berlaku untuk eth\_getLogs

`eth_getLogs` dibatasi oleh batas per-rantai yang dipublikasikan respons publik `GET /v1/chains`:

* **Rentang blok**: `max_logs_block_range` adalah jumlah maksimum blok yang dapat dicakup oleh satu permintaan `eth_getLogs`. Batas ini berbeda menurut rantai — baca dari `GET /v1/chains` (rantai tercantum di [Rantai yang Didukung](https://docs.blockvectra.com/en/chains/)) alih-alih melakukan hardcoding. Rentang yang lebih lebar ditolak dengan error JSON-RPC `-32602 eth_getLogs block range too large` (tidak ditagih).
* **Sinkronisasi node**: selama node rantai belum tersinkronisasi, `eth_getLogs` mengembalikan `-32010` (tidak ditagih).
* **Jendela status**: jendela status yang dilaporkan `GET /v1/chains` sebagai `state_window_blocks` berlaku untuk metode pembacaan status seperti `eth_call` dan `eth_getBalance`, bukan untuk `eth_getLogs`.
* **Pemangkasan node (pruning)**: pembacaan blok dan log tidak dibatasi oleh jendela status, tetapi dibatasi oleh riwayat yang dipertahankan oleh node. Data yang telah dipangkas mengembalikan `4444 pruned history unavailable` (tidak ditagih).

Ketika bidang filter `fromBlock` dan `toBlock` dihilangkan atau `null`, bidang tersebut default ke `latest`.

Memanggil `eth_subscribe` melalui HTTP mengembalikan `-32601 method not available`. Pada rantai di mana `ws` bernilai `true` di `/v1/chains`, `eth_subscribe` tersedia melalui WebSocket (lihat [Rantai yang Didukung](https://docs.blockvectra.com/en/chains/)); jika tidak, lakukan polling `eth_getLogs` pada blok-blok terbaru.

## Apa yang disediakan oleh endpoint transfer Data API

Kedua endpoint memerlukan parameter yang berbeda:

| Endpoint                                     | `standard`                                                              | Jendela blok                                                                                                                                                                                                                                               |
| -------------------------------------------- | ----------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `GET /{chain}/addresses/{address}/transfers` | Wajib: `erc20` atau `erc721`. `erc1155` mengembalikan `422 no_coverage` | `from_block` dan `to_block` keduanya wajib. Hasil diurutkan berdasarkan `(block_number, log_index)` menurun. `direction` (`in`, `out`, atau `any`; default `any`) memfilter berdasarkan arah, dan `token` secara opsional membatasi hasil ke satu kontrak. |
| `GET /{chain}/tokens/{token}/transfers`      | Wajib: `erc20`, `erc721`, atau `erc1155`                                | `from_block` dan `to_block` bersifat opsional. `to_block` yang tidak ada default ke `as_of_block`; `to_block` atau `from_block` eksplisit di atasnya adalah error keras `409 not_indexed_yet`, tanpa jalan keluar `clamp`.                                 |

### Paginasi

Kedua endpoint menggunakan paginasi berbasis keyset:

* `limit` default ke 50; nilai di atas 500 dibatasi (clamp) ke 500, dan `0` atau non-integer mengembalikan `400 bad_request`.
* `next_cursor` hanya muncul jika ada halaman lain. Pada halaman terakhir, kuncinya sama sekali tidak ada, tidak pernah `null`.
* Teruskan nilai yang dikembalikan kembali sebagai `cursor`, tanpa perubahan, untuk mengambil halaman berikutnya. Kursor hanya valid untuk rantai, endpoint, dan parameter kueri yang menerbitkannya.

### Cakupan dan finalitas

Transfer Data API mengindeks transfer token historis dari `coverage.from_block` setiap rantai hingga `meta.as_of_block`. Lihat [Rantai yang Didukung](https://docs.blockvectra.com/en/chains/) untuk mengetahui rantai mana saja yang menyediakannya.

Setiap item transfer berisi `token`, `standard`, `from`, `to`, `block_number`, `block_timestamp`, `tx_hash`, `tx_index`, dan `log_index`. Item ERC-20 menambahkan `amount`; item ERC-721 menambahkan `token_id`; item ERC-1155 menambahkan `operator`, `token_id`, `value`, dan `batch_index`.

## Mana yang harus digunakan

| Tugas umum                                   | Pilihan lebih baik                                           | Alasan                                                                                                                                                           |
| -------------------------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Peristiwa dalam beberapa ratus blok terakhir | `eth_getLogs`                                                | Satu permintaan dapat mencakup rentang terbaru selama tidak melebihi `max_logs_block_range` rantai tersebut.                                                     |
| Riwayat transfer suatu alamat                | `GET /{chain}/addresses/{address}/transfers`                 | Kueri dengan cakupan alamat dengan jendela `from_block`/`to_block`, filter `direction` dan `token`, serta paginasi kursor; hasil disajikan hingga `as_of_block`. |
| Semua transfer dari suatu token              | `GET /{chain}/tokens/{token}/transfers`                      | Kueri dengan cakupan kontrak token yang mencakup `erc20`, `erc721`, dan `erc1155`, dengan jendela opsional dan paginasi kursor untuk seluruh kumpulan hasil.     |
| Pemantauan langsung peristiwa baru           | `eth_subscribe` (rantai WebSocket) / `eth_getLogs` (polling) | Berlangganan ke newHeads atau log melalui WebSocket jika didukung, atau lakukan polling pada rentang blok terbaru.                                               |

## Mengueri log dengan 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())
```


## Mengueri transfer dengan 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
```


Untuk mengueri berdasarkan alamat sebagai gantinya, `from_block` dan `to_block` diperlukan:

```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"
```

## CU per panggilan

Setiap metode ditagih berdasarkan bobot CU-nya. Bobot di bawah ini dibaca dari API rencana platform:

**Bobot CU per panggilan**

| Metode | CU per panggilan |
| --- | --- |
| `eth_getLogs` | 30 |
| `data.address_transfers` | 25 |
| `data.token_transfers` | 25 |

Untuk harga terkini dan opsi top-up, lihat [halaman Harga](https://blockvectra.com/en/pricing/).

## Langkah selanjutnya

* [Telusuri direktori dataset](https://blockvectra.com/en/data/) untuk melihat setiap dataset yang diindeks oleh BlockVectra.
* [Lihat paket gratis dan harga](https://blockvectra.com/en/pricing/#free) untuk memeriksa apa yang termasuk dalam akun Anda.
* [Masuk ke konsol](https://console.blockvectra.com/login/?next=%2Fkeys%2F) untuk membuat API key.
