# Batas laju RPC HyperEVM dan backfill log

> Source: https://docs.blockvectra.com/id/guides/hyperevm-backfill/

## Jawaban langsung

RPC publik resmi default HyperEVM mengizinkan 50 blok per kueri `eth_getLogs` (sumber: [dokumentasi JSON-RPC](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/json-rpc) resmi Hyperliquid). Di BlockVectra, permintaan `eth_getLogs` terautentikasi mencakup hingga 1,000 blok per kueri (`hyperevm_mainnet.max_logs_block_range` dari [GET /v1/chains](https://api.blockvectra.com/v1/chains)), termasuk kedua titik akhir. Rentang yang lebih lebar mengembalikan HTTP 200, JSON-RPC `-32602` dan `logs_range_too_large`, dengan `retryable: false` (lihat [katalog error](https://docs.blockvectra.com/en/errors/#logs_range_too_large)); bagi menjadi `[from, min(from + max − 1, end)]`, simpan kursor Anda, dan lanjutkan ke akhir ditambah satu setelah berhasil untuk melanjutkan proses. Batas laju per IP RPC publik resmi dan batas kunci BlockVectra dijelaskan secara terpisah dalam [Batas laju RPC publik resmi dan 429](#official-public-rpc-rate-limits-and-429) serta parameter layanan di bawah ini.

## Tugas yang dibantu panduan ini

* [Uji RPC HyperEVM](#connect-with-viem-or-ethers) dengan pembacaan publik menggunakan viem atau ethers sebelum memilih metode terautentikasi.
* [Lakukan backfill jendela log terbatas](#three-step-task-backfill-a-bounded-hyperevm-log-window) dalam batas `eth_getLogs` HyperEVM, dengan keputusan percobaan ulang berdasarkan error yang dikembalikan.
* [Baca aktivitas alamat](#using-data-api-endpoints-instead-of-extensive-getlogs-scanning) melalui transaksi dan transfer terindeks dengan kunci, memeriksa cakupan dan metadata keterbaruan yang dikembalikan.

<span id="bounded-log-backfill-task" />

## Tugas tiga langkah: backfill jendela log HyperEVM terbatas

Baca blok terbaru tanpa kunci, buat kunci, lalu ambil log peristiwa untuk suatu kontrak dalam jendela blok terbatas.

Pilih kontrak dan jendela blok yang Anda butuhkan. Tugas ini mencakup jendela terbatas tersebut; tugas ini tidak menjamin riwayat kontrak yang lengkap.

### 1. Baca blok terbaru tanpa API key

```bash
curl -sS "https://api.blockvectra.com/v1/hyperevm_mainnet/public" \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}'
```

`result` JSON-RPC adalah nomor blok terbaru dalam heksadesimal. Ini adalah `public.url` HyperEVM yang dipublikasikan oleh [GET /v1/chains](https://api.blockvectra.com/v1/chains). `public.methods` endpoint publik tidak mencakup `eth_getLogs`; langkah 3 memerlukan kunci.

### 2. Buat API key

<div data-attribution-ref="docs-hyperevm-task">
  [Buat kunci untuk backfill ini](https://console.blockvectra.com/login/?next=%2Fkeys%2F). Buat kunci dan simpan rahasia yang ditampilkan di dialog untuk digunakan dengan `hyperevm_mainnet`.

  Untuk Agen AI yang menggunakan HTTP tanpa browser, ikuti <a href="/en/guides/programmatic-signup/">Panduan pendaftaran terprogram</a>. Teruskan `ref` valid URL panduan dalam isi JSON `POST /auth/siwe/login` alih-alih `docs-signup` dari contoh; hilangkan jika tidak tersedia. Jangan meminta pengguna menempelkan kunci ke dalam obrolan.
</div>

### 3. Lakukan backfill log dengan API key Anda

Templat awal lengkap: [blockvectra/hyperevm-backfill](https://github.com/blockvectra/hyperevm-backfill)

Simpan skrip berikut sebagai `hyperevm-task.ts`. Skrip ini berjalan dengan Node.js 24 atau lebih baru, tanpa paket tambahan. Tetapkan `BLOCKVECTRA_API_KEY` ke kunci yang Anda simpan dan `LOG_ADDRESS` ke alamat kontrak pemancar yang ingin Anda periksa; simpan kunci di server Anda atau di terminal lokal.

```bash
export BLOCKVECTRA_API_KEY='replace-with-your-key'
export LOG_ADDRESS='replace-with-contract-address'
node hyperevm-task.ts
```

Secara default, skrip mengambil blok `max_logs_block_range` terbaru, atau lebih sedikit di dekat genesis. Skrip membaca batas tersebut dari `/v1/chains` pada waktu proses. Untuk memilih jendela terbatas lainnya, tetapkan `FROM_BLOCK` dan `TO_BLOCK` ke nomor blok desimal atau heksadesimal `0x` sebelum menjalankan. Jendela yang lebih besar dibagi menjadi chunk berurutan, masing-masing paling banyak batas yang dipublikasikan.

```ts
const apiKey = process.env.BLOCKVECTRA_API_KEY;
const address = process.env.LOG_ADDRESS;
if (!apiKey || apiKey === "replace-with-your-key") throw new Error("Set BLOCKVECTRA_API_KEY");
if (!address || !/^0x[0-9a-f]{40}$/i.test(address)) throw new Error("Set LOG_ADDRESS to a contract address");

const fromBlock = process.env.FROM_BLOCK;
const toBlock = process.env.TO_BLOCK;
if ((fromBlock !== undefined || toBlock !== undefined) && (!fromBlock || !toBlock)) {
  throw new Error("Set both FROM_BLOCK and TO_BLOCK");
}

const chainsUrl = "https://api.blockvectra.com/v1/chains";
const rpcUrl = new URL("./hyperevm_mainnet", chainsUrl).href;
async function readJson(url: string) {
  const response = await fetch(url, { signal: AbortSignal.timeout(15_000) });
  if (!response.ok) throw new Error(`Metadata HTTP ${response.status}`);
  return response.json();
}
const catalog = await readJson(chainsUrl);
const chain = catalog.chains.find((item: { chain: string }) => item.chain === "hyperevm_mainnet");
if (!chain || !Number.isSafeInteger(chain.max_logs_block_range) || chain.max_logs_block_range <= 0) {
  throw new Error("Missing or invalid max_logs_block_range");
}
if (!chain.methods.allow.includes("eth_getLogs") || chain.methods.deny.includes("eth_getLogs")) {
  throw new Error("eth_getLogs is unavailable on this chain");
}
const maxRange = BigInt(chain.max_logs_block_range);
const plans = await readJson("https://console-api.blockvectra.com/v1/plans");
function weight(method: string): bigint {
  const row = plans.method_weights.find((item: { method: string }) => item.method === method);
  if (!row || !Number.isSafeInteger(row.cu_weight) || row.cu_weight <= 0) {
    throw new Error(`Missing or invalid CU weight for ${method}`);
  }
  return BigInt(row.cu_weight);
}
const headWeight = weight("eth_blockNumber");
const logsWeight = weight("eth_getLogs");

type RpcBody = {
  result?: unknown;
  error?: { code: number; data?: { retryable?: boolean } };
};
async function rpc(method: string, params: unknown[]): Promise<unknown> {
  for (let attempt = 0; attempt < 4; attempt++) {
    const response = await fetch(rpcUrl, {
      method: "POST",
      redirect: "error",
      headers: { "Content-Type": "application/json", "x-api-key": apiKey! },
      body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
      signal: AbortSignal.timeout(15_000),
    });
    const body = await response.json() as RpcBody;
    if (response.ok && !body.error && body.result !== undefined) return body.result;
    if (body.error?.data?.retryable !== true || attempt === 3) {
      throw new Error(`RPC failed: HTTP ${response.status}, code ${body.error?.code ?? "unknown"}`);
    }
    const retryAfter = response.headers.get("Retry-After");
    const delay = retryAfter === null ? 0 : /^\d+$/.test(retryAfter)
      ? Number(retryAfter) * 1000 : Date.parse(retryAfter) - Date.now();
    if (delay > 30_000) throw new Error("Retry-After exceeds 30 seconds; rerun later");
    const backoff = 1000 * 2 ** attempt + Math.random() * 250;
    await new Promise((resolve) => setTimeout(resolve, Math.max(backoff, Number.isFinite(delay) ? delay : 0)));
  }
  throw new Error("Retry limit reached");
}
function block(value: string): bigint {
  if (!/^(0x[0-9a-f]+|[0-9]+)$/i.test(value)) throw new Error("Invalid block number");
  return BigInt(value);
}
const head = await rpc("eth_blockNumber", []);
if (typeof head !== "string" || !/^0x[0-9a-f]+$/i.test(head)) throw new Error("Invalid chain head");
const latest = block(head);
const end = toBlock ? block(toBlock) : latest;
const start = fromBlock ? block(fromBlock)
  : end >= maxRange - 1n ? end - maxRange + 1n : 0n;
if (start > end || end > latest) throw new Error("Require 0 <= FROM_BLOCK <= TO_BLOCK <= latest");
const chunks = (end - start + maxRange) / maxRange;
console.error(`Window ${start}..${end}; chunks=${chunks}; estimated CU=${headWeight + chunks * logsWeight}`);

const hex = (value: bigint) => `0x${value.toString(16)}`;
for (let from = start; from <= end; from += maxRange) {
  const to = from + maxRange - 1n < end ? from + maxRange - 1n : end;
  const result = await rpc("eth_getLogs", [{ address, fromBlock: hex(from), toBlock: hex(to) }]);
  if (!Array.isArray(result)) throw new Error("Expected eth_getLogs result array");
  console.log(JSON.stringify({ fromBlock: hex(from), toBlock: hex(to), result }));
}
```

Permintaan berjalan secara berurutan. Error JSON-RPC dicoba kembali hanya jika `error.data.retryable` bernilai `true`, dengan paling banyak empat percobaan per permintaan, backoff eksponensial dan jitter, serta dukungan untuk detik `Retry-After` atau tanggal HTTP. Menunggu lebih dari 30 detik akan menghentikan skrip sehingga Anda dapat menjalankannya kembali nanti. Kegagalan jaringan, batas waktu habis (timeout), respons tidak valid, dan error yang tidak dapat dicoba ulang langsung berhenti; skrip keluar dengan status tidak berhasil daripada melaporkan backfill yang lengkap.

Setiap baris output standar berisi `fromBlock`, `toBlock`, dan array `result` untuk satu chunk. `result: []` berarti tidak ada log yang cocok dalam chunk tersebut. Baca bidang-bidang berikut di setiap log:

| Bidang                                            | Arti                                                                                                        |
| ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `address`                                         | Kontrak yang memancarkan peristiwa.                                                                         |
| `blockNumber`, `blockHash`                        | Blok yang berisi log; nomornya adalah heksadesimal.                                                         |
| `transactionHash`, `transactionIndex`, `logIndex` | Posisi transaksi dan log; indeks adalah heksadesimal.                                                       |
| `topics`, `data`                                  | Argumen peristiwa terindeks dan argumen non-terindeks yang dikodekan dengan ABI; dekode dengan ABI kontrak. |
| `removed`                                         | Apakah log dihapus oleh reorganisasi rantai (reorg).                                                        |

Blok terbaru bukanlah penanda finalitas. Jika Anda memerlukan jendela historis yang stabil, pilih `TO_BLOCK` terkonfirmasi untuk aplikasi Anda dan tangani reorganisasi rantai.

Untuk jendela `B = TO_BLOCK − FROM_BLOCK + 1` blok dan batas yang dipublikasikan `L`, jumlah chunk adalah `N = ceil(B / L)`. Baca `method_weights[].cu_weight` untuk `eth_getLogs` dan `eth_blockNumber` dari [GET /v1/plans](https://console-api.blockvectra.com/v1/plans). Skrip mencetak perkiraan ke standard error: `N × weight(eth_getLogs) + weight(eth_blockNumber)`, termasuk pencarian head dengan kunci. Ini tidak termasuk panggilan ekstra dan percobaan ulang yang dapat ditagih; lihat [aturan penagihan](https://docs.blockvectra.com/en/guides/billing-rules/) untuk penyelesaian. CU bergantung pada panggilan, bukan jumlah log yang dikembalikan.

**Pengiriman peristiwa:** Gunakan polling HTTP terbagi di bawah ini, atau kirim peristiwa alamat yang dipantau ke penerima HTTPS dengan [webhook push](https://docs.blockvectra.com/en/guides/webhook-push/). **GET /v1/push/chains mencantumkan rantai yang didukung** dan pengaturan konfirmasi; autentikasi dengan `x-api-key`. Tanda tangan webhook, deduplikasi, dan pemutaran ulang (replay) dibahas dalam panduan tersebut. Webhook push terpisah dari langganan WebSocket (`ws` dan `subscriptions` di `/v1/chains`).

## Hubungkan dengan viem atau ethers

| Parameter / Endpoint | Nilai / Templat | Autentikasi |
|---|---|---|
| Chain ID (EIP-155) | `999` | — |
| JSON-RPC (kunci di path) | `POST https://api.blockvectra.com/v1/hyperevm_mainnet/{api_key}` | API key di path URL |
| JSON-RPC (kunci di header) | `POST https://api.blockvectra.com/v1/hyperevm_mainnet` | Header x-api-key: {api_key} |
| Basis Data API | `GET https://api.blockvectra.com/v1/data/hyperevm_mainnet/…` | Header x-api-key: {api_key} |
| Status publik | `GET https://api.blockvectra.com/v1/status` | Tanpa autentikasi (publik) |

Pengembang dan Agen AI dapat menggunakan pengaturan sisi server yang sama. Gunakan Node.js 24 atau lebih baru, viem 2 atau ethers 6, dan mulailah dengan pembacaan publik. Tetapkan `BLOCKVECTRA_API_KEY` secara aman di lingkungan untuk metode yang menggunakan kunci. Jauhkan kunci dan URL RPC yang berisi kunci dari kode browser, log, dan kontrol versi.

Simpan ini sebagai `network.mjs`. Skrip ini membaca `chain_id` dan kebijakan metode dari [GET /v1/chains](https://api.blockvectra.com/v1/chains). Untuk pembacaan tanpa kunci, gunakan `public.url` dari katalog dan hanya metode yang tercantum dalam `public.methods`; ketersediaan HTTP publik tidak menyiratkan akses WebSocket.

```js
const chainSlug = process.env.BLOCKVECTRA_CHAIN ?? 'hyperevm_mainnet';
const key = process.env.BLOCKVECTRA_API_KEY;
const catalogUrl = 'https://api.blockvectra.com/v1/chains';
const response = await fetch(catalogUrl, { signal: AbortSignal.timeout(15_000) });
if (!response.ok) throw new Error(`Chains HTTP ${response.status}`);
const catalog = await response.json();
export const chainInfo = catalog.chains.find(item => item.chain === chainSlug);
if (!chainInfo || !Number.isSafeInteger(chainInfo.chain_id) || chainInfo.chain_id <= 0) {
  throw new Error('Missing chain or chain_id');
}
export function allows(method) {
  const matches = pattern => pattern.endsWith('*')
    ? method.startsWith(pattern.slice(0, -1)) : pattern === method;
  if (!key) return (chainInfo.public?.methods ?? []).some(matches);
  return (chainInfo.methods?.allow ?? []).some(matches)
    && !(chainInfo.methods?.deny ?? []).some(matches);
}
if (!allows('eth_chainId')) throw new Error('eth_chainId is unavailable');
export const rpcUrl = key
  ? new URL(`./${chainSlug}/${encodeURIComponent(key)}`, catalogUrl).href
  : chainInfo.public?.url;
if (!rpcUrl) throw new Error('Public RPC is unavailable; set BLOCKVECTRA_API_KEY');
```

Simpan sebagai `viem-client.mjs`, instal dengan `npm install viem@2`, lalu jalankan `node viem-client.mjs`.

```js
import { createPublicClient, defineChain, http } from 'viem';
import { chainInfo, rpcUrl } from './network.mjs';

export const chain = defineChain({
  id: chainInfo.chain_id,
  name: chainInfo.name,
  nativeCurrency: { name: 'HYPE', symbol: 'HYPE', decimals: 18 },
  rpcUrls: { default: { http: [rpcUrl] } },
});
export const client = createPublicClient({ chain, transport: http(rpcUrl) });
if (await client.getChainId() !== chain.id) throw new Error('RPC chain ID mismatch');
console.error(await client.getBlockNumber());
```

Untuk ethers, simpan sebagai `ethers-client.mjs`, instal dengan `npm install ethers@6`, lalu jalankan `node ethers-client.mjs`.

```js
import { JsonRpcProvider } from 'ethers';
import { chainInfo, rpcUrl } from './network.mjs';

const provider = new JsonRpcProvider(rpcUrl, chainInfo.chain_id, { batchMaxCount: 1 });
const network = await provider.getNetwork();
if (network.chainId !== BigInt(chainInfo.chain_id)) throw new Error('RPC chain ID mismatch');
console.log(await provider.getBlockNumber());
provider.destroy();
```

## Deploy dengan Foundry atau Hardhat

Katalog `hyperevm_mainnet` saat ini memiliki `ws=false` dan tidak mencantumkan `eth_sendRawTransaction` dalam `methods.allow`. Gunakan BlockVectra untuk pembacaan; deployment memerlukan RPC yang mendukung penyiaran (broadcasting). Tetapkan `DEPLOY_RPC_URL` ke URL HTTP terautentikasi penyedia tersebut. Jangan berasumsi bahwa penyedia tersebut memiliki batas metode atau batas rentang log yang sama dengan BlockVectra. Periksa Chain ID yang dipilih sebelum menandatangani.

```bash
: "${DEPLOY_RPC_URL:?Set a broadcasting RPC URL}"
export RPC_URL="$DEPLOY_RPC_URL"
export CHAIN_ID="$(node --input-type=module -e "import { chainInfo } from './network.mjs'; console.log(chainInfo.chain_id)")"
```

Lanjutkan dengan [tutorial deployment Foundry atau Hardhat](https://docs.blockvectra.com/en/guides/deploy-contract/) bersama. Danai deployer dengan EVM HYPE dan tinjau persyaratan blok ganda (dual-block) di bawah ini sebelum deployment besar.

## HYPE, blok kecil, dan deployment besar

[Panduan jaringan resmi HyperEVM](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm) mengidentifikasi HYPE sebagai gas, dengan 18 desimal (diakses: 2026-10-07). Pastikan deployer memiliki HYPE di HyperEVM; saldo HyperCore saja bukan saldo gas EVM. Ikuti instruksi transfer native yang ditautkan saat memindahkan dana.

[Panduan blok ganda](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/dual-block-architecture) menjelaskan blok kecil yang cepat dan blok besar yang lebih lambat untuk transaksi yang lebih besar (diakses: 2026-10-07). Perkirakan gas deployment terlebih dahulu. Untuk deployment yang melebihi anggaran blok kecil, deployer harus menjadi pengguna HyperCore yang sudah ada dan menandatangani tindakan Core `{"type":"evmUserModify","usingBigBlocks":true}`; menetapkan batas gas transaksi yang lebih besar saja tidak memilih blok besar. Kembalikan `usingBigBlocks=false` setelahnya untuk kembali ke blok kecil.

Pada penyedia yang mendukungnya, gunakan `eth_usingBigBlocks` untuk memeriksa mode alamat dan `eth_bigBlockGasPrice` untuk biaya dasar blok besar. [Referensi JSON-RPC resmi](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/json-rpc) mendokumentasikan metode-metode ini (diakses: 2026-10-07). Periksa metode penyedia yang dipilih; gunakan `/v1/chains` untuk BlockVectra. Deployment minimal di atas menargetkan kontrak kecil dan tidak mengubah mode akun Core.

## Data HyperCore dan HyperEVM

RPC EVM melayani kontrak, resi (receipt), dan log. Data perdagangan dan tindakan HyperCore menggunakan Core API. Kontrak dapat membaca status Core melalui precompile dan mengirim tindakan melalui CoreWriter; gunakan [panduan interaksi resmi](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/interacting-with-hypercore) saat mengintegrasikan jalur ini (diakses: 2026-10-07). Log EVM tidak menggantikan kueri buku pesanan (order book) atau posisi Core.

Transaksi sistem HyperEVM (seperti transfer HyperCore ke HyperEVM) tidak disertakan dalam respons standar `eth_getBlockByNumber` dan disediakan secara terpisah oleh RPC resmi melalui `eth_getSystemTxsByBlockNumber` dan `eth_getSystemTxsByBlockHash` (lihat [dokumentasi JSON-RPC resmi](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/json-rpc), diakses: 2026-10-07). Data blok, transaksi, dan Data API HyperEVM BlockVectra saat ini tidak menyertakan transaksi sistem; gunakan kedua metode RPC resmi ini secara langsung jika memerlukan data transaksi sistem.

## Menangani error resmi 10055

[Panduan resmi HyperEVM](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm) mendefinisikan `10055` sebagai error batas Core/EVM, termasuk kegagalan nonce, dana tidak mencukupi, hash duplikat, dan penggantian dengan harga terlalu rendah (underpriced replacement) (diakses: 2026-10-07). Periksa pesan dari RPC penyiaran sebelum memutuskan cara pemulihan:

* **Nonce:** bandingkan `eth_getTransactionCount` dengan transaksi tertunda Anda; buat serialisasi pengiriman dari satu deployer dan rekonsiliasi nonce berikutnya.
* **Dana:** periksa saldo EVM HYPE deployer terhadap nilai ditambah biaya gas.
* **Hash duplikat:** cari transaksi dan resi yang ada sebelum mengirimkan transaksi lain.
* **Biaya penggantian:** verifikasi nonce dan biaya yang ada, lalu gunakan kebijakan penggantian penyiar; mengulang byte yang sama tidak menaikkan biaya.

`10055` saja tidak membenarkan percobaan ulang tanpa pertimbangan. Baca error dan panduan pemulihannya secara terpisah dalam [referensi error BlockVectra](https://docs.blockvectra.com/en/errors/).

## Batas laju RPC publik resmi dan 429

[Dokumentasi batas laju](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/rate-limits-and-user-limits) resmi Hyperliquid menetapkan paling banyak 100 permintaan EVM JSON-RPC per menit per IP untuk `rpc.hyperliquid.xyz/evm`. [Dokumentasi JSON-RPC](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/json-rpc)-nya juga membatasi `eth_getLogs` hingga 50 blok per kueri dan hingga 4 topik. Diakses: 2026-10-07.

Pada HTTP 429, jeda permintaan dan hormati `Retry-After` terlebih dahulu (detik atau tanggal HTTP). Jika tidak ada, gunakan backoff eksponensial dengan jitter dan jumlah percobaan ulang terbatas, mencoba kembali chunk yang belum selesai yang sama. Kurangi konkurensi dan frekuensi polling, dan bagi kueri log menjadi chunk dalam batas endpoint. Pembagian chunk saja tidak menghilangkan batas laju; klien yang berbagi IP perlu mengoordinasikan laju permintaan mereka.

Untuk endpoint dengan kunci BlockVectra, baca `max_logs_block_range`, `methods.allow`, dan `methods.deny` untuk `hyperevm_mainnet` dari [GET /v1/chains](https://api.blockvectra.com/v1/chains) alih-alih menerapkan rentang blok atau batas permintaan per menit RPC publik resmi. Laju permintaan secara terpisah tunduk pada `cu_per_sec`, `burst_cu` kunci, dan batas panggilan paket gratis (lihat bagian berikutnya). Pada 429, periksa `error.data.reason` dan `retryable`; `request_exceeds_burst` memerlukan permintaan yang lebih kecil daripada percobaan ulang tanpa perubahan dengan backoff.

## Parameter dan aturan layanan BlockVectra

BlockVectra melayani mainnet HyperEVM melalui endpoint JSON-RPC dan REST Data API:

1. **Parameter rantai dan batas log**:
   Dari `GET /v1/chains` untuk `hyperevm_mainnet`:
   * **Pengidentifikasi rantai (Slug)**: `hyperevm_mainnet`, Chain ID `999`.
   * **`max_logs_block_range`**: Diatur oleh bidang `max_logs_block_range` dari `GET /v1/chains`. Satu permintaan `eth_getLogs` dapat mencakup paling banyak jumlah blok ini (`toBlock − fromBlock + 1`). Melebihi rentang ini mengembalikan HTTP 200 dengan kode error JSON-RPC `-32602` (`eth_getLogs block range too large: max <N> blocks`), yang tidak ditagih.
   * **`state_window_blocks`**: Diatur oleh bidang `state_window_blocks` dari `GET /v1/chains`. Panggilan pembacaan status (seperti `eth_call` dan `eth_getBalance`) tunduk pada jendela retensi yang dinyatakan oleh bidang ini (jika `null`, status penuh dipertahankan tanpa batas jendela bergulir).
   * **Kebijakan metode**: Diatur oleh `methods.allow` dan `methods.deny`. Metode standar EVM (`eth_blockNumber`, `eth_getLogs`, `eth_call`, `eth_getBalance`, `eth_getBlockByNumber`, `eth_getTransactionReceipt`, dll.) diizinkan; metode filter dan langganan (`eth_subscribe`, `eth_unsubscribe`, `eth_newFilter`, `eth_newBlockFilter`) ditolak, mengembalikan `-32601` (tidak ditagih).
2. **Batas laju tingkat gratis dan peningkatan**:
   Dari `GET /v1/plans`:
   * **`free.max_calls_per_sec`**: hingga 25 panggilan per detik, dibagi di antara semua kunci di akun, semua rantai, dan Data API.
   * **Batas kunci default**: Setiap API key memiliki bucket CU (pengisian ulang `cu_per_sec`, kapasitas `burst_cu` — default adalah 400 CU/dtk dan burst 1,600 CU). Metode diukur berdasarkan bobot Compute Unit (CU).
   * **Meningkatkan batas**: Setelah melakukan top up, batas panggilan per detik di seluruh akun dihapus; setiap kunci tetap tunduk pada batas laju Compute Unit (CU) dan burst. Untuk tarif dan unit penagihan saat ini, lihat [halaman Harga](https://blockvectra.com/en/pricing/).

## Melakukan backfill log historis: eth\_getLogs terbagi dan logika percobaan ulang

Saat mengueri log historis, interval lebar harus dibagi menjadi chunk berurutan yang dibatasi oleh `max_logs_block_range` rantai target. Strategi percobaan ulang klien harus memeriksa bidang `retryable` di dalam respons error.

### Mengevaluasi retryable dalam respons error

Di BlockVectra, objek error JSON-RPC menyertakan payload `error.data` yang berisi `reason`, `docs_url`, dan `retryable` (boolean):

* **`retryable: true`**: Kondisi sementara, termasuk kelebihan beban layanan (`overloaded`), batas panggilan per detik paket gratis (`free_plan_call_limit`), sinkronisasi node (`node_syncing`), atau upstream tidak tersedia (`upstream_unavailable`). Klien harus menghormati header `Retry-After` jika ada atau menerapkan backoff eksponensial dengan jitter.
* **`retryable: false`**: Error non-sementara, seperti rentang blok melebihi batas (`-32602` / `logs_range_too_large`), parameter tidak valid (`invalid_params`), API key tidak ada (`missing_api_key`), atau permintaan melebihi kapasitas burst (`-32022` / `request_exceeds_burst`). Mencoba lagi tanpa menyesuaikan parameter tidak akan berhasil.

Berikut adalah respons yang dikembalikan saat API key dihilangkan:

```json
{
  "jsonrpc": "2.0",
  "id": null,
  "error": {
    "code": -32024,
    "message": "missing API key: send it in the request path (/v1/{chain}/<api_key>) or in the x-api-key header",
    "data": {
      "reason": "missing_api_key",
      "docs_url": "https://docs.blockvectra.com/en/errors/#missing_api_key",
      "retryable": false
    }
  }
}
```

## Menggunakan endpoint Data API alih-alih pemindaian getLogs yang ekstensif

Ketika sebuah aplikasi melacak riwayat transaksi atau perpindahan token untuk alamat tertentu, memindai melalui `eth_getLogs` memerlukan pengiriman kueri terbagi berurutan yang dibatasi oleh `max_logs_block_range` dan mem-parsing log peristiwa Transfer mentah.

Data API BlockVectra menyediakan endpoint REST yang telah diindeks sebelumnya untuk `hyperevm_mainnet`, mendukung jendela hingga 100.000 blok dengan paginasi berbasis kursor:

1. **Transaksi alamat**: `GET /v1/data/hyperevm_mainnet/addresses/{address}/transactions`
   * Parameter: `from_block` (wajib), `to_block` (wajib), `direction` (opsional: `from`, `to`, `any`, default `any`), `clamp` (string boolean opsional, default `false`; saat disetel ke `true`, jendela yang melebihi 100.000 blok atau lebih tinggi dari `as_of_block` dipotong alih-alih mengembalikan 409), `limit` (opsional, maks 500), `cursor` (token paginasi).
2. **Transfer token alamat**: `GET /v1/data/hyperevm_mainnet/addresses/{address}/transfers`
   * Parameter: `standard` (wajib: `erc20` atau `erc721`; `erc1155` tidak dapat dikueri berdasarkan alamat dan mengembalikan `422 no_coverage`), `token` (filter kontrak token opsional), `from_block` (wajib), `to_block` (wajib), `direction` (opsional: `in`, `out`, `any`), `clamp` (opsional), `limit`, `cursor`.

### Struktur respons

Respons menggunakan struktur respons standar:

* `data`: Array rekaman. Transaksi mencakup `hash`, `block_number`, `block_timestamp`, `from`, `to`, `value`, `tx_index`, `gas_limit`, `gas_used`, dan `status`. Transfer mencakup `token`, `standard`, `from`, `to`, `block_number`, `block_timestamp`, `tx_hash`, `tx_index`, dan `log_index` (`amount` untuk ERC-20, `token_id` untuk ERC-721).
* `next_cursor`: Token paginasi buram (opaque) yang dikembalikan jika rekaman berikutnya ada (tidak ada pada halaman terakhir, bukan `null`).
* `meta`: Metadata yang berisi `chain`, `chain_slug`, `chain_external_id`, `as_of_block`, `safe_block`, `finalized_block`, `coverage` (`full` atau `partial`), dan `refreshed_at`.

### Contoh kode: kueri Data API

**cURL**

```bash
export BLOCKVECTRA_API_KEY="rgw_your_api_key"

# 1. Kueri riwayat transaksi alamat (clamp=true mencegah error 409)
curl -s "https://api.blockvectra.com/v1/data/hyperevm_mainnet/addresses/0x2222222222222222222222222222222222222222/transactions?from_block=0&to_block=50000&clamp=true" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"

# 2. Kueri transfer token ERC-20 alamat
curl -s "https://api.blockvectra.com/v1/data/hyperevm_mainnet/addresses/0x2222222222222222222222222222222222222222/transfers?standard=erc20&from_block=0&to_block=50000&clamp=true" \
  -H "x-api-key: $BLOCKVECTRA_API_KEY"
```


  **TypeScript**

```ts
const apiKey = process.env.BLOCKVECTRA_API_KEY!;
const targetAddress = "0x2222222222222222222222222222222222222222";

let cursor: string | undefined;

do {
  const url = new URL(
    `https://api.blockvectra.com/v1/data/hyperevm_mainnet/addresses/${targetAddress}/transfers`,
  );
  url.searchParams.set("standard", "erc20");
  url.searchParams.set("from_block", "0");
  url.searchParams.set("to_block", "50000");
  url.searchParams.set("clamp", "true");
  if (cursor) {
    url.searchParams.set("cursor", cursor);
  }

  const res = await fetch(url, {
    headers: { "x-api-key": apiKey },
  });

  if (!res.ok) {
    throw new Error(`Data API HTTP ${res.status}`);
  }

  const body = (await res.json()) as {
    data: unknown[];
    next_cursor?: string;
  };

  console.log(`Fetched ${body.data.length} transfers`);
  cursor = body.next_cursor; // Loop terminates when cursor is absent
} while (cursor);
```


## Pelacakan real-time: polling blok baru

Untuk transportasi HTTP, lacak blok dengan polling dan ambil log peristiwa dalam chunk berurutan dalam batas `max_logs_block_range`. Pilih WebSocket hanya jika `/v1/chains` melaporkan `ws=true` dan entri `subscriptions` yang diperlukan. Untuk pengiriman ke penerima HTTPS, gunakan [webhook push](https://docs.blockvectra.com/en/guides/webhook-push/).

Untuk mencoba kontrak `Hello` yang telah di-deploy, tetapkan `LOG_ADDRESS` ke alamatnya. Kirim `ping()` melalui RPC penyiaran, lalu lakukan backfill blok resi dengan skrip backfill di halaman ini. Lanjutkan dari chunk terakhir yang selesai untuk peristiwa baru.

```bash
cast send "$CONTRACT_ADDRESS" "ping()" --rpc-url "$DEPLOY_RPC_URL" \
  --private-key "$DEPLOYER_PRIVATE_KEY"
```

### Alur polling

1. Keluarkan panggilan ringan berkala ke `eth_blockNumber` untuk memeriksa head rantai terbaru.
2. Bandingkan nomor blok yang dikembalikan dengan `lastSeenBlock` yang diproses sebelumnya.
3. Jika `currentBlock > lastSeenBlock`, bagi `[lastSeenBlock + 1, currentBlock]` menjadi chunk paling banyak `max_logs_block_range`. Simpan `lastSeenBlock` hanya setelah berhasil memproses setiap chunk; saat gagal, coba lagi chunk yang belum selesai. Hapus duplikasi berdasarkan `(blockHash, transactionHash, logIndex)` dan putar ulang tumpang tindih setelah menyambung kembali untuk merekonsiliasi reorg.
4. `watchBlockNumber` atau `watchBlocks` dari viem secara bawaan mengimplementasikan polling HTTP di bawah transportasi HTTP, memungkinkan kustomisasi melalui parameter `pollingInterval` (seperti 1000 ms).

### Lakukan polling log peristiwa dalam chunk terbatas

Simpan sebagai `poll-logs.mjs` di samping `network.mjs` dan `viem-client.mjs`. Tetapkan `BLOCKVECTRA_API_KEY`, `LOG_ADDRESS` dan `FROM_BLOCK`, lalu jalankan `node poll-logs.mjs`. Contoh terbatas ini mengambil sampel head sebanyak 12 kali, berjarak lima detik, dan mengueri setiap rentang baru dalam chunk berurutan. Error akan menghentikan skrip sebelum memajukan chunk yang gagal.

```js
import { isAddress } from 'viem';
import { client } from './viem-client.mjs';
import { chainInfo, allows } from './network.mjs';

const address = process.env.LOG_ADDRESS;
const start = process.env.FROM_BLOCK;
if (!address || !isAddress(address)) throw new Error('Set LOG_ADDRESS');
if (!/^(0x[0-9a-f]+|[0-9]+)$/i.test(start ?? '')) throw new Error('Set FROM_BLOCK');
if (!allows('eth_getLogs')) throw new Error('eth_getLogs requires an available keyed endpoint');
if (!Number.isSafeInteger(chainInfo.max_logs_block_range) || chainInfo.max_logs_block_range <= 0) {
  throw new Error('Invalid max_logs_block_range');
}
const max = BigInt(chainInfo.max_logs_block_range);
let from = BigInt(start);
for (let poll = 0; poll < 12; poll++) {
  const head = await client.getBlockNumber();
  while (from <= head) {
    const to = from + max - 1n < head ? from + max - 1n : head;
    const logs = await client.getLogs({ address, fromBlock: from, toBlock: to });
    console.log(JSON.stringify({ from: from.toString(), to: to.toString(), logs },
      (_, value) => typeof value === 'bigint' ? value.toString() : value));
    from = to + 1n;
  }
  if (poll < 11) await new Promise(resolve => setTimeout(resolve, 5_000));
}
```

Setiap output mencatat chunk yang telah selesai. Untuk melanjutkan, tetapkan `FROM_BLOCK` ke nilai `to + 1`-nya; konsumen persisten harus menyimpan peristiwa dan kursor bersama-sama, mendeduplikasi, dan merekonsiliasi reorg seperti yang dijelaskan di atas. Untuk 429 atau kegagalan lain yang dapat dicoba ulang, terapkan panduan backoff terbatas pada chunk yang belum selesai yang sama.

## Panduan terkait

* Temukan URL RPC publik, metode yang didukung, dan batas saat ini di [halaman rantai HyperEVM](https://blockvectra.com/en/chains/hyperevm_mainnet/).
* Untuk aturan lengkap tentang rentang `eth_getLogs` dan algoritma pembagian chunk, lihat [batas rentang blok eth\_getLogs dan kueri terbagi](https://docs.blockvectra.com/en/guides/getlogs-block-range/).
* Untuk membandingkan `eth_getLogs` terhadap transfer Data API, memahami batas `as_of_block`, dan penanda `safe_block` / `finalized_block`, lihat [eth\_getLogs dan transfer terindeks: cakupan dan finalitas](https://docs.blockvectra.com/en/guides/logs-vs-transfers/).
* Untuk detail tentang pengukuran CU, error yang tidak ditagih, dan percobaan ulang, lihat [Apa yang tidak ditagih: kode error dan aturan penagihan](https://docs.blockvectra.com/en/guides/billing-rules/).

## 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.
