# Обмеження швидкості RPC та бекфіл журналів у HyperEVM

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

## Пряма відповідь

Стандартний офіційний публічний RPC HyperEVM дозволяє 50 блоків на один запит `eth_getLogs` (джерело: офіційна [документація JSON-RPC](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/json-rpc) Hyperliquid). У BlockVectra автентифіковані запити `eth_getLogs` охоплюють до 1,000 блоків на запит (`hyperevm_mainnet.max_logs_block_range` з [GET /v1/chains](https://api.blockvectra.com/v1/chains)), враховуючи обидві межі. Більший діапазон повертає HTTP 200, JSON-RPC `-32602` та `logs_range_too_large` із `retryable: false` (див. [каталог помилок](https://docs.blockvectra.com/en/errors/#logs_range_too_large)); розділіть на `[from, min(from + max − 1, end)]`, збережіть свій курсор і після успішного виконання переходьте до кінця плюс один для відновлення роботи. Ліміт частоти запитів на одну IP-адресу офіційного публічного RPC та ліміти ключів BlockVectra описані окремо в розділі [Офіційні ліміти швидкості публічного RPC та помилка 429](#official-public-rpc-rate-limits-and-429) і в параметрах сервісу нижче.

* **Перший крок:** [прочитайте останній блок без API key](#1-read-the-latest-block-without-an-api-key), скориставшись наведеною нижче командою curl.
* **Готово, коли:** скрипт бекфілу виводить `fromBlock`, `toBlock` та масив `result` для кожної частини в обраному вами вікні; порожній масив означає відсутність відповідних журналів у цій частині.

[Параметри мережі та варіанти доступу](https://blockvectra.com/en/chains/hyperevm_mainnet/).

## Завдання, які допомагає вирішити цей посібник

* [Перевірте HyperEVM RPC](#connect-with-viem-or-ethers) за допомогою публічного читання через viem або ethers перед вибором методів з автентифікацією.
* [Виконайте бекфіл обмеженого вікна журналів](#three-step-task-backfill-a-bounded-hyperevm-log-window) у межах ліміту `eth_getLogs` для HyperEVM із прийняттям рішень щодо повторних спроб на основі повернутої помилки.
* [Прочитайте активність адреси](#using-data-api-endpoints-instead-of-extensive-getlogs-scanning) через індексовані транзакції та перекази за допомогою ключа, перевіряючи метадані повернутого покриття та актуальності.

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

## Трикрокове завдання: бекфіл обмеженого вікна журналів HyperEVM

Прочитайте останній блок без ключа, створіть ключ, а потім отримайте журнали подій для контракту за скінченне вікно блоків.

Виберіть контракт і потрібне вікно блоків. Це завдання охоплює це обмежене вікно; воно не гарантує повної історії контракту.

### 1. Читання останнього блоку без 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 — це номер останнього блоку в шістнадцятковому форматі. Це адреса `public.url` для HyperEVM, опублікована в [GET /v1/chains](https://api.blockvectra.com/v1/chains). Перелік `public.methods` публічного ендпоінта не містить `eth_getLogs`; крок 3 вимагає наявності ключа.

### 2. Створення API key

<div data-attribution-ref="docs-hyperevm-task">
  [Створіть ключ для цього бекфілу](https://console.blockvectra.com/login/?next=%2Fkeys%2F). Створіть ключ і збережіть секрет, показаний у діалоговому вікні, для використання з `hyperevm_mainnet`.

  Для AI-агента, який використовує HTTP без браузера, дотримуйтесь <a href="/en/guides/programmatic-signup/">Посібника з програмної реєстрації</a>. Передайте валідний `ref` URL-адреси посібника в JSON-тілі `POST /auth/siwe/login` замість значення `docs-signup` із прикладу; пропустіть його, якщо він недоступний. Не просіть користувача вставляти ключ у чат.
</div>

### 3. Бекфіл журналів за допомогою вашого ключа

Повний стартовий шаблон: [blockvectra/hyperevm-backfill](https://github.com/blockvectra/hyperevm-backfill)

Збережіть наступний скрипт як `hyperevm-task.ts`. Він працює в Node.js 24 або новішої версії без додаткових пакетів. Встановіть `BLOCKVECTRA_API_KEY` у ваш збережений ключ, а `LOG_ADDRESS` — в адресу контракту-емітента, яку ви хочете перевірити; зберігайте ключ на вашому сервері або в локальному терміналі.

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

За замовчуванням скрипт отримує останні `max_logs_block_range` блоків або менше поблизу генезису. Він зчитує цей ліміт із `/v1/chains` під час виконання. Щоб вибрати інше скінченне вікно, встановіть `FROM_BLOCK` та `TO_BLOCK` у десяткових або шістнадцяткових числах із префіксом `0x` перед запуском. Більші вікна діляться на послідовні частини, кожна з яких не перевищує опублікований ліміт.

```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 }));
}
```

Запити виконуються послідовно. Помилка JSON-RPC повторюється лише тоді, коли `error.data.retryable` має значення `true`, щонайбільше чотири спроби на запит, з експоненціальною затримкою (exponential backoff) та випадковим відхиленням (jitter), а також підтримкою секунд або дати HTTP у заголовку `Retry-After`. Очікування довше ніж 30 секунд зупиняє скрипт, щоб ви могли перезапустити його пізніше. Збої мережі, таймаути, некоректні відповіді та неповторювані помилки зупиняють роботу негайно; скрипт завершується аварійно, а не повідомляє про повний бекфіл.

Кожен рядок стандартного виводу містить `fromBlock`, `toBlock` та масив `result` однієї частини. `result: []` означає відсутність відповідних журналів у цій частині. Читайте такі поля в кожному журналі:

| Поле                                              | Значення                                                                                                           |
| ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `address`                                         | Контракт, який згенерував подію.                                                                                   |
| `blockNumber`, `blockHash`                        | Блок, що містить журнал; номер є шістнадцятковим числом.                                                           |
| `transactionHash`, `transactionIndex`, `logIndex` | Позиція транзакції та журналу; індекси є шістнадцятковими числами.                                                 |
| `topics`, `data`                                  | Індексовані аргументи події та неіндексовані аргументи, закодовані за ABI; декодуються за допомогою ABI контракту. |
| `removed`                                         | Чи був журнал видалений у результаті реорганізації ланцюга.                                                        |

Останній блок не є маркером фінальності. Якщо вам потрібне стабільне історичне вікно, виберіть підтверджений `TO_BLOCK` вашого застосунку та обробляйте реорганізації ланцюга.

Для вікна з `B = TO_BLOCK − FROM_BLOCK + 1` блоків та опублікованого ліміту `L` кількість частин становить `N = ceil(B / L)`. Дізнайтеся `method_weights[].cu_weight` для `eth_getLogs` та `eth_blockNumber` з [GET /v1/plans](https://console-api.blockvectra.com/v1/plans). Скрипт виводить оцінку в стандартний потік помилок: `N × weight(eth_getLogs) + weight(eth_blockNumber)`, включаючи запит голови ланцюга з ключем. Це не включає додаткові виклики та платні повторні спроби; див. [правила тарифікації](https://docs.blockvectra.com/en/guides/billing-rules/) щодо розрахунків. Кількість CU залежить від викликів, а не від кількості повернутих журналів.

**Доставка подій:** використовуйте опитування через HTTP частинами нижче або надсилайте події відстежуваних адрес на отримувач HTTPS за допомогою [webhook push](https://docs.blockvectra.com/en/guides/webhook-push/). **GET /v1/push/chains містить список підтримуваних мереж** та налаштувань підтвердження; автентифікація здійснюється через `x-api-key`. Підписи вебхуків, дедуплікація та повторна відправка описані в цьому посібнику. Webhook push існує окремо від підписок WebSocket (`ws` та `subscriptions` у `/v1/chains`).

## Підключення за допомогою viem або ethers

| Параметр / Ендпоінт | Значення / Шаблон | Автентифікація |
|---|---|---|
| Chain ID (EIP-155) | `999` | — |
| JSON-RPC (ключ у шляху) | `POST https://api.blockvectra.com/v1/hyperevm_mainnet/{api_key}` | API key у шляху URL |
| JSON-RPC (ключ у заголовку) | `POST https://api.blockvectra.com/v1/hyperevm_mainnet` | Заголовок x-api-key: {api_key} |
| Базовий URL Data API | `GET https://api.blockvectra.com/v1/data/hyperevm_mainnet/…` | Заголовок x-api-key: {api_key} |
| Публічний статус | `GET https://api.blockvectra.com/v1/status` | Без автентифікації (публічний) |

Розробники та AI-агенти можуть використовувати однакові налаштування на стороні сервера. Використовуйте Node.js 24 або новішої версії, viem 2 або ethers 6 і починайте з публічного читання. Надійно встановіть `BLOCKVECTRA_API_KEY` у середовищі для методів з автентифікацією. Не допускайте потрапляння ключів та URL-адрес RPC з ключами у код браузера, логи та системи контролю версій.

Збережіть це як `network.mjs`. Він зчитує `chain_id` та політику методів із [GET /v1/chains](https://api.blockvectra.com/v1/chains). Для читання без ключа використовуйте `public.url` каталогу та лише методи, зазначені в `public.methods`; доступність публічного HTTP не означає доступу до 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');
```

Збережіть як `viem-client.mjs`, встановіть за допомогою `npm install viem@2`, потім запустіть `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());
```

Для ethers збережіть як `ethers-client.mjs`, встановіть за допомогою `npm install ethers@6`, потім запустіть `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();
```

## Деплой за допомогою Foundry або Hardhat

Поточний каталог `hyperevm_mainnet` має `ws=false` і не містить `eth_sendRawTransaction` у `methods.allow`. Використовуйте BlockVectra для читання; деплой вимагає RPC із підтримкою трансляції (broadcasting). Встановіть `DEPLOY_RPC_URL` у значення автентифікованого HTTP URL цього провайдера. Не вважайте, що він має такі самі ліміти методів або діапазонів журналів, як у BlockVectra. Перевірте вибраний chain ID перед підписанням.

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

Продовжте за спільним [посібником із деплою у Foundry або Hardhat](https://docs.blockvectra.com/en/guides/deploy-contract/). Поповніть баланс деплоєра токенами EVM HYPE і перегляньте вимоги до подвійних блоків нижче перед великим деплоєм.

## HYPE, малі блоки та великі деплої

[Офіційний посібник із мережі HyperEVM](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm) визначає HYPE як газ із 18 знаками після коми (доступ: 2026-10-07). Переконайтеся, що деплоєр має HYPE на HyperEVM; баланс тільки в HyperCore не є балансом газу EVM. Дотримуйтесь інструкцій за посиланням щодо переказу нативних токенів під час переміщення коштів.

[Посібник з архітектури подвійних блоків](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/dual-block-architecture) описує швидкі малі блоки та повільніші великі блоки для більших транзакцій (доступ: 2026-10-07). Спочатку оцініть газ для деплою. Для деплоїв, які перевищують бюджет малого блоку, деплоєр повинен бути наявним користувачем HyperCore і підписати дію Core `{"type":"evmUserModify","usingBigBlocks":true}`; встановлення більшого ліміту газу для транзакції саме по собі не вибирає великі блоки. Після цього відновіть `usingBigBlocks=false`, щоб повернутися до малих блоків.

У провайдера, який їх підтримує, використовуйте `eth_usingBigBlocks` для перевірки режиму адреси та `eth_bigBlockGasPrice` для базової комісії великого блоку. [Офіційний довідник JSON-RPC](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/json-rpc) документує ці методи (доступ: 2026-10-07). Перевірте методи обраного провайдера; для BlockVectra використовуйте `/v1/chains`. Наведений вище мінімальний деплой націлений на малий контракт і не змінює режим акаунта Core.

## Дані HyperCore та HyperEVM

EVM RPC обслуговує контракти, квитанції (receipts) та журнали. Торгові дані та дії HyperCore використовують Core API. Контракти можуть зчитувати стан Core через прекомпільовані контракти (precompiles) та надсилати дії через CoreWriter; використовуйте [офіційний посібник із взаємодії](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/interacting-with-hypercore) під час інтеграції цих шляхів (доступ: 2026-10-07). Журнали EVM не замінюють запити книги ордерів або позицій у Core.

Системні транзакції HyperEVM (такі як перекази з HyperCore до HyperEVM) не включаються до стандартних відповідей `eth_getBlockByNumber` і надаються окремо офіційним RPC через `eth_getSystemTxsByBlockNumber` та `eth_getSystemTxsByBlockHash` (див. [офіційну документацію JSON-RPC](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/json-rpc), доступ: 2026-10-07). Дані блоків, транзакцій та Data API для HyperEVM у BlockVectra наразі не містять системних транзакцій; використовуйте ці два офіційні методи RPC напряму, якщо вам потрібні дані системних транзакцій.

## Обробка офіційної помилки 10055

[Офіційний посібник HyperEVM](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm) визначає `10055` як помилку на межі Core/EVM, що включає збої через nonce, недостатність коштів, дублікати хешів та занижену ціну заміни (underpriced-replacement) (доступ: 2026-10-07). Перевірте повідомлення від трансляційного RPC перед тим, як вирішити, як відновлювати роботу:

* **Nonce:** порівняйте `eth_getTransactionCount` із вашими очікуваними транзакціями; серіалізуйте надсилання від одного деплоєра та узгоджуйте його наступний nonce.
* **Кошти:** перевірте баланс EVM HYPE деплоєра порівняно зі значенням передачі плюс витрати на газ.
* **Дублікат хешу:** знайдіть наявну транзакцію та квитанцію перед надсиланням іншої транзакції.
* **Комісія за заміну:** перевірте наявний nonce та комісію, а потім скористайтеся політикою заміни транслятора; повторення тих самих байтів не збільшує комісію.

Сама лише помилка `10055` не виправдовує сліпих повторних спроб. Ознайомтеся з помилками та рекомендаціями щодо їх усунення окремо в [довіднику помилок BlockVectra](https://docs.blockvectra.com/en/errors/).

## Офіційні ліміти швидкості публічного RPC та помилка 429

Офіційна [документація щодо лімітів швидкості](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/rate-limits-and-user-limits) Hyperliquid визначає щонайбільше 100 запитів EVM JSON-RPC на хвилину на одну IP-адресу для `rpc.hyperliquid.xyz/evm`. Її [документація JSON-RPC](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/hyperevm/json-rpc) також обмежує `eth_getLogs` до 50 блоків на запит і не більше ніж 4 топіки. Доступ: 2026-10-07.

При отриманні HTTP 429 призупиніть запити та насамперед дотримуйтесь заголовка `Retry-After` (секунди або дата HTTP). Якщо він відсутній, використовуйте експоненціальну затримку з jitter та обмежену кількість повторних спроб, повторюючи ту саму незавершену частину. Зменшіть паралелізм і частоту опитування, а також розділіть запити журналів на частини в межах ліміту ендпоінта. Саме лише розбиття на частини не скасовує обмеження швидкості; клієнти, що використовують спільну IP-адресу, повинні координувати частоту своїх запитів.

Для ендпоінта BlockVectra з ключем дізнавайтеся значення `max_logs_block_range`, `methods.allow` та `methods.deny` для `hyperevm_mainnet` з [GET /v1/chains](https://api.blockvectra.com/v1/chains), замість того щоб застосовувати діапазон блоків або ліміт запитів на хвилину офіційного публічного RPC. Частота запитів окремо підпорядковується параметрам ключа `cu_per_sec`, `burst_cu` та ліміту викликів безкоштовного плану (див. наступний розділ). При 429 перевіряйте `error.data.reason` та `retryable`; помилка `request_exceeds_burst` вимагає надсилання менших запитів, а не повторних спроб без змін із затримкою.

## Параметри та правила сервісу BlockVectra

BlockVectra обслуговує мейннет HyperEVM через ендпоінти JSON-RPC та REST Data API:

1. **Параметри мережі та ліміти журналів**:
   З `GET /v1/chains` для `hyperevm_mainnet`:
   * **Ідентифікатор мережі (Slug)**: `hyperevm_mainnet`, Chain ID `999`.
   * **`max_logs_block_range`**: визначається полем `max_logs_block_range` з `GET /v1/chains`. Один запит `eth_getLogs` може охоплювати щонайбільше таку кількість блоків (`toBlock − fromBlock + 1`). Перевищення цього діапазону повертає HTTP 200 із кодом помилки JSON-RPC `-32602` (`eth_getLogs block range too large: max <N> blocks`), що не тарифікується.
   * **`state_window_blocks`**: визначається полем `state_window_blocks` з `GET /v1/chains`. Виклики зчитування стану (такі як `eth_call` та `eth_getBalance`) підпорядковуються вікну збереження, оголошеному цим полем (якщо значення `null`, зберігається повний стан без обмеження ковзного вікна).
   * **Політика методів**: визначається `methods.allow` та `methods.deny`. Стандартні методи EVM (`eth_blockNumber`, `eth_getLogs`, `eth_call`, `eth_getBalance`, `eth_getBlockByNumber`, `eth_getTransactionReceipt` тощо) дозволені; методи фільтрів і підписок (`eth_subscribe`, `eth_unsubscribe`, `eth_newFilter`, `eth_newBlockFilter`) заборонені й повертають `-32601` (не тарифікується).
2. **Ліміти швидкості безкоштовного тарифу та оновлення**:
   З `GET /v1/plans`:
   * **`free.max_calls_per_sec`**: до 25 викликів на секунду, спільно для всіх ключів облікового запису, усіх мереж і Data API.
   * **Стандартні ліміти ключів**: кожен API key має токен-кошик CU (швидкість поповнення `cu_per_sec`, місткість `burst_cu` — за замовчуванням 400 CU/s і burst 1,600 CU). Методи тарифікуються за вагою обчислювальних одиниць (CU).
   * **Оновлення лімітів**: після поповнення балансу ліміт викликів на секунду на рівні акаунта знімається; кожен ключ залишається підпорядкованим лімітам швидкості CU та пікової місткості. Поточні тарифи та розрахункові одиниці див. на [сторінці цін](https://blockvectra.com/en/pricing/).

## Бекфіл історичних журналів: запити eth\_getLogs частинами та логіка повторних спроб

Під час запиту історичних журналів широкі інтервали необхідно розділяти на суміжні частини, обмежені значенням `max_logs_block_range` цільової мережі. Клієнтські стратегії повторних спроб повинні перевіряти поле `retryable` у відповідях із помилками.

### Оцінка retryable у відповідях із помилками

У BlockVectra об'єкти помилок JSON-RPC містять корисне навантаження `error.data`, що включає `reason`, `docs_url` та `retryable` (булеве значення):

* **`retryable: true`**: тимчасові стани, зокрема перевантаження сервісу (`overloaded`), ліміт викликів на секунду безкоштовного плану (`free_plan_call_limit`), синхронізація вузла (`node_syncing`) або недоступність апстріму (`upstream_unavailable`). Клієнти повинні дотримуватися заголовка `Retry-After`, якщо він присутній, або застосовувати експоненціальну затримку з jitter.
* **`retryable: false`**: непостійні помилки, такі як перевищення ліміту діапазону блоків (`-32602` / `logs_range_too_large`), недійсні параметри (`invalid_params`), відсутній API key (`missing_api_key`) або запит, що перевищує пікову пропускну здатність (`-32022` / `request_exceeds_burst`). Повторна спроба без коригування параметрів не матиме успіху.

Нижче наведено відповідь, що повертається у разі відсутності API key:

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

## Використання ендпоінтів Data API замість масштабного сканування getLogs

Коли застосунок відстежує історію транзакцій або рух токенів для конкретної адреси, сканування через `eth_getLogs` вимагає надсилання послідовних запитів частинами, обмежених `max_logs_block_range`, та парсингу необроблених журналів подій Transfer.

Data API BlockVectra надає попередньо проіндексовані ендпоінти REST для `hyperevm_mainnet`, які підтримують вікна до 100,000 блоків із пагінацією за курсором:

1. **Транзакції адреси**: `GET /v1/data/hyperevm_mainnet/addresses/{address}/transactions`
   * Параметри: `from_block` (обов'язковий), `to_block` (обов'язковий), `direction` (необов'язковий: `from`, `to`, `any`, типово `any`), `clamp` (необов'язковий булевий рядок, типово `false`; якщо встановлено `true`, вікна, що перевищують 100,000 блоків або вищі за `as_of_block`, усікаються замість повернення 409), `limit` (необов'язковий, максимум 500), `cursor` (токен пагінації).
2. **Перекази токенів адреси**: `GET /v1/data/hyperevm_mainnet/addresses/{address}/transfers`
   * Параметри: `standard` (обов'язковий: `erc20` або `erc721`; `erc1155` не можна запитувати за адресою і повертає `422 no_coverage`), `token` (необов'язковий фільтр контракту токена), `from_block` (обов'язковий), `to_block` (обов'язковий), `direction` (необов'язковий: `in`, `out`, `any`), `clamp` (необов'язковий), `limit`, `cursor`.

### Структура відповіді

Відповіді використовують стандартні схеми-обгортки (envelope schemas):

* `data`: масив записів. Транзакції містять `hash`, `block_number`, `block_timestamp`, `from`, `to`, `value`, `tx_index`, `gas_limit`, `gas_used` та `status`. Перекази містять `token`, `standard`, `from`, `to`, `block_number`, `block_timestamp`, `tx_hash`, `tx_index` та `log_index` (`amount` для ERC-20, `token_id` для ERC-721).
* `next_cursor`: непрозорий токен пагінації, що повертається за наявності наступних записів (відсутній на останній сторінці, а не `null`).
* `meta`: метадані, що містять `chain`, `chain_slug`, `chain_external_id`, `as_of_block`, `safe_block`, `finalized_block`, `coverage` (`full` або `partial`) та `refreshed_at`.

### Приклад коду: запити Data API

**cURL**

```bash
export BLOCKVECTRA_API_KEY="rgw_your_api_key"

# 1. Query address transaction history (clamp=true prevents 409 errors)
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. Query address ERC-20 token transfers
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);
```


## Відстеження в реальному часі: опитування нових блоків

Для транспорту HTTP відстежуйте блоки за допомогою опитування та отримуйте журнали подій послідовними частинами в межах `max_logs_block_range`. Вибирайте WebSocket лише тоді, коли `/v1/chains` повідомляє `ws=true` та містить необхідний запис у `subscriptions`. Для доставки на отримувач HTTPS використовуйте [webhook push](https://docs.blockvectra.com/en/guides/webhook-push/).

Щоб протестувати розгорнутий контракт `Hello`, встановіть `LOG_ADDRESS` у його адресу. Надішліть `ping()` через трансляційний RPC, а потім виконайте бекфіл блоку квитанції за допомогою скрипта бекфілу на цій сторінці. Продовжуйте з останньої завершеної частини для нових подій.

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

### Процес опитування

1. Періодично виконуйте легкі виклики `eth_blockNumber`, щоб перевіряти останню голову ланцюга.
2. Порівнюйте отриманий номер блоку з раніше обробленим `lastSeenBlock`.
3. Якщо `currentBlock > lastSeenBlock`, розділіть `[lastSeenBlock + 1, currentBlock]` на частини розміром не більше ніж `max_logs_block_range`. Зберігайте `lastSeenBlock` лише після успішної обробки кожної частини; у разі помилки повторюйте спробу для незавершеної частини. Виконуйте дедуплікацію за `(blockHash, transactionHash, logIndex)` та повторно запитуйте перекриття після повторного підключення для узгодження можливих реорганізацій.
4. Функції `watchBlockNumber` або `watchBlocks` у viem нативно реалізують HTTP-опитування для транспорту HTTP, дозволяючи налаштування через параметр `pollingInterval` (наприклад, 1000 ms).

### Опитування журналів подій обмеженими частинами

Збережіть як `poll-logs.mjs` поруч із `network.mjs` та `viem-client.mjs`. Встановіть `BLOCKVECTRA_API_KEY`, `LOG_ADDRESS` та `FROM_BLOCK`, потім запустіть `node poll-logs.mjs`. Цей скінченний приклад опитує голову 12 разів з інтервалом у п'ять секунд і запитує кожен новий діапазон послідовними частинами. Помилка зупиняє скрипт перед переходом до наступної частини.

```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));
}
```

Кожен вивід фіксує завершену частину. Щоб відновити роботу, встановіть `FROM_BLOCK` у значення `to + 1`; надійні обробники повинні зберігати події та курсор разом, виконувати дедуплікацію та узгоджувати реорганізації ланцюга, як описано вище. Для помилок 429 або інших повторюваних збоїв застосовуйте рекомендації щодо обмеженої затримки для тієї самої незавершеної частини.

## Пов'язані посібники

* Знайдіть публічну URL-адресу RPC, підтримувані методи та поточні ліміти на [сторінці мережі HyperEVM](https://blockvectra.com/en/chains/hyperevm_mainnet/).
* Повні правила щодо діапазонів `eth_getLogs` та алгоритмів розбиття на частини див. у розділі [Ліміти діапазону блоків eth\_getLogs та запити частинами](https://docs.blockvectra.com/en/guides/getlogs-block-range/).
* Для порівняння `eth_getLogs` із переказами Data API, розуміння меж `as_of_block` та маркерів `safe_block` / `finalized_block` див. [eth\_getLogs та індексовані перекази: покриття та фінальність](https://docs.blockvectra.com/en/guides/logs-vs-transfers/).
* Детальну інформацію про облік CU, нетарифіковані помилки та повторні спроби див. у розділі [Що не тарифікується: коди помилок та правила тарифікації](https://docs.blockvectra.com/en/guides/billing-rules/).

## Наступні кроки

* [Перегляньте каталог датасетів](https://blockvectra.com/en/data/), щоб побачити всі набори даних, які індексує BlockVectra.
* [Ознайомтеся з безкоштовним планом і тарифами](https://blockvectra.com/en/pricing/#free), щоб дізнатися, що включено у ваш акаунт.
* [Увійдіть до консолі](https://console.blockvectra.com/login/?next=%2Fkeys%2F), щоб створити API key.
